From 895c6be18228614529230b5fbfb5f7f92e373f01 Mon Sep 17 00:00:00 2001 From: jrgissing Date: Tue, 31 Dec 2019 19:32:28 -0500 Subject: [PATCH 001/689] bond/react: tiny epoxy example --- .../tiny_epoxy/in.tiny_epoxy.stabilized | 49 + .../log.20Nov19.tiny_epoxy.stabilized.g++.1 | 172 ++ .../log.20Nov19.tiny_epoxy.stabilized.g++.4 | 172 ++ .../misc/bond_react/tiny_epoxy/rxn1_stp1.map | 47 + .../tiny_epoxy/rxn1_stp1_post.data_template | 315 ++++ .../tiny_epoxy/rxn1_stp1_pre.data_template | 301 ++++ .../misc/bond_react/tiny_epoxy/rxn1_stp2.map | 47 + .../tiny_epoxy/rxn1_stp2_post.data_template | 307 ++++ .../misc/bond_react/tiny_epoxy/rxn2_stp1.map | 59 + .../tiny_epoxy/rxn2_stp1_post.data_template | 424 +++++ .../tiny_epoxy/rxn2_stp1_pre.data_template | 407 +++++ .../misc/bond_react/tiny_epoxy/rxn2_stp2.map | 59 + .../tiny_epoxy/rxn2_stp2_post.data_template | 413 +++++ .../bond_react/tiny_epoxy/tiny_epoxy.data | 1582 +++++++++++++++++ 14 files changed, 4354 insertions(+) create mode 100644 examples/USER/misc/bond_react/tiny_epoxy/in.tiny_epoxy.stabilized create mode 100644 examples/USER/misc/bond_react/tiny_epoxy/log.20Nov19.tiny_epoxy.stabilized.g++.1 create mode 100644 examples/USER/misc/bond_react/tiny_epoxy/log.20Nov19.tiny_epoxy.stabilized.g++.4 create mode 100644 examples/USER/misc/bond_react/tiny_epoxy/rxn1_stp1.map create mode 100644 examples/USER/misc/bond_react/tiny_epoxy/rxn1_stp1_post.data_template create mode 100644 examples/USER/misc/bond_react/tiny_epoxy/rxn1_stp1_pre.data_template create mode 100644 examples/USER/misc/bond_react/tiny_epoxy/rxn1_stp2.map create mode 100644 examples/USER/misc/bond_react/tiny_epoxy/rxn1_stp2_post.data_template create mode 100644 examples/USER/misc/bond_react/tiny_epoxy/rxn2_stp1.map create mode 100644 examples/USER/misc/bond_react/tiny_epoxy/rxn2_stp1_post.data_template create mode 100644 examples/USER/misc/bond_react/tiny_epoxy/rxn2_stp1_pre.data_template create mode 100644 examples/USER/misc/bond_react/tiny_epoxy/rxn2_stp2.map create mode 100644 examples/USER/misc/bond_react/tiny_epoxy/rxn2_stp2_post.data_template create mode 100644 examples/USER/misc/bond_react/tiny_epoxy/tiny_epoxy.data diff --git a/examples/USER/misc/bond_react/tiny_epoxy/in.tiny_epoxy.stabilized b/examples/USER/misc/bond_react/tiny_epoxy/in.tiny_epoxy.stabilized new file mode 100644 index 0000000000..0e6e97cd46 --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_epoxy/in.tiny_epoxy.stabilized @@ -0,0 +1,49 @@ +# two molecules DGEBA (diepoxy) and one DETA (linker) +# two crosslinking reactions + +units real + +boundary p p p + +atom_style full + +pair_style lj/class2 8 + +angle_style class2 + +bond_style class2 + +dihedral_style class2 + +improper_style class2 + +read_data tiny_epoxy.data + +velocity all create 300.0 4928459 dist gaussian + +molecule mol1 rxn1_stp1_pre.data_template +molecule mol2 rxn1_stp1_post.data_template +molecule mol3 rxn1_stp2_post.data_template +molecule mol4 rxn2_stp1_pre.data_template +molecule mol5 rxn2_stp1_post.data_template +molecule mol6 rxn2_stp2_post.data_template + +thermo 50 + +# dump 1 all xyz 1 test_vis.xyz + +fix rxns all bond/react stabilization yes statted_grp .03 & + react rxn1_stp1 all 1 0.0 5 mol1 mol2 rxn1_stp1.map & + react rxn1_stp2 all 1 0.0 5 mol2 mol3 rxn1_stp2.map & + react rxn2_stp1 all 1 0.0 5 mol4 mol5 rxn2_stp1.map & + react rxn2_stp2 all 1 0.0 5 mol5 mol6 rxn2_stp2.map + + +fix 1 statted_grp_REACT nvt temp 300 300 100 + +thermo_style custom step temp f_rxns[1] f_rxns[2] f_rxns[3] f_rxns[4] + +run 2000 + +# write_restart restart_longrun +# write_data restart_longrun.data nofix diff --git a/examples/USER/misc/bond_react/tiny_epoxy/log.20Nov19.tiny_epoxy.stabilized.g++.1 b/examples/USER/misc/bond_react/tiny_epoxy/log.20Nov19.tiny_epoxy.stabilized.g++.1 new file mode 100644 index 0000000000..6ca0361513 --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_epoxy/log.20Nov19.tiny_epoxy.stabilized.g++.1 @@ -0,0 +1,172 @@ +LAMMPS (20 Nov 2019) + +WARNING-WARNING-WARNING-WARNING-WARNING +This LAMMPS executable was compiled using C++98 compatibility. +Please report the compiler info below at https://github.com/lammps/lammps/issues/1659 +GNU C++ 4.8.5 +WARNING-WARNING-WARNING-WARNING-WARNING + +Reading data file ... + orthogonal box = (10 -10 -15) to (30 20 10) + 1 by 1 by 1 MPI processor grid + reading atoms ... + 118 atoms + scanning bonds ... + 4 = max bonds/atom + scanning angles ... + 6 = max angles/atom + scanning dihedrals ... + 18 = max dihedrals/atom + scanning impropers ... + 4 = max impropers/atom + reading bonds ... + 123 bonds + reading angles ... + 221 angles + reading dihedrals ... + 302 dihedrals + reading impropers ... + 115 impropers +Finding 1-2 1-3 1-4 neighbors ... + special bond factors lj: 0 0 0 + special bond factors coul: 0 0 0 + 4 = max # of 1-2 neighbors + 10 = max # of 1-3 neighbors + 19 = max # of 1-4 neighbors + 22 = max # of special neighbors + special bonds CPU = 0.000286808 secs + read_data CPU = 0.00724107 secs +Read molecule mol1: + 31 atoms with max type 10 + 30 bonds with max type 15 + 53 angles with max type 29 + 66 dihedrals with max type 39 + 31 impropers with max type 5 +Read molecule mol2: + 31 atoms with max type 10 + 30 bonds with max type 17 + 55 angles with max type 36 + 75 dihedrals with max type 51 + 34 impropers with max type 5 +Read molecule mol3: + 31 atoms with max type 11 + 30 bonds with max type 18 + 53 angles with max type 37 + 72 dihedrals with max type 53 + 31 impropers with max type 5 +Read molecule mol4: + 42 atoms with max type 11 + 41 bonds with max type 18 + 73 angles with max type 41 + 96 dihedrals with max type 54 + 43 impropers with max type 5 +Read molecule mol5: + 42 atoms with max type 11 + 41 bonds with max type 18 + 75 angles with max type 37 + 108 dihedrals with max type 53 + 46 impropers with max type 5 +Read molecule mol6: + 42 atoms with max type 11 + 41 bonds with max type 19 + 73 angles with max type 50 + 102 dihedrals with max type 66 + 43 impropers with max type 22 +dynamic group bond_react_MASTER_group defined +dynamic group statted_grp_REACT defined +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 10 + ghost atom cutoff = 10 + binsize = 5, bins = 4 6 5 + 2 neighbor lists, perpetual/occasional/extra = 1 1 0 + (1) pair lj/class2, perpetual + attributes: half, newton on + pair build: half/bin/newton + stencil: half/bin/3d/newton + bin: standard + (2) fix bond/react, occasional, copy from (1) + attributes: half, newton on + pair build: copy + stencil: none + bin: none +Setting up Verlet run ... + Unit style : real + Current step : 0 + Time step : 1 +Per MPI rank memory allocation (min/avg/max) = 17.28 | 17.28 | 17.28 Mbytes +Step Temp f_rxns[1] f_rxns[2] f_rxns[3] f_rxns[4] + 0 300 0 0 0 0 + 50 391.52956 1 0 0 0 + 100 475.26826 1 1 0 0 + 150 605.26215 1 1 1 0 + 200 545.7485 1 1 1 0 + 250 461.64929 1 1 1 1 + 300 452.10611 1 1 1 1 + 350 379.61671 1 1 1 1 + 400 331.22444 1 1 1 1 + 450 275.63969 1 1 1 1 + 500 316.63407 1 1 1 1 + 550 261.39841 1 1 1 1 + 600 313.70928 1 1 1 1 + 650 294.24011 1 1 1 1 + 700 285.81736 1 1 1 1 + 750 340.37496 1 1 1 1 + 800 333.2496 1 1 1 1 + 850 307.40826 1 1 1 1 + 900 304.68718 1 1 1 1 + 950 328.0289 1 1 1 1 + 1000 290.22808 1 1 1 1 + 1050 272.78518 1 1 1 1 + 1100 291.30546 1 1 1 1 + 1150 320.33992 1 1 1 1 + 1200 330.57057 1 1 1 1 + 1250 300.51008 1 1 1 1 + 1300 293.6209 1 1 1 1 + 1350 324.36604 1 1 1 1 + 1400 331.15408 1 1 1 1 + 1450 302.23396 1 1 1 1 + 1500 297.55562 1 1 1 1 + 1550 277.3187 1 1 1 1 + 1600 289.66052 1 1 1 1 + 1650 281.85404 1 1 1 1 + 1700 293.4999 1 1 1 1 + 1750 306.21866 1 1 1 1 + 1800 283.22696 1 1 1 1 + 1850 295.10473 1 1 1 1 + 1900 317.3843 1 1 1 1 + 1950 305.14825 1 1 1 1 + 2000 289.00911 1 1 1 1 +Loop time of 1.87066 on 1 procs for 2000 steps with 118 atoms + +Performance: 92.374 ns/day, 0.260 hours/ns, 1069.141 timesteps/s +98.4% CPU use with 1 MPI tasks x no OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.12832 | 0.12832 | 0.12832 | 0.0 | 6.86 +Bond | 0.77458 | 0.77458 | 0.77458 | 0.0 | 41.41 +Neigh | 0.45068 | 0.45068 | 0.45068 | 0.0 | 24.09 +Comm | 0.029785 | 0.029785 | 0.029785 | 0.0 | 1.59 +Output | 0.31635 | 0.31635 | 0.31635 | 0.0 | 16.91 +Modify | 0.16657 | 0.16657 | 0.16657 | 0.0 | 8.90 +Other | | 0.004368 | | | 0.23 + +Nlocal: 118 ave 118 max 118 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 332 ave 332 max 332 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 4338 ave 4338 max 4338 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 4338 +Ave neighs/atom = 36.7627 +Ave special neighs/atom = 10.5763 +Neighbor list builds = 2000 +Dangerous builds = 0 + +Please see the log.cite file for references relevant to this simulation + +Total wall time: 0:00:02 diff --git a/examples/USER/misc/bond_react/tiny_epoxy/log.20Nov19.tiny_epoxy.stabilized.g++.4 b/examples/USER/misc/bond_react/tiny_epoxy/log.20Nov19.tiny_epoxy.stabilized.g++.4 new file mode 100644 index 0000000000..4673ba3980 --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_epoxy/log.20Nov19.tiny_epoxy.stabilized.g++.4 @@ -0,0 +1,172 @@ +LAMMPS (20 Nov 2019) + +WARNING-WARNING-WARNING-WARNING-WARNING +This LAMMPS executable was compiled using C++98 compatibility. +Please report the compiler info below at https://github.com/lammps/lammps/issues/1659 +GNU C++ 4.8.5 +WARNING-WARNING-WARNING-WARNING-WARNING + +Reading data file ... + orthogonal box = (10 -10 -15) to (30 20 10) + 1 by 2 by 2 MPI processor grid + reading atoms ... + 118 atoms + scanning bonds ... + 4 = max bonds/atom + scanning angles ... + 6 = max angles/atom + scanning dihedrals ... + 18 = max dihedrals/atom + scanning impropers ... + 4 = max impropers/atom + reading bonds ... + 123 bonds + reading angles ... + 221 angles + reading dihedrals ... + 302 dihedrals + reading impropers ... + 115 impropers +Finding 1-2 1-3 1-4 neighbors ... + special bond factors lj: 0 0 0 + special bond factors coul: 0 0 0 + 4 = max # of 1-2 neighbors + 10 = max # of 1-3 neighbors + 19 = max # of 1-4 neighbors + 22 = max # of special neighbors + special bonds CPU = 0.000239905 secs + read_data CPU = 0.0080783 secs +Read molecule mol1: + 31 atoms with max type 10 + 30 bonds with max type 15 + 53 angles with max type 29 + 66 dihedrals with max type 39 + 31 impropers with max type 5 +Read molecule mol2: + 31 atoms with max type 10 + 30 bonds with max type 17 + 55 angles with max type 36 + 75 dihedrals with max type 51 + 34 impropers with max type 5 +Read molecule mol3: + 31 atoms with max type 11 + 30 bonds with max type 18 + 53 angles with max type 37 + 72 dihedrals with max type 53 + 31 impropers with max type 5 +Read molecule mol4: + 42 atoms with max type 11 + 41 bonds with max type 18 + 73 angles with max type 41 + 96 dihedrals with max type 54 + 43 impropers with max type 5 +Read molecule mol5: + 42 atoms with max type 11 + 41 bonds with max type 18 + 75 angles with max type 37 + 108 dihedrals with max type 53 + 46 impropers with max type 5 +Read molecule mol6: + 42 atoms with max type 11 + 41 bonds with max type 19 + 73 angles with max type 50 + 102 dihedrals with max type 66 + 43 impropers with max type 22 +dynamic group bond_react_MASTER_group defined +dynamic group statted_grp_REACT defined +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 10 + ghost atom cutoff = 10 + binsize = 5, bins = 4 6 5 + 2 neighbor lists, perpetual/occasional/extra = 1 1 0 + (1) pair lj/class2, perpetual + attributes: half, newton on + pair build: half/bin/newton + stencil: half/bin/3d/newton + bin: standard + (2) fix bond/react, occasional, copy from (1) + attributes: half, newton on + pair build: copy + stencil: none + bin: none +Setting up Verlet run ... + Unit style : real + Current step : 0 + Time step : 1 +Per MPI rank memory allocation (min/avg/max) = 16.26 | 16.45 | 16.63 Mbytes +Step Temp f_rxns[1] f_rxns[2] f_rxns[3] f_rxns[4] + 0 300 0 0 0 0 + 50 391.52956 1 0 0 0 + 100 475.26826 1 1 0 0 + 150 605.26215 1 1 1 0 + 200 545.7485 1 1 1 0 + 250 461.64929 1 1 1 1 + 300 452.10611 1 1 1 1 + 350 379.61671 1 1 1 1 + 400 331.22444 1 1 1 1 + 450 275.63969 1 1 1 1 + 500 316.63407 1 1 1 1 + 550 261.39841 1 1 1 1 + 600 313.70928 1 1 1 1 + 650 294.24011 1 1 1 1 + 700 285.81736 1 1 1 1 + 750 340.37496 1 1 1 1 + 800 333.2496 1 1 1 1 + 850 307.40826 1 1 1 1 + 900 304.68718 1 1 1 1 + 950 328.0289 1 1 1 1 + 1000 290.22808 1 1 1 1 + 1050 272.78518 1 1 1 1 + 1100 291.30546 1 1 1 1 + 1150 320.33992 1 1 1 1 + 1200 330.57057 1 1 1 1 + 1250 300.51008 1 1 1 1 + 1300 293.6209 1 1 1 1 + 1350 324.36604 1 1 1 1 + 1400 331.15408 1 1 1 1 + 1450 302.23396 1 1 1 1 + 1500 297.55562 1 1 1 1 + 1550 277.3187 1 1 1 1 + 1600 289.66052 1 1 1 1 + 1650 281.85404 1 1 1 1 + 1700 293.4999 1 1 1 1 + 1750 306.21866 1 1 1 1 + 1800 283.22695 1 1 1 1 + 1850 295.10472 1 1 1 1 + 1900 317.38431 1 1 1 1 + 1950 305.14824 1 1 1 1 + 2000 289.00909 1 1 1 1 +Loop time of 0.689125 on 4 procs for 2000 steps with 118 atoms + +Performance: 250.753 ns/day, 0.096 hours/ns, 2902.231 timesteps/s +100.0% CPU use with 4 MPI tasks x no OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.02002 | 0.030617 | 0.053133 | 7.7 | 4.44 +Bond | 0.10356 | 0.18908 | 0.22691 | 11.6 | 27.44 +Neigh | 0.16721 | 0.17002 | 0.17247 | 0.5 | 24.67 +Comm | 0.057286 | 0.12002 | 0.21612 | 17.0 | 17.42 +Output | 0.00028991 | 0.00034121 | 0.00049323 | 0.0 | 0.05 +Modify | 0.17626 | 0.17675 | 0.17721 | 0.1 | 25.65 +Other | | 0.002287 | | | 0.33 + +Nlocal: 29.5 ave 41 max 18 min +Histogram: 1 0 0 1 0 0 1 0 0 1 +Nghost: 306 ave 349 max 269 min +Histogram: 1 1 0 0 0 0 1 0 0 1 +Neighs: 1084.5 ave 2154 max 397 min +Histogram: 1 0 1 1 0 0 0 0 0 1 + +Total # of neighbors = 4338 +Ave neighs/atom = 36.7627 +Ave special neighs/atom = 10.5763 +Neighbor list builds = 2000 +Dangerous builds = 0 + +Please see the log.cite file for references relevant to this simulation + +Total wall time: 0:00:01 diff --git a/examples/USER/misc/bond_react/tiny_epoxy/rxn1_stp1.map b/examples/USER/misc/bond_react/tiny_epoxy/rxn1_stp1.map new file mode 100644 index 0000000000..fb8720be63 --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_epoxy/rxn1_stp1.map @@ -0,0 +1,47 @@ +this is a map file + +1 edgeIDs +31 equivalences + +BondingIDs + +15 +1 + +EdgeIDs + +5 + +Equivalences + +1 1 +2 2 +3 3 +4 4 +5 5 +6 6 +7 7 +8 8 +9 9 +10 10 +11 11 +12 12 +13 13 +14 14 +15 15 +16 16 +17 17 +18 18 +19 19 +20 20 +21 21 +22 22 +23 23 +24 24 +25 25 +26 26 +27 27 +28 28 +29 29 +30 30 +31 31 diff --git a/examples/USER/misc/bond_react/tiny_epoxy/rxn1_stp1_post.data_template b/examples/USER/misc/bond_react/tiny_epoxy/rxn1_stp1_post.data_template new file mode 100644 index 0000000000..e510883432 --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_epoxy/rxn1_stp1_post.data_template @@ -0,0 +1,315 @@ +rxn1_stp1_post + +31 atoms +30 bonds +55 angles +75 dihedrals +34 impropers + +Types + +1 1 +2 6 +3 1 +4 7 +5 4 +6 7 +7 8 +8 8 +9 8 +10 8 +11 8 +12 9 +13 1 +14 1 +15 9 +16 9 +17 1 +18 1 +19 10 +20 8 +21 8 +22 8 +23 8 +24 10 +25 10 +26 10 +27 10 +28 8 +29 8 +30 8 +31 8 + +Charges + +1 0.000000 +2 0.000000 +3 0.000000 +4 0.100000 +5 0.000000 +6 0.000000 +7 0.000000 +8 0.000000 +9 0.000000 +10 0.000000 +11 0.000000 +12 0.000000 +13 0.000000 +14 0.000000 +15 -0.025000 +16 -0.025000 +17 0.000000 +18 0.000000 +19 0.000000 +20 0.000000 +21 0.000000 +22 0.000000 +23 0.000000 +24 0.000000 +25 0.000000 +26 0.000000 +27 0.000000 +28 0.000000 +29 0.000000 +30 0.000000 +31 0.000000 + +Coords + +1 22.582573 10.988183 -5.014054 +2 23.904713 10.750493 -4.202215 +3 23.989172 9.487042 -3.323374 +4 24.067001 11.723383 -4.037435 +5 24.627851 7.325302 -3.319944 +6 24.554632 8.418972 -4.080365 +7 22.667763 11.445703 -5.999605 +8 21.787441 10.247643 -4.916974 +9 24.964962 10.712683 -4.449374 +10 24.616703 9.689913 -2.456034 +11 22.989313 9.208153 -2.991455 +12 18.808882 13.758042 -3.958724 +13 19.293213 12.549683 -3.196594 +14 20.810543 12.417832 -3.417504 +15 21.090193 12.251203 -4.891234 +16 17.657042 16.437199 -3.985224 +17 19.126713 16.210239 -4.245154 +18 19.589151 14.957593 -3.479565 +19 19.000433 13.609432 -5.041715 +20 18.761223 11.614392 -3.573184 +21 19.082903 12.688992 -2.085145 +22 21.202852 11.511562 -2.848624 +23 21.328482 13.360252 -3.038924 +24 19.949852 12.199403 -5.680355 +25 21.477343 13.247442 -5.445915 +26 17.080341 15.555528 -4.334374 +27 17.319832 17.341927 -4.532204 +28 19.720472 17.115158 -3.887564 +29 19.298622 16.058659 -5.361685 +30 19.410772 15.105113 -2.363724 +31 20.700163 14.782252 -3.666344 + +Bonds + +1 1 1 8 +2 16 1 2 +3 1 1 7 +4 13 1 15 +5 16 3 2 +6 12 2 9 +7 17 2 4 +8 3 3 6 +9 1 3 10 +10 1 3 11 +11 8 6 5 +12 13 13 12 +13 13 18 12 +14 14 12 19 +15 15 13 14 +16 1 13 20 +17 1 13 21 +18 13 14 15 +19 1 14 22 +20 1 14 23 +21 14 15 24 +22 14 15 25 +23 13 17 16 +24 14 16 26 +25 14 16 27 +26 15 17 18 +27 1 17 28 +28 1 17 29 +29 1 18 30 +30 1 18 31 + +Angles + +1 30 2 1 8 +2 2 8 1 7 +3 26 8 1 15 +4 30 2 1 7 +5 31 2 1 15 +6 26 7 1 15 +7 32 1 2 3 +8 33 1 2 9 +9 34 1 2 4 +10 33 3 2 9 +11 34 3 2 4 +12 35 4 2 9 +13 36 2 3 6 +14 30 2 3 10 +15 30 2 3 11 +16 3 6 3 10 +17 3 6 3 11 +18 2 10 3 11 +19 22 3 6 5 +20 23 13 12 18 +21 24 13 12 19 +22 24 18 12 19 +23 25 14 13 12 +24 26 20 13 12 +25 26 21 13 12 +26 27 14 13 20 +27 27 14 13 21 +28 2 20 13 21 +29 25 13 14 15 +30 27 13 14 22 +31 27 13 14 23 +32 26 22 14 15 +33 26 23 14 15 +34 2 22 14 23 +35 23 1 15 14 +36 24 1 15 24 +37 24 1 15 25 +38 24 14 15 24 +39 24 14 15 25 +40 28 24 15 25 +41 24 17 16 26 +42 24 17 16 27 +43 28 26 16 27 +44 25 18 17 16 +45 26 28 17 16 +46 26 29 17 16 +47 27 18 17 28 +48 27 18 17 29 +49 2 28 17 29 +50 25 17 18 12 +51 26 30 18 12 +52 26 31 18 12 +53 27 17 18 30 +54 27 17 18 31 +55 2 30 18 31 + +Dihedrals + +1 40 8 1 2 3 +2 41 8 1 2 9 +3 42 8 1 2 4 +4 40 7 1 2 3 +5 41 7 1 2 9 +6 42 7 1 2 4 +7 43 15 1 2 3 +8 44 15 1 2 9 +9 45 15 1 2 4 +10 28 8 1 15 14 +11 30 8 1 15 24 +12 30 8 1 15 25 +13 46 2 1 15 14 +14 47 2 1 15 24 +15 47 2 1 15 25 +16 28 7 1 15 14 +17 30 7 1 15 24 +18 30 7 1 15 25 +19 48 6 3 2 1 +20 40 10 3 2 1 +21 40 11 3 2 1 +22 49 6 3 2 9 +23 41 10 3 2 9 +24 41 11 3 2 9 +25 50 6 3 2 4 +26 42 10 3 2 4 +27 42 11 3 2 4 +28 51 2 3 6 5 +29 7 10 3 6 5 +30 7 11 3 6 5 +31 27 14 13 12 18 +32 28 20 13 12 18 +33 28 21 13 12 18 +34 29 14 13 12 19 +35 30 20 13 12 19 +36 30 21 13 12 19 +37 27 17 18 12 13 +38 28 30 18 12 13 +39 28 31 18 12 13 +40 29 17 18 12 19 +41 30 30 18 12 19 +42 30 31 18 12 19 +43 31 12 13 14 15 +44 32 22 14 13 12 +45 32 23 14 13 12 +46 32 20 13 14 15 +47 33 20 13 14 22 +48 33 20 13 14 23 +49 32 21 13 14 15 +50 33 21 13 14 22 +51 33 21 13 14 23 +52 27 13 14 15 1 +53 29 13 14 15 24 +54 29 13 14 15 25 +55 28 22 14 15 1 +56 30 22 14 15 24 +57 30 22 14 15 25 +58 28 23 14 15 1 +59 30 23 14 15 24 +60 30 23 14 15 25 +61 29 18 17 16 26 +62 30 28 17 16 26 +63 30 29 17 16 26 +64 29 18 17 16 27 +65 30 28 17 16 27 +66 30 29 17 16 27 +67 31 16 17 18 12 +68 32 30 18 17 16 +69 32 31 18 17 16 +70 32 28 17 18 12 +71 33 28 17 18 30 +72 33 28 17 18 31 +73 32 29 17 18 12 +74 33 29 17 18 30 +75 33 29 17 18 31 + +Impropers + +1 4 13 12 18 19 +2 5 17 16 26 27 +3 1 2 1 8 7 +4 1 2 1 8 15 +5 1 8 1 7 15 +6 1 2 1 7 15 +7 1 1 2 3 9 +8 1 1 2 3 4 +9 1 1 2 4 9 +10 1 3 2 4 9 +11 1 2 3 6 10 +12 1 2 3 6 11 +13 1 2 3 10 11 +14 1 6 3 10 11 +15 1 14 13 20 12 +16 1 14 13 21 12 +17 1 20 13 21 12 +18 1 14 13 20 21 +19 1 13 14 22 15 +20 1 13 14 23 15 +21 1 13 14 22 23 +22 1 22 14 23 15 +23 1 1 15 14 24 +24 1 1 15 14 25 +25 1 1 15 24 25 +26 1 14 15 24 25 +27 1 18 17 28 16 +28 1 18 17 29 16 +29 1 28 17 29 16 +30 1 18 17 28 29 +31 1 17 18 30 12 +32 1 17 18 31 12 +33 1 30 18 31 12 +34 1 17 18 30 31 diff --git a/examples/USER/misc/bond_react/tiny_epoxy/rxn1_stp1_pre.data_template b/examples/USER/misc/bond_react/tiny_epoxy/rxn1_stp1_pre.data_template new file mode 100644 index 0000000000..dd767a4cba --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_epoxy/rxn1_stp1_pre.data_template @@ -0,0 +1,301 @@ +rxn1_stp1_pre + +31 atoms +30 bonds +53 angles +66 dihedrals +31 impropers + +Types + +1 2 +2 2 +3 1 +4 3 +5 4 +6 7 +7 8 +8 8 +9 8 +10 8 +11 8 +12 9 +13 1 +14 1 +15 9 +16 9 +17 1 +18 1 +19 10 +20 8 +21 8 +22 8 +23 8 +24 10 +25 10 +26 10 +27 10 +28 8 +29 8 +30 8 +31 8 + +Charges + +1 0.000000 +2 0.000000 +3 0.000000 +4 0.100000 +5 0.000000 +6 0.000000 +7 0.000000 +8 0.000000 +9 0.000000 +10 0.000000 +11 0.000000 +12 0.000000 +13 0.000000 +14 0.000000 +15 -0.025000 +16 -0.025000 +17 0.000000 +18 0.000000 +19 0.000000 +20 0.000000 +21 0.000000 +22 0.000000 +23 0.000000 +24 0.000000 +25 0.000000 +26 0.000000 +27 0.000000 +28 0.000000 +29 0.000000 +30 0.000000 +31 0.000000 + +Coords + +1 19.846882 9.569666 -1.229588 +2 21.168802 9.331466 -0.418038 +3 21.253012 8.067936 0.460722 +4 20.170443 10.460656 0.020692 +5 21.891691 5.906196 0.464152 +6 21.818472 6.999866 -0.296268 +7 19.932211 10.027435 -2.215008 +8 19.051722 8.829116 -1.132808 +9 22.229073 9.293536 -0.665088 +10 21.880442 8.270676 1.328162 +11 20.253073 7.789126 0.792482 +12 16.072590 12.338870 -0.174330 +13 16.557261 11.130320 0.587290 +14 18.074570 10.998810 0.366080 +15 18.353970 10.832370 -1.107720 +16 14.920720 15.017820 -0.200530 +17 16.390430 14.791100 -0.460440 +18 16.852980 13.538320 0.304870 +19 16.263750 12.190560 -1.257430 +20 16.025360 10.195070 0.210470 +21 16.347120 11.269210 1.698830 +22 18.467180 10.092570 0.934800 +23 18.592390 11.941300 0.744640 +24 17.843861 9.919930 -1.479780 +25 19.448191 10.736480 -1.267520 +26 14.344120 14.136250 -0.550130 +27 14.583470 15.922760 -0.747140 +28 16.984060 15.696010 -0.102600 +29 16.562420 14.639820 -1.577000 +30 16.674820 13.685670 1.420760 +31 17.963949 13.362980 0.117850 + +Bonds + +1 6 1 8 +2 4 1 4 +3 5 1 2 +4 6 1 7 +5 4 2 4 +6 2 2 3 +7 6 2 9 +8 3 3 6 +9 1 3 10 +10 1 3 11 +11 8 5 6 +12 13 13 12 +13 13 18 12 +14 14 12 19 +15 15 13 14 +16 1 13 20 +17 1 13 21 +18 13 14 15 +19 1 14 22 +20 1 14 23 +21 14 15 24 +22 14 15 25 +23 13 17 16 +24 14 16 26 +25 14 16 27 +26 15 17 18 +27 1 17 28 +28 1 17 29 +29 1 18 30 +30 1 18 31 + +Angles + +1 9 4 1 8 +2 10 2 1 8 +3 11 8 1 7 +4 8 2 1 4 +5 9 4 1 7 +6 10 2 1 7 +7 8 1 2 4 +8 29 1 2 3 +9 10 1 2 9 +10 5 3 2 4 +11 9 4 2 9 +12 7 3 2 9 +13 4 2 3 6 +14 1 2 3 10 +15 1 2 3 11 +16 3 6 3 10 +17 3 6 3 11 +18 2 10 3 11 +19 12 1 4 2 +20 22 3 6 5 +21 23 13 12 18 +22 24 13 12 19 +23 24 18 12 19 +24 25 14 13 12 +25 26 20 13 12 +26 26 21 13 12 +27 27 14 13 20 +28 27 14 13 21 +29 2 20 13 21 +30 25 13 14 15 +31 27 13 14 22 +32 27 13 14 23 +33 26 22 14 15 +34 26 23 14 15 +35 2 22 14 23 +36 24 14 15 24 +37 24 14 15 25 +38 28 24 15 25 +39 24 17 16 26 +40 24 17 16 27 +41 28 26 16 27 +42 25 18 17 16 +43 26 28 17 16 +44 26 29 17 16 +45 27 18 17 28 +46 27 18 17 29 +47 2 28 17 29 +48 25 17 18 12 +49 26 30 18 12 +50 26 31 18 12 +51 27 17 18 30 +52 27 17 18 31 +53 2 30 18 31 + +Dihedrals + +1 10 8 1 4 2 +2 10 7 1 4 2 +3 13 4 2 1 8 +4 12 3 2 1 8 +5 14 8 1 2 9 +6 11 3 2 1 4 +7 13 4 1 2 9 +8 13 4 2 1 7 +9 12 3 2 1 7 +10 14 7 1 2 9 +11 9 3 2 4 1 +12 10 9 2 4 1 +13 34 1 2 3 6 +14 35 1 2 3 10 +15 35 1 2 3 11 +16 36 4 2 3 6 +17 37 4 2 3 10 +18 37 4 2 3 11 +19 38 9 2 3 6 +20 39 9 2 3 10 +21 39 9 2 3 11 +22 8 2 3 6 5 +23 7 10 3 6 5 +24 7 11 3 6 5 +25 27 14 13 12 18 +26 28 20 13 12 18 +27 28 21 13 12 18 +28 29 14 13 12 19 +29 30 20 13 12 19 +30 30 21 13 12 19 +31 27 17 18 12 13 +32 28 30 18 12 13 +33 28 31 18 12 13 +34 29 17 18 12 19 +35 30 30 18 12 19 +36 30 31 18 12 19 +37 31 12 13 14 15 +38 32 22 14 13 12 +39 32 23 14 13 12 +40 32 20 13 14 15 +41 33 20 13 14 22 +42 33 20 13 14 23 +43 32 21 13 14 15 +44 33 21 13 14 22 +45 33 21 13 14 23 +46 29 13 14 15 24 +47 29 13 14 15 25 +48 30 22 14 15 24 +49 30 22 14 15 25 +50 30 23 14 15 24 +51 30 23 14 15 25 +52 29 18 17 16 26 +53 30 28 17 16 26 +54 30 29 17 16 26 +55 29 18 17 16 27 +56 30 28 17 16 27 +57 30 29 17 16 27 +58 31 16 17 18 12 +59 32 30 18 17 16 +60 32 31 18 17 16 +61 32 28 17 18 12 +62 33 28 17 18 30 +63 33 28 17 18 31 +64 32 29 17 18 12 +65 33 29 17 18 30 +66 33 29 17 18 31 + +Impropers + +1 4 13 12 18 19 +2 5 14 15 24 25 +3 5 17 16 26 27 +4 1 2 1 4 8 +5 1 4 1 8 7 +6 1 2 1 8 7 +7 1 2 1 4 7 +8 1 1 2 3 4 +9 1 1 2 4 9 +10 1 1 2 3 9 +11 1 3 2 4 9 +12 1 2 3 6 10 +13 1 2 3 6 11 +14 1 2 3 10 11 +15 1 6 3 10 11 +16 1 14 13 20 12 +17 1 14 13 21 12 +18 1 20 13 21 12 +19 1 14 13 20 21 +20 1 13 14 22 15 +21 1 13 14 23 15 +22 1 13 14 22 23 +23 1 22 14 23 15 +24 1 18 17 28 16 +25 1 18 17 29 16 +26 1 28 17 29 16 +27 1 18 17 28 29 +28 1 17 18 30 12 +29 1 17 18 31 12 +30 1 30 18 31 12 +31 1 17 18 30 31 diff --git a/examples/USER/misc/bond_react/tiny_epoxy/rxn1_stp2.map b/examples/USER/misc/bond_react/tiny_epoxy/rxn1_stp2.map new file mode 100644 index 0000000000..9e39e57310 --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_epoxy/rxn1_stp2.map @@ -0,0 +1,47 @@ +this is a map file + +1 edgeIDs +31 equivalences + +BondingIDs + +4 +25 + +EdgeIDs + +5 + +Equivalences + +1 1 +2 2 +3 3 +4 4 +5 5 +6 6 +7 7 +8 8 +9 9 +10 10 +11 11 +12 12 +13 13 +14 14 +15 15 +16 16 +17 17 +18 18 +19 19 +20 20 +21 21 +22 22 +23 23 +24 24 +25 25 +26 26 +27 27 +28 28 +29 29 +30 30 +31 31 diff --git a/examples/USER/misc/bond_react/tiny_epoxy/rxn1_stp2_post.data_template b/examples/USER/misc/bond_react/tiny_epoxy/rxn1_stp2_post.data_template new file mode 100644 index 0000000000..cbb66a3151 --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_epoxy/rxn1_stp2_post.data_template @@ -0,0 +1,307 @@ +rxn1_stp2_post + +31 atoms +30 bonds +53 angles +72 dihedrals +31 impropers + +Types + +1 1 +2 6 +3 1 +4 7 +5 4 +6 7 +7 8 +8 8 +9 8 +10 8 +11 8 +12 9 +13 1 +14 1 +15 9 +16 9 +17 1 +18 1 +19 10 +20 8 +21 8 +22 8 +23 8 +24 10 +25 11 +26 10 +27 10 +28 8 +29 8 +30 8 +31 8 + +Charges + +1 0.000000 +2 0.000000 +3 0.000000 +4 0.100000 +5 0.000000 +6 0.000000 +7 0.000000 +8 0.000000 +9 0.000000 +10 0.000000 +11 0.000000 +12 0.000000 +13 0.000000 +14 0.000000 +15 -0.025000 +16 -0.025000 +17 0.000000 +18 0.000000 +19 0.000000 +20 0.000000 +21 0.000000 +22 0.000000 +23 0.000000 +24 0.000000 +25 0.000000 +26 0.000000 +27 0.000000 +28 0.000000 +29 0.000000 +30 0.000000 +31 0.000000 + +Coords + +1 19.846411 9.569080 -1.229960 +2 21.168550 9.331390 -0.418120 +3 21.253010 8.067940 0.460720 +4 21.330839 10.304280 -0.253340 +5 21.891689 5.906200 0.464150 +6 21.818470 6.999870 -0.296270 +7 19.931601 10.026600 -2.215510 +8 19.051279 8.828540 -1.132880 +9 22.228800 9.293580 -0.665280 +10 21.880541 8.270810 1.328060 +11 20.253151 7.789050 0.792640 +12 16.072720 12.338940 -0.174630 +13 16.557051 11.130580 0.587500 +14 18.074381 10.998730 0.366590 +15 18.354031 10.832100 -1.107140 +16 14.920880 15.018100 -0.201130 +17 16.390551 14.791140 -0.461060 +18 16.852989 13.538490 0.304530 +19 16.264271 12.190330 -1.257620 +20 16.025061 10.195290 0.210910 +21 16.346741 11.269890 1.698950 +22 18.466690 10.092460 0.935470 +23 18.592319 11.941150 0.745170 +24 17.213690 10.780300 -1.896260 +25 20.881861 11.302060 -0.773030 +26 14.344180 14.136430 -0.550280 +27 14.583670 15.922830 -0.748110 +28 16.984310 15.696060 -0.103470 +29 16.562460 14.639560 -1.577590 +30 16.674610 13.686010 1.420370 +31 17.964001 13.363150 0.117750 + +Bonds + +1 1 1 8 +2 16 1 2 +3 1 1 7 +4 13 1 15 +5 16 3 2 +6 12 2 9 +7 17 2 4 +8 3 3 6 +9 1 3 10 +10 1 3 11 +11 18 4 25 +12 8 6 5 +13 13 13 12 +14 13 18 12 +15 14 12 19 +16 15 13 14 +17 1 13 20 +18 1 13 21 +19 13 14 15 +20 1 14 22 +21 1 14 23 +22 14 15 24 +23 13 17 16 +24 14 16 26 +25 14 16 27 +26 15 17 18 +27 1 17 28 +28 1 17 29 +29 1 18 30 +30 1 18 31 + +Angles + +1 30 2 1 8 +2 2 8 1 7 +3 26 8 1 15 +4 30 2 1 7 +5 31 2 1 15 +6 26 7 1 15 +7 32 1 2 3 +8 33 1 2 9 +9 34 1 2 4 +10 33 3 2 9 +11 34 3 2 4 +12 35 4 2 9 +13 36 2 3 6 +14 30 2 3 10 +15 30 2 3 11 +16 3 6 3 10 +17 3 6 3 11 +18 2 10 3 11 +19 37 2 4 25 +20 22 3 6 5 +21 23 13 12 18 +22 24 13 12 19 +23 24 18 12 19 +24 25 14 13 12 +25 26 20 13 12 +26 26 21 13 12 +27 27 14 13 20 +28 27 14 13 21 +29 2 20 13 21 +30 25 13 14 15 +31 27 13 14 22 +32 27 13 14 23 +33 26 22 14 15 +34 26 23 14 15 +35 2 22 14 23 +36 23 1 15 14 +37 24 1 15 24 +38 24 14 15 24 +39 24 17 16 26 +40 24 17 16 27 +41 28 26 16 27 +42 25 18 17 16 +43 26 28 17 16 +44 26 29 17 16 +45 27 18 17 28 +46 27 18 17 29 +47 2 28 17 29 +48 25 17 18 12 +49 26 30 18 12 +50 26 31 18 12 +51 27 17 18 30 +52 27 17 18 31 +53 2 30 18 31 + +Dihedrals + +1 40 8 1 2 3 +2 41 8 1 2 9 +3 42 8 1 2 4 +4 40 7 1 2 3 +5 41 7 1 2 9 +6 42 7 1 2 4 +7 43 15 1 2 3 +8 44 15 1 2 9 +9 45 15 1 2 4 +10 28 8 1 15 14 +11 30 8 1 15 24 +12 46 2 1 15 14 +13 47 2 1 15 24 +14 28 7 1 15 14 +15 30 7 1 15 24 +16 48 6 3 2 1 +17 40 10 3 2 1 +18 40 11 3 2 1 +19 49 6 3 2 9 +20 41 10 3 2 9 +21 41 11 3 2 9 +22 50 6 3 2 4 +23 42 10 3 2 4 +24 42 11 3 2 4 +25 52 1 2 4 25 +26 52 3 2 4 25 +27 53 9 2 4 25 +28 51 2 3 6 5 +29 7 10 3 6 5 +30 7 11 3 6 5 +31 27 14 13 12 18 +32 28 20 13 12 18 +33 28 21 13 12 18 +34 29 14 13 12 19 +35 30 20 13 12 19 +36 30 21 13 12 19 +37 27 17 18 12 13 +38 28 30 18 12 13 +39 28 31 18 12 13 +40 29 17 18 12 19 +41 30 30 18 12 19 +42 30 31 18 12 19 +43 31 12 13 14 15 +44 32 22 14 13 12 +45 32 23 14 13 12 +46 32 20 13 14 15 +47 33 20 13 14 22 +48 33 20 13 14 23 +49 32 21 13 14 15 +50 33 21 13 14 22 +51 33 21 13 14 23 +52 27 13 14 15 1 +53 29 13 14 15 24 +54 28 22 14 15 1 +55 30 22 14 15 24 +56 28 23 14 15 1 +57 30 23 14 15 24 +58 29 18 17 16 26 +59 30 28 17 16 26 +60 30 29 17 16 26 +61 29 18 17 16 27 +62 30 28 17 16 27 +63 30 29 17 16 27 +64 31 16 17 18 12 +65 32 30 18 17 16 +66 32 31 18 17 16 +67 32 28 17 18 12 +68 33 28 17 18 30 +69 33 28 17 18 31 +70 32 29 17 18 12 +71 33 29 17 18 30 +72 33 29 17 18 31 + +Impropers + +1 4 13 12 18 19 +2 4 1 15 14 24 +3 5 17 16 26 27 +4 1 2 1 8 7 +5 1 2 1 8 15 +6 1 8 1 7 15 +7 1 2 1 7 15 +8 1 1 2 3 9 +9 1 1 2 3 4 +10 1 1 2 4 9 +11 1 3 2 4 9 +12 1 2 3 6 10 +13 1 2 3 6 11 +14 1 2 3 10 11 +15 1 6 3 10 11 +16 1 14 13 20 12 +17 1 14 13 21 12 +18 1 20 13 21 12 +19 1 14 13 20 21 +20 1 13 14 22 15 +21 1 13 14 23 15 +22 1 13 14 22 23 +23 1 22 14 23 15 +24 1 18 17 28 16 +25 1 18 17 29 16 +26 1 28 17 29 16 +27 1 18 17 28 29 +28 1 17 18 30 12 +29 1 17 18 31 12 +30 1 30 18 31 12 +31 1 17 18 30 31 diff --git a/examples/USER/misc/bond_react/tiny_epoxy/rxn2_stp1.map b/examples/USER/misc/bond_react/tiny_epoxy/rxn2_stp1.map new file mode 100644 index 0000000000..cbe2a44f36 --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_epoxy/rxn2_stp1.map @@ -0,0 +1,59 @@ +this is a map file + +2 edgeIDs +42 equivalences + +BondingIDs + +15 +32 + +EdgeIDs + +5 +36 + +Equivalences + +1 1 +2 2 +3 3 +4 4 +5 5 +6 6 +7 7 +8 8 +9 9 +10 10 +11 11 +12 12 +13 13 +14 14 +15 15 +16 16 +17 17 +18 18 +19 19 +20 20 +21 21 +22 22 +23 23 +24 24 +25 25 +26 26 +27 27 +28 28 +29 29 +30 30 +31 31 +32 32 +33 33 +34 34 +35 35 +36 36 +37 37 +38 38 +39 39 +40 40 +41 41 +42 42 diff --git a/examples/USER/misc/bond_react/tiny_epoxy/rxn2_stp1_post.data_template b/examples/USER/misc/bond_react/tiny_epoxy/rxn2_stp1_post.data_template new file mode 100644 index 0000000000..0600abdc0c --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_epoxy/rxn2_stp1_post.data_template @@ -0,0 +1,424 @@ +rxn2_stp1_post + +42 atoms +41 bonds +75 angles +108 dihedrals +46 impropers + +Types + +1 1 +2 6 +3 1 +4 7 +5 4 +6 7 +7 8 +8 8 +9 8 +10 8 +11 8 +12 9 +13 1 +14 1 +15 9 +16 9 +17 1 +18 1 +19 10 +20 8 +21 8 +22 8 +23 8 +24 10 +25 11 +26 10 +27 10 +28 8 +29 8 +30 8 +31 8 +32 1 +33 6 +34 1 +35 7 +36 4 +37 7 +38 8 +39 8 +40 8 +41 8 +42 8 + +Charges + +1 0.000000 +2 0.000000 +3 0.000000 +4 0.100000 +5 0.000000 +6 0.000000 +7 0.000000 +8 0.000000 +9 0.000000 +10 0.000000 +11 0.000000 +12 0.000000 +13 0.000000 +14 0.000000 +15 -0.025000 +16 -0.025000 +17 0.000000 +18 0.000000 +19 0.000000 +20 0.000000 +21 0.000000 +22 0.000000 +23 0.000000 +24 0.000000 +25 0.000000 +26 0.000000 +27 0.000000 +28 0.000000 +29 0.000000 +30 0.000000 +31 0.000000 +32 0.000000 +33 0.000000 +34 0.000000 +35 0.100000 +36 0.000000 +37 0.000000 +38 0.000000 +39 0.000000 +40 0.000000 +41 0.000000 +42 0.000000 + +Coords + +1 19.846411 9.569080 -1.229960 +2 21.168550 9.331390 -0.418120 +3 21.253010 8.067940 0.460720 +4 21.330839 10.304280 -0.253340 +5 21.891689 5.906200 0.464150 +6 21.818470 6.999870 -0.296270 +7 19.931601 10.026600 -2.215510 +8 19.051279 8.828540 -1.132880 +9 22.228800 9.293580 -0.665280 +10 21.880541 8.270810 1.328060 +11 20.253151 7.789050 0.792640 +12 16.072720 12.338940 -0.174630 +13 16.557051 11.130580 0.587500 +14 18.074381 10.998730 0.366590 +15 18.354031 10.832100 -1.107140 +16 14.920880 15.018100 -0.201130 +17 16.390551 14.791140 -0.461060 +18 16.852989 13.538490 0.304530 +19 16.264271 12.190330 -1.257620 +20 16.025061 10.195290 0.210910 +21 16.346741 11.269890 1.698950 +22 18.466690 10.092460 0.935470 +23 18.592319 11.941150 0.745170 +24 17.213690 10.780300 -1.896260 +25 20.881861 11.302060 -0.773030 +26 14.344180 14.136430 -0.550280 +27 14.583670 15.922830 -0.748110 +28 16.984310 15.696060 -0.103470 +29 16.562460 14.639560 -1.577590 +30 16.674610 13.686010 1.420370 +31 17.964001 13.363150 0.117750 +32 18.680189 9.134390 -4.183100 +33 18.099751 8.263650 -5.343000 +34 19.081829 7.609610 -6.334180 +35 17.971729 9.827680 -5.367080 +36 20.263880 5.733600 -6.736780 +37 19.414030 6.299980 -5.878960 +38 18.194740 9.091640 -3.210950 +39 19.788940 9.208560 -4.119640 +40 17.399309 7.432220 -5.407800 +41 18.616249 7.545570 -7.316910 +42 19.987049 8.212500 -6.399400 + +Bonds + +1 1 1 8 +2 16 1 2 +3 1 1 7 +4 13 1 15 +5 16 3 2 +6 12 2 9 +7 17 2 4 +8 3 3 6 +9 1 3 10 +10 1 3 11 +11 18 4 25 +12 8 6 5 +13 13 13 12 +14 13 18 12 +15 14 12 19 +16 15 13 14 +17 1 13 20 +18 1 13 21 +19 13 14 15 +20 1 14 22 +21 1 14 23 +22 14 15 24 +23 13 32 15 +24 13 17 16 +25 14 16 26 +26 14 16 27 +27 15 17 18 +28 1 17 28 +29 1 17 29 +30 1 18 30 +31 1 18 31 +32 1 32 39 +33 16 32 33 +34 1 32 38 +35 17 33 35 +36 16 34 33 +37 12 33 40 +38 3 34 37 +39 1 34 41 +40 1 34 42 +41 8 37 36 + +Angles + +1 30 2 1 8 +2 2 8 1 7 +3 26 8 1 15 +4 30 2 1 7 +5 31 2 1 15 +6 26 7 1 15 +7 32 1 2 3 +8 33 1 2 9 +9 34 1 2 4 +10 33 3 2 9 +11 34 3 2 4 +12 35 4 2 9 +13 36 2 3 6 +14 30 2 3 10 +15 30 2 3 11 +16 3 6 3 10 +17 3 6 3 11 +18 2 10 3 11 +19 37 2 4 25 +20 22 3 6 5 +21 23 13 12 18 +22 24 13 12 19 +23 24 18 12 19 +24 25 14 13 12 +25 26 20 13 12 +26 26 21 13 12 +27 27 14 13 20 +28 27 14 13 21 +29 2 20 13 21 +30 25 13 14 15 +31 27 13 14 22 +32 27 13 14 23 +33 26 22 14 15 +34 26 23 14 15 +35 2 22 14 23 +36 23 1 15 14 +37 24 1 15 24 +38 23 1 15 32 +39 24 14 15 24 +40 23 14 15 32 +41 24 32 15 24 +42 24 17 16 26 +43 24 17 16 27 +44 28 26 16 27 +45 25 18 17 16 +46 26 28 17 16 +47 26 29 17 16 +48 27 18 17 28 +49 27 18 17 29 +50 2 28 17 29 +51 25 17 18 12 +52 26 30 18 12 +53 26 31 18 12 +54 27 17 18 30 +55 27 17 18 31 +56 2 30 18 31 +57 26 39 32 15 +58 31 33 32 15 +59 26 38 32 15 +60 30 33 32 39 +61 2 39 32 38 +62 30 33 32 38 +63 34 32 33 35 +64 32 32 33 34 +65 33 32 33 40 +66 34 34 33 35 +67 35 35 33 40 +68 33 34 33 40 +69 36 33 34 37 +70 30 33 34 41 +71 30 33 34 42 +72 3 37 34 41 +73 3 37 34 42 +74 2 41 34 42 +75 22 34 37 36 + +Dihedrals + +1 40 8 1 2 3 +2 41 8 1 2 9 +3 42 8 1 2 4 +4 40 7 1 2 3 +5 41 7 1 2 9 +6 42 7 1 2 4 +7 43 15 1 2 3 +8 44 15 1 2 9 +9 45 15 1 2 4 +10 28 8 1 15 14 +11 30 8 1 15 24 +12 28 8 1 15 32 +13 46 2 1 15 14 +14 47 2 1 15 24 +15 46 2 1 15 32 +16 28 7 1 15 14 +17 30 7 1 15 24 +18 28 7 1 15 32 +19 48 6 3 2 1 +20 40 10 3 2 1 +21 40 11 3 2 1 +22 49 6 3 2 9 +23 41 10 3 2 9 +24 41 11 3 2 9 +25 50 6 3 2 4 +26 42 10 3 2 4 +27 42 11 3 2 4 +28 52 1 2 4 25 +29 52 3 2 4 25 +30 53 9 2 4 25 +31 51 2 3 6 5 +32 7 10 3 6 5 +33 7 11 3 6 5 +34 27 14 13 12 18 +35 28 20 13 12 18 +36 28 21 13 12 18 +37 29 14 13 12 19 +38 30 20 13 12 19 +39 30 21 13 12 19 +40 27 17 18 12 13 +41 28 30 18 12 13 +42 28 31 18 12 13 +43 29 17 18 12 19 +44 30 30 18 12 19 +45 30 31 18 12 19 +46 31 12 13 14 15 +47 32 22 14 13 12 +48 32 23 14 13 12 +49 32 20 13 14 15 +50 33 20 13 14 22 +51 33 20 13 14 23 +52 32 21 13 14 15 +53 33 21 13 14 22 +54 33 21 13 14 23 +55 27 13 14 15 1 +56 29 13 14 15 24 +57 27 13 14 15 32 +58 28 22 14 15 1 +59 30 22 14 15 24 +60 28 22 14 15 32 +61 28 23 14 15 1 +62 30 23 14 15 24 +63 28 23 14 15 32 +64 28 39 32 15 1 +65 46 33 32 15 1 +66 28 38 32 15 1 +67 28 39 32 15 14 +68 46 33 32 15 14 +69 28 38 32 15 14 +70 30 39 32 15 24 +71 47 33 32 15 24 +72 30 38 32 15 24 +73 29 18 17 16 26 +74 30 28 17 16 26 +75 30 29 17 16 26 +76 29 18 17 16 27 +77 30 28 17 16 27 +78 30 29 17 16 27 +79 31 16 17 18 12 +80 32 30 18 17 16 +81 32 31 18 17 16 +82 32 28 17 18 12 +83 33 28 17 18 30 +84 33 28 17 18 31 +85 32 29 17 18 12 +86 33 29 17 18 30 +87 33 29 17 18 31 +88 45 15 32 33 35 +89 43 15 32 33 34 +90 44 15 32 33 40 +91 42 39 32 33 35 +92 40 39 32 33 34 +93 41 39 32 33 40 +94 42 38 32 33 35 +95 40 38 32 33 34 +96 41 38 32 33 40 +97 48 37 34 33 32 +98 40 41 34 33 32 +99 40 42 34 33 32 +100 50 37 34 33 35 +101 42 41 34 33 35 +102 42 42 34 33 35 +103 49 37 34 33 40 +104 41 41 34 33 40 +105 41 42 34 33 40 +106 51 33 34 37 36 +107 7 41 34 37 36 +108 7 42 34 37 36 + +Impropers + +1 4 13 12 18 19 +2 5 17 16 26 27 +3 1 2 1 8 7 +4 1 2 1 8 15 +5 1 8 1 7 15 +6 1 2 1 7 15 +7 1 1 2 3 9 +8 1 1 2 3 4 +9 1 1 2 4 9 +10 1 3 2 4 9 +11 1 2 3 6 10 +12 1 2 3 6 11 +13 1 2 3 10 11 +14 1 6 3 10 11 +15 1 14 13 20 12 +16 1 14 13 21 12 +17 1 20 13 21 12 +18 1 14 13 20 21 +19 1 13 14 22 15 +20 1 13 14 23 15 +21 1 13 14 22 23 +22 1 22 14 23 15 +23 1 1 15 14 24 +24 1 1 15 14 32 +25 1 1 15 32 24 +26 1 14 15 32 24 +27 1 18 17 28 16 +28 1 18 17 29 16 +29 1 28 17 29 16 +30 1 18 17 28 29 +31 1 17 18 30 12 +32 1 17 18 31 12 +33 1 30 18 31 12 +34 1 17 18 30 31 +35 1 33 32 39 15 +36 1 39 32 38 15 +37 1 33 32 38 15 +38 1 33 32 39 38 +39 1 32 33 34 35 +40 1 32 33 35 40 +41 1 32 33 34 40 +42 1 34 33 35 40 +43 1 33 34 37 41 +44 1 33 34 37 42 +45 1 33 34 41 42 +46 1 37 34 41 42 diff --git a/examples/USER/misc/bond_react/tiny_epoxy/rxn2_stp1_pre.data_template b/examples/USER/misc/bond_react/tiny_epoxy/rxn2_stp1_pre.data_template new file mode 100644 index 0000000000..9ee4ffb2de --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_epoxy/rxn2_stp1_pre.data_template @@ -0,0 +1,407 @@ +rxn2_stp1_pre + +42 atoms +41 bonds +73 angles +96 dihedrals +43 impropers + +Types + +1 1 +2 6 +3 1 +4 7 +5 4 +6 7 +7 8 +8 8 +9 8 +10 8 +11 8 +12 9 +13 1 +14 1 +15 9 +16 9 +17 1 +18 1 +19 10 +20 8 +21 8 +22 8 +23 8 +24 10 +25 11 +26 10 +27 10 +28 8 +29 8 +30 8 +31 8 +32 2 +33 2 +34 1 +35 3 +36 4 +37 7 +38 8 +39 8 +40 8 +41 8 +42 8 + +Charges + +1 0.000000 +2 0.000000 +3 0.000000 +4 0.100000 +5 0.000000 +6 0.000000 +7 0.000000 +8 0.000000 +9 0.000000 +10 0.000000 +11 0.000000 +12 0.000000 +13 0.000000 +14 0.000000 +15 -0.025000 +16 -0.025000 +17 0.000000 +18 0.000000 +19 0.000000 +20 0.000000 +21 0.000000 +22 0.000000 +23 0.000000 +24 0.000000 +25 0.000000 +26 0.000000 +27 0.000000 +28 0.000000 +29 0.000000 +30 0.000000 +31 0.000000 +32 0.000000 +33 0.000000 +34 0.000000 +35 0.100000 +36 0.000000 +37 0.000000 +38 0.000000 +39 0.000000 +40 0.000000 +41 0.000000 +42 0.000000 + +Coords + +1 19.846411 9.569080 -1.229960 +2 21.168550 9.331390 -0.418120 +3 21.253010 8.067940 0.460720 +4 21.330839 10.304280 -0.253340 +5 21.891689 5.906200 0.464150 +6 21.818470 6.999870 -0.296270 +7 19.931601 10.026600 -2.215510 +8 19.051279 8.828540 -1.132880 +9 22.228800 9.293580 -0.665280 +10 21.880541 8.270810 1.328060 +11 20.253151 7.789050 0.792640 +12 16.072720 12.338940 -0.174630 +13 16.557051 11.130580 0.587500 +14 18.074381 10.998730 0.366590 +15 18.354031 10.832100 -1.107140 +16 14.920880 15.018100 -0.201130 +17 16.390551 14.791140 -0.461060 +18 16.852989 13.538490 0.304530 +19 16.264271 12.190330 -1.257620 +20 16.025061 10.195290 0.210910 +21 16.346741 11.269890 1.698950 +22 18.466690 10.092460 0.935470 +23 18.592319 11.941150 0.745170 +24 17.213690 10.780300 -1.896260 +25 20.881861 11.302060 -0.773030 +26 14.344180 14.136430 -0.550280 +27 14.583670 15.922830 -0.748110 +28 16.984310 15.696060 -0.103470 +29 16.562460 14.639560 -1.577590 +30 16.674610 13.686010 1.420370 +31 17.964001 13.363150 0.117750 +32 18.703360 9.118830 -4.174240 +33 18.099751 8.263650 -5.343000 +34 19.081829 7.609610 -6.334180 +35 17.971729 9.827680 -5.367080 +36 20.263880 5.733600 -6.736780 +37 19.414030 6.299980 -5.878960 +38 18.194740 9.091640 -3.210950 +39 19.788940 9.208560 -4.119640 +40 17.399309 7.432220 -5.407800 +41 18.616249 7.545570 -7.316910 +42 19.987049 8.212500 -6.399400 + +Bonds + +1 1 1 8 +2 16 1 2 +3 1 1 7 +4 13 1 15 +5 16 3 2 +6 12 2 9 +7 17 2 4 +8 3 3 6 +9 1 3 10 +10 1 3 11 +11 18 4 25 +12 8 6 5 +13 13 13 12 +14 13 18 12 +15 14 12 19 +16 15 13 14 +17 1 13 20 +18 1 13 21 +19 13 14 15 +20 1 14 22 +21 1 14 23 +22 14 15 24 +23 13 17 16 +24 14 16 26 +25 14 16 27 +26 15 17 18 +27 1 17 28 +28 1 17 29 +29 1 18 30 +30 1 18 31 +31 6 39 32 +32 4 32 35 +33 5 32 33 +34 6 38 32 +35 4 33 35 +36 2 34 33 +37 6 40 33 +38 3 34 37 +39 1 34 41 +40 1 34 42 +41 8 37 36 + +Angles + +1 30 2 1 8 +2 2 8 1 7 +3 26 8 1 15 +4 30 2 1 7 +5 31 2 1 15 +6 26 7 1 15 +7 32 1 2 3 +8 33 1 2 9 +9 34 1 2 4 +10 33 3 2 9 +11 34 3 2 4 +12 35 4 2 9 +13 36 2 3 6 +14 30 2 3 10 +15 30 2 3 11 +16 3 6 3 10 +17 3 6 3 11 +18 2 10 3 11 +19 37 2 4 25 +20 22 3 6 5 +21 23 13 12 18 +22 24 13 12 19 +23 24 18 12 19 +24 25 14 13 12 +25 26 20 13 12 +26 26 21 13 12 +27 27 14 13 20 +28 27 14 13 21 +29 2 20 13 21 +30 25 13 14 15 +31 27 13 14 22 +32 27 13 14 23 +33 26 22 14 15 +34 26 23 14 15 +35 2 22 14 23 +36 23 1 15 14 +37 24 1 15 24 +38 24 14 15 24 +39 24 17 16 26 +40 24 17 16 27 +41 28 26 16 27 +42 25 18 17 16 +43 26 28 17 16 +44 26 29 17 16 +45 27 18 17 28 +46 27 18 17 29 +47 2 28 17 29 +48 25 17 18 12 +49 26 30 18 12 +50 26 31 18 12 +51 27 17 18 30 +52 27 17 18 31 +53 2 30 18 31 +54 38 39 32 35 +55 39 39 32 33 +56 11 39 32 38 +57 8 33 32 35 +58 38 38 32 35 +59 39 38 32 33 +60 8 32 33 35 +61 6 34 33 32 +62 39 40 33 32 +63 5 34 33 35 +64 38 40 33 35 +65 7 34 33 40 +66 40 37 34 33 +67 41 41 34 33 +68 41 42 34 33 +69 3 37 34 41 +70 3 37 34 42 +71 2 41 34 42 +72 12 32 35 33 +73 22 34 37 36 + +Dihedrals + +1 40 8 1 2 3 +2 41 8 1 2 9 +3 42 8 1 2 4 +4 40 7 1 2 3 +5 41 7 1 2 9 +6 42 7 1 2 4 +7 43 15 1 2 3 +8 44 15 1 2 9 +9 45 15 1 2 4 +10 28 8 1 15 14 +11 30 8 1 15 24 +12 46 2 1 15 14 +13 47 2 1 15 24 +14 28 7 1 15 14 +15 30 7 1 15 24 +16 48 6 3 2 1 +17 40 10 3 2 1 +18 40 11 3 2 1 +19 49 6 3 2 9 +20 41 10 3 2 9 +21 41 11 3 2 9 +22 50 6 3 2 4 +23 42 10 3 2 4 +24 42 11 3 2 4 +25 52 1 2 4 25 +26 52 3 2 4 25 +27 53 9 2 4 25 +28 51 2 3 6 5 +29 7 10 3 6 5 +30 7 11 3 6 5 +31 27 14 13 12 18 +32 28 20 13 12 18 +33 28 21 13 12 18 +34 29 14 13 12 19 +35 30 20 13 12 19 +36 30 21 13 12 19 +37 27 17 18 12 13 +38 28 30 18 12 13 +39 28 31 18 12 13 +40 29 17 18 12 19 +41 30 30 18 12 19 +42 30 31 18 12 19 +43 31 12 13 14 15 +44 32 22 14 13 12 +45 32 23 14 13 12 +46 32 20 13 14 15 +47 33 20 13 14 22 +48 33 20 13 14 23 +49 32 21 13 14 15 +50 33 21 13 14 22 +51 33 21 13 14 23 +52 27 13 14 15 1 +53 29 13 14 15 24 +54 28 22 14 15 1 +55 30 22 14 15 24 +56 28 23 14 15 1 +57 30 23 14 15 24 +58 29 18 17 16 26 +59 30 28 17 16 26 +60 30 29 17 16 26 +61 29 18 17 16 27 +62 30 28 17 16 27 +63 30 29 17 16 27 +64 31 16 17 18 12 +65 32 30 18 17 16 +66 32 31 18 17 16 +67 32 28 17 18 12 +68 33 28 17 18 30 +69 33 28 17 18 31 +70 32 29 17 18 12 +71 33 29 17 18 30 +72 33 29 17 18 31 +73 10 39 32 35 33 +74 10 38 32 35 33 +75 54 39 32 33 35 +76 12 34 33 32 39 +77 14 39 32 33 40 +78 11 34 33 32 35 +79 54 40 33 32 35 +80 54 38 32 33 35 +81 12 34 33 32 38 +82 14 38 32 33 40 +83 9 34 33 35 32 +84 10 40 33 35 32 +85 5 37 34 33 32 +86 2 41 34 33 32 +87 2 42 34 33 32 +88 4 37 34 33 35 +89 1 41 34 33 35 +90 1 42 34 33 35 +91 6 37 34 33 40 +92 3 41 34 33 40 +93 3 42 34 33 40 +94 8 33 34 37 36 +95 7 41 34 37 36 +96 7 42 34 37 36 + +Impropers + +1 4 13 12 18 19 +2 4 1 15 14 24 +3 5 17 16 26 27 +4 1 2 1 8 7 +5 1 2 1 8 15 +6 1 8 1 7 15 +7 1 2 1 7 15 +8 1 1 2 3 9 +9 1 1 2 3 4 +10 1 1 2 4 9 +11 1 3 2 4 9 +12 1 2 3 6 10 +13 1 2 3 6 11 +14 1 2 3 10 11 +15 1 6 3 10 11 +16 1 14 13 20 12 +17 1 14 13 21 12 +18 1 20 13 21 12 +19 1 14 13 20 21 +20 1 13 14 22 15 +21 1 13 14 23 15 +22 1 13 14 22 23 +23 1 22 14 23 15 +24 1 18 17 28 16 +25 1 18 17 29 16 +26 1 28 17 29 16 +27 1 18 17 28 29 +28 1 17 18 30 12 +29 1 17 18 31 12 +30 1 30 18 31 12 +31 1 17 18 30 31 +32 1 39 32 33 35 +33 1 39 32 38 35 +34 1 39 32 38 33 +35 1 38 32 33 35 +36 1 34 33 32 35 +37 1 40 33 32 35 +38 1 34 33 40 32 +39 1 34 33 40 35 +40 1 37 34 41 33 +41 1 37 34 42 33 +42 1 41 34 42 33 +43 1 37 34 41 42 diff --git a/examples/USER/misc/bond_react/tiny_epoxy/rxn2_stp2.map b/examples/USER/misc/bond_react/tiny_epoxy/rxn2_stp2.map new file mode 100644 index 0000000000..f90915a54f --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_epoxy/rxn2_stp2.map @@ -0,0 +1,59 @@ +this is a map file + +2 edgeIDs +42 equivalences + +BondingIDs + +35 +24 + +EdgeIDs + +5 +36 + +Equivalences + +1 1 +2 2 +3 3 +4 4 +5 5 +6 6 +7 7 +8 8 +9 9 +10 10 +11 11 +12 12 +13 13 +14 14 +15 15 +16 16 +17 17 +18 18 +19 19 +20 20 +21 21 +22 22 +23 23 +24 24 +25 25 +26 26 +27 27 +28 28 +29 29 +30 30 +31 31 +32 32 +33 33 +34 34 +35 35 +36 36 +37 37 +38 38 +39 39 +40 40 +41 41 +42 42 diff --git a/examples/USER/misc/bond_react/tiny_epoxy/rxn2_stp2_post.data_template b/examples/USER/misc/bond_react/tiny_epoxy/rxn2_stp2_post.data_template new file mode 100644 index 0000000000..2b37ecff03 --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_epoxy/rxn2_stp2_post.data_template @@ -0,0 +1,413 @@ +rxn2_stp2_post + +42 atoms +41 bonds +73 angles +102 dihedrals +43 impropers + +Types + +1 1 +2 2 +3 1 +4 7 +5 4 +6 7 +7 8 +8 8 +9 8 +10 8 +11 8 +12 9 +13 1 +14 1 +15 9 +16 9 +17 1 +18 1 +19 10 +20 8 +21 8 +22 8 +23 8 +24 11 +25 11 +26 10 +27 10 +28 8 +29 8 +30 8 +31 8 +32 1 +33 6 +34 1 +35 7 +36 4 +37 7 +38 8 +39 8 +40 8 +41 8 +42 8 + +Charges + +1 0.000000 +2 0.000000 +3 0.000000 +4 0.100000 +5 0.000000 +6 0.000000 +7 0.000000 +8 0.000000 +9 0.000000 +10 0.000000 +11 0.000000 +12 0.000000 +13 0.000000 +14 0.000000 +15 -0.025000 +16 -0.025000 +17 0.000000 +18 0.000000 +19 0.000000 +20 0.000000 +21 0.000000 +22 0.000000 +23 0.000000 +24 0.000000 +25 0.000000 +26 0.000000 +27 0.000000 +28 0.000000 +29 0.000000 +30 0.000000 +31 0.000000 +32 0.000000 +33 0.000000 +34 0.000000 +35 0.100000 +36 0.000000 +37 0.000000 +38 0.000000 +39 0.000000 +40 0.000000 +41 0.000000 +42 0.000000 + +Coords + +1 19.846411 9.569080 -1.229960 +2 21.168550 9.331390 -0.418120 +3 21.253010 8.067940 0.460720 +4 21.330839 10.304280 -0.253340 +5 21.891689 5.906200 0.464150 +6 21.818470 6.999870 -0.296270 +7 19.931601 10.026600 -2.215510 +8 19.051279 8.828540 -1.132880 +9 22.228800 9.293580 -0.665280 +10 21.880541 8.270810 1.328060 +11 20.253151 7.789050 0.792640 +12 16.072720 12.338940 -0.174630 +13 16.557051 11.130580 0.587500 +14 18.074381 10.998730 0.366590 +15 18.354031 10.832100 -1.107140 +16 14.920880 15.018100 -0.201130 +17 16.390551 14.791140 -0.461060 +18 16.852989 13.538490 0.304530 +19 16.264271 12.190330 -1.257620 +20 16.025061 10.195290 0.210910 +21 16.346741 11.269890 1.698950 +22 18.466690 10.092460 0.935470 +23 18.592319 11.941150 0.745170 +24 16.017490 9.805710 -4.329880 +25 20.881861 11.302060 -0.773030 +26 14.344180 14.136430 -0.550280 +27 14.583670 15.922830 -0.748110 +28 16.984310 15.696060 -0.103470 +29 16.562460 14.639560 -1.577590 +30 16.674610 13.686010 1.420370 +31 17.964001 13.363150 0.117750 +32 18.680189 9.134390 -4.183100 +33 18.099751 8.263650 -5.343000 +34 19.081829 7.609610 -6.334180 +35 17.971729 9.827680 -5.367080 +36 20.263880 5.733600 -6.736780 +37 19.414030 6.299980 -5.878960 +38 18.194740 9.091640 -3.210950 +39 19.788940 9.208560 -4.119640 +40 17.399309 7.432220 -5.407800 +41 18.616249 7.545570 -7.316910 +42 19.987049 8.212500 -6.399400 + +Bonds + +1 1 1 8 +2 2 1 2 +3 1 1 7 +4 13 1 15 +5 2 3 2 +6 6 2 9 +7 19 2 4 +8 3 3 6 +9 1 3 10 +10 1 3 11 +11 18 4 25 +12 8 6 5 +13 13 13 12 +14 13 18 12 +15 14 12 19 +16 15 13 14 +17 1 13 20 +18 1 13 21 +19 13 14 15 +20 1 14 22 +21 1 14 23 +22 13 32 15 +23 13 17 16 +24 14 16 26 +25 14 16 27 +26 15 17 18 +27 1 17 28 +28 1 17 29 +29 1 18 30 +30 1 18 31 +31 18 35 24 +32 1 32 39 +33 16 32 33 +34 1 32 38 +35 17 35 33 +36 16 34 33 +37 12 40 33 +38 3 34 37 +39 1 34 41 +40 1 34 42 +41 8 37 36 + +Angles + +1 1 2 1 8 +2 2 8 1 7 +3 26 8 1 15 +4 1 2 1 7 +5 42 2 1 15 +6 26 7 1 15 +7 43 1 2 3 +8 7 1 2 9 +9 44 1 2 4 +10 7 3 2 9 +11 44 3 2 4 +12 45 4 2 9 +13 4 2 3 6 +14 1 2 3 10 +15 1 2 3 11 +16 3 6 3 10 +17 3 6 3 11 +18 2 10 3 11 +19 46 2 4 25 +20 22 3 6 5 +21 23 13 12 18 +22 24 13 12 19 +23 24 18 12 19 +24 25 14 13 12 +25 26 20 13 12 +26 26 21 13 12 +27 27 14 13 20 +28 27 14 13 21 +29 2 20 13 21 +30 25 13 14 15 +31 27 13 14 22 +32 27 13 14 23 +33 26 22 14 15 +34 26 23 14 15 +35 2 22 14 23 +36 23 1 15 14 +37 23 1 15 32 +38 23 14 15 32 +39 24 17 16 26 +40 24 17 16 27 +41 28 26 16 27 +42 25 18 17 16 +43 26 28 17 16 +44 26 29 17 16 +45 27 18 17 28 +46 27 18 17 29 +47 2 28 17 29 +48 25 17 18 12 +49 26 30 18 12 +50 26 31 18 12 +51 27 17 18 30 +52 27 17 18 31 +53 2 30 18 31 +54 26 39 32 15 +55 47 15 32 33 +56 26 38 32 15 +57 48 39 32 33 +58 2 39 32 38 +59 48 38 32 33 +60 34 32 33 35 +61 32 32 33 34 +62 33 32 33 40 +63 34 34 33 35 +64 35 35 33 40 +65 33 34 33 40 +66 49 37 34 33 +67 48 41 34 33 +68 48 42 34 33 +69 3 37 34 41 +70 3 37 34 42 +71 2 41 34 42 +72 50 24 35 33 +73 22 34 37 36 + +Dihedrals + +1 55 8 1 2 3 +2 3 8 1 2 9 +3 56 8 1 2 4 +4 55 7 1 2 3 +5 3 7 1 2 9 +6 56 7 1 2 4 +7 57 15 1 2 3 +8 58 15 1 2 9 +9 59 15 1 2 4 +10 28 8 1 15 14 +11 28 8 1 15 32 +12 60 2 1 15 14 +13 60 2 1 15 32 +14 28 7 1 15 14 +15 28 7 1 15 32 +16 61 6 3 2 1 +17 55 10 3 2 1 +18 55 11 3 2 1 +19 6 6 3 2 9 +20 3 10 3 2 9 +21 3 11 3 2 9 +22 62 6 3 2 4 +23 56 10 3 2 4 +24 56 11 3 2 4 +25 63 1 2 4 25 +26 63 3 2 4 25 +27 64 9 2 4 25 +28 8 2 3 6 5 +29 7 10 3 6 5 +30 7 11 3 6 5 +31 27 14 13 12 18 +32 28 20 13 12 18 +33 28 21 13 12 18 +34 29 14 13 12 19 +35 30 20 13 12 19 +36 30 21 13 12 19 +37 27 17 18 12 13 +38 28 30 18 12 13 +39 28 31 18 12 13 +40 29 17 18 12 19 +41 30 30 18 12 19 +42 30 31 18 12 19 +43 31 12 13 14 15 +44 32 22 14 13 12 +45 32 23 14 13 12 +46 32 20 13 14 15 +47 33 20 13 14 22 +48 33 20 13 14 23 +49 32 21 13 14 15 +50 33 21 13 14 22 +51 33 21 13 14 23 +52 27 13 14 15 1 +53 27 13 14 15 32 +54 28 22 14 15 1 +55 28 22 14 15 32 +56 28 23 14 15 1 +57 28 23 14 15 32 +58 28 39 32 15 1 +59 46 33 32 15 1 +60 28 38 32 15 1 +61 28 39 32 15 14 +62 46 33 32 15 14 +63 28 38 32 15 14 +64 29 18 17 16 26 +65 30 28 17 16 26 +66 30 29 17 16 26 +67 29 18 17 16 27 +68 30 28 17 16 27 +69 30 29 17 16 27 +70 31 16 17 18 12 +71 32 30 18 17 16 +72 32 31 18 17 16 +73 32 28 17 18 12 +74 33 28 17 18 30 +75 33 28 17 18 31 +76 32 29 17 18 12 +77 33 29 17 18 30 +78 33 29 17 18 31 +79 45 15 32 33 35 +80 43 15 32 33 34 +81 44 15 32 33 40 +82 42 39 32 33 35 +83 40 39 32 33 34 +84 41 39 32 33 40 +85 42 38 32 33 35 +86 40 38 32 33 34 +87 41 38 32 33 40 +88 65 24 35 33 32 +89 65 24 35 33 34 +90 66 24 35 33 40 +91 48 37 34 33 32 +92 40 41 34 33 32 +93 40 42 34 33 32 +94 50 37 34 33 35 +95 42 41 34 33 35 +96 42 42 34 33 35 +97 49 37 34 33 40 +98 41 41 34 33 40 +99 41 42 34 33 40 +100 51 33 34 37 36 +101 7 41 34 37 36 +102 7 42 34 37 36 + +Impropers + +1 4 13 12 18 19 +2 22 1 15 14 32 +3 5 17 16 26 27 +4 1 2 1 8 7 +5 1 2 1 8 15 +6 1 8 1 7 15 +7 1 2 1 7 15 +8 1 1 2 3 9 +9 1 1 2 3 4 +10 1 1 2 4 9 +11 1 3 2 4 9 +12 1 2 3 6 10 +13 1 2 3 6 11 +14 1 2 3 10 11 +15 1 6 3 10 11 +16 1 14 13 20 12 +17 1 14 13 21 12 +18 1 20 13 21 12 +19 1 14 13 20 21 +20 1 13 14 22 15 +21 1 13 14 23 15 +22 1 13 14 22 23 +23 1 22 14 23 15 +24 1 18 17 28 16 +25 1 18 17 29 16 +26 1 28 17 29 16 +27 1 18 17 28 29 +28 1 17 18 30 12 +29 1 17 18 31 12 +30 1 30 18 31 12 +31 1 17 18 30 31 +32 1 39 32 15 33 +33 1 39 32 38 15 +34 1 38 32 15 33 +35 1 39 32 38 33 +36 1 32 33 34 35 +37 1 32 33 35 40 +38 1 32 33 34 40 +39 1 34 33 35 40 +40 1 37 34 41 33 +41 1 37 34 42 33 +42 1 41 34 42 33 +43 1 37 34 41 42 diff --git a/examples/USER/misc/bond_react/tiny_epoxy/tiny_epoxy.data b/examples/USER/misc/bond_react/tiny_epoxy/tiny_epoxy.data new file mode 100644 index 0000000000..d98006b107 --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_epoxy/tiny_epoxy.data @@ -0,0 +1,1582 @@ +# two molecules DGEBA (diepoxy) and one DETA (linker) + +118 atoms +123 bonds +221 angles +302 dihedrals +115 impropers +11 atom types +19 bond types +50 angle types +66 dihedral types +22 improper types +10 30 xlo xhi +-10 20 ylo yhi +-15 10 zlo zhi + +Masses + +1 12.011150 # c2 +2 12.011150 # c3m +3 15.999400 # o3e +4 12.011150 # cp +5 12.011150 # c +6 12.011150 # c3 +7 15.999400 # oc +8 1.007970 # hc +9 14.006700 # na +10 1.007970 # hn +11 1.007970 # ho + +Pair Coeffs # lj/class2/coul/long + +1 0.0540000000 4.0100000000 # c2 +2 0.0540000000 4.0100000000 # c3m +3 0.2400000000 3.5350000000 # o3e +4 0.0640000000 4.0100000000 # cp +5 0.0540000000 4.0100000000 # c +6 0.0540000000 4.0100000000 # c3 +7 0.2400000000 3.5350000000 # oc +8 0.0200000000 2.7000000000 # hc +9 0.0650000000 4.0700000000 # na +10 0.0130000000 1.0980000000 # hn +11 0.0130000000 1.0980000000 # ho + +Bond Coeffs # class2 + +1 1.1010 345.0000 -691.8900 844.6000 # c2-hc +2 1.5300 299.6700 -501.7700 679.8100 # c2-c3m +3 1.4200 400.3954 -835.1951 1313.0142 # c2-oc +4 1.4200 400.3954 -835.1951 1313.0142 # c3m-o3e +5 1.5300 299.6700 -501.7700 679.8100 # c3m-c3m +6 1.1010 345.0000 -691.8900 844.6000 # c3m-hc +7 1.4170 470.8361 -627.6179 1327.6345 # cp-cp +8 1.3768 428.8798 -738.2351 1114.9655 # cp-oc +9 1.0982 372.8251 -803.4526 894.3173 # cp-hc +10 1.5010 321.9021 -521.8208 572.1628 # cp-c +11 1.5300 299.6700 -501.7700 679.8100 # c-c3 +12 1.1010 345.0000 -691.8900 844.6000 # c3-hc +13 1.4570 365.8052 -699.6368 998.4842 # c2-na +14 1.0060 466.7400 -1073.6018 1251.1056 # na-hn +15 1.5300 299.6700 -501.7700 679.8100 # c2-c2 +16 1.5300 299.6700 -501.7700 679.8100 # c2-c3 +17 1.4200 400.3954 -835.1951 1313.0142 # c3-oc +18 0.9650 532.5062 -1282.9050 2004.7658 # oc-ho +19 1.4200 400.3954 -835.1951 1313.0142 # c3m-oc + +Angle Coeffs # class2 + +1 110.7700 41.4530 -10.6040 5.1290 # c3m-c2-hc +2 107.6600 39.6410 -12.9210 -2.4318 # hc-c2-hc +3 108.7280 58.5446 -10.8088 -12.4006 # oc-c2-hc +4 111.2700 54.5381 -8.3642 -13.0838 # c3m-c2-oc +5 111.2700 54.5381 -8.3642 -13.0838 # c2-c3m-o3e +6 112.6700 39.5160 -7.4430 -9.5583 # c2-c3m-c3m +7 110.7700 41.4530 -10.6040 5.1290 # c2-c3m-hc +8 111.2700 54.5381 -8.3642 -13.0838 # c3m-c3m-o3e +9 108.7280 58.5446 -10.8088 -12.4006 # o3e-c3m-hc +10 110.7700 41.4530 -10.6040 5.1290 # c3m-c3m-hc +11 107.6600 39.6410 -12.9210 -2.4318 # hc-c3m-hc +12 104.5000 35.7454 -10.0067 -6.2729 # c3m-o3e-c3m +13 118.9000 61.0226 -34.9931 0.0000 # cp-cp-cp +14 123.4200 73.6781 -21.6787 0.0000 # cp-cp-oc +15 117.9400 35.1558 -12.4682 0.0000 # cp-cp-hc +16 120.0500 44.7148 -22.7352 0.0000 # cp-cp-c +17 108.4000 43.9594 -8.3924 -9.3379 # cp-c-c3 +18 111.0000 44.3234 -9.4454 0.0000 # cp-c-cp +19 112.6700 39.5160 -7.4430 -9.5583 # c3-c-c3 +20 110.7700 41.4530 -10.6040 5.1290 # c-c3-hc +21 107.6600 39.6410 -12.9210 -2.4318 # hc-c3-hc +22 102.9695 38.9739 -6.2595 -8.1710 # c2-oc-cp +23 112.4436 47.2337 -10.6612 -10.2062 # c2-na-c2 +24 110.9538 50.8652 -4.4522 -10.0298 # c2-na-hn +25 111.9100 60.7147 -13.3366 -13.0785 # c2-c2-na +26 110.6204 51.3137 -6.7198 -2.6003 # hc-c2-na +27 110.7700 41.4530 -10.6040 5.1290 # c2-c2-hc +28 107.0671 45.2520 -7.5558 -9.5120 # hn-na-hn +29 112.6700 39.5160 -7.4430 -9.5583 # c3m-c3m-c2 +30 110.7700 41.4530 -10.6040 5.1290 # c3-c2-hc +31 111.9100 60.7147 -13.3366 -13.0785 # c3-c2-na +32 112.6700 39.5160 -7.4430 -9.5583 # c2-c3-c2 +33 110.7700 41.4530 -10.6040 5.1290 # c2-c3-hc +34 111.2700 54.5381 -8.3642 -13.0838 # c2-c3-oc +35 108.7280 58.5446 -10.8088 -12.4006 # oc-c3-hc +36 111.2700 54.5381 -8.3642 -13.0838 # c3-c2-oc +37 105.8000 52.7061 -12.1090 -9.8681 # c3-oc-ho +38 108.7280 58.5446 -10.8088 -12.4006 # hc-c3m-o3e +39 110.7700 41.4530 -10.6040 5.1290 # hc-c3m-c3m +40 111.2700 54.5381 -8.3642 -13.0838 # oc-c2-c3m +41 110.7700 41.4530 -10.6040 5.1290 # hc-c2-c3m +42 111.9100 60.7147 -13.3366 -13.0785 # c3m-c2-na +43 112.6700 39.5160 -7.4430 -9.5583 # c2-c3m-c2 +44 111.2700 54.5381 -8.3642 -13.0838 # c2-c3m-oc +45 108.7280 58.5446 -10.8088 -12.4006 # oc-c3m-hc +46 105.8000 52.7061 -12.1090 -9.8681 # c3m-oc-ho +47 111.9100 60.7147 -13.3366 -13.0785 # na-c2-c3 +48 110.7700 41.4530 -10.6040 5.1290 # hc-c2-c3 +49 111.2700 54.5381 -8.3642 -13.0838 # oc-c2-c3 +50 105.8000 52.7061 -12.1090 -9.8681 # ho-oc-c3 + +Dihedral Coeffs # class2 + +1 -0.1435 0.0000 0.2530 0.0000 -0.0905 0.0000# hc-c2-c3m-o3e +2 0.0000 0.0000 0.0316 0.0000 -0.1681 0.0000# hc-c2-c3m-c3m +3 -0.1432 0.0000 0.0617 0.0000 -0.1083 0.0000# hc-c2-c3m-hc +4 -0.1820 0.0000 -0.1084 0.0000 -0.7047 0.0000# oc-c2-c3m-o3e +5 0.7137 0.0000 0.2660 0.0000 -0.2545 0.0000# oc-c2-c3m-c3m +6 -0.1435 0.0000 0.2530 0.0000 -0.0905 0.0000# oc-c2-c3m-hc +7 0.9513 0.0000 0.1155 0.0000 0.0720 0.0000# hc-c2-oc-cp +8 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000# c3m-c2-oc-cp +9 -0.5203 0.0000 -0.3028 0.0000 -0.3450 0.0000# c2-c3m-o3e-c3m +10 0.5302 0.0000 0.0000 0.0000 -0.3966 0.0000# hc-c3m-o3e-c3m +11 0.7137 0.0000 0.2660 0.0000 -0.2545 0.0000# c2-c3m-c3m-o3e +12 0.0000 0.0000 0.0316 0.0000 -0.1681 0.0000# c2-c3m-c3m-hc +13 -0.1435 0.0000 0.2530 0.0000 -0.0905 0.0000# o3e-c3m-c3m-hc +14 -0.1432 0.0000 0.0617 0.0000 -0.1083 0.0000# hc-c3m-c3m-hc +15 8.3667 0.0000 1.1932 0.0000 0.0000 0.0000# cp-cp-cp-cp +16 0.0000 0.0000 3.9661 0.0000 0.0000 0.0000# cp-cp-cp-hc +17 0.0000 0.0000 4.8498 0.0000 0.0000 0.0000# cp-cp-cp-oc +18 0.0000 0.0000 1.7234 0.0000 0.0000 0.0000# oc-cp-cp-hc +19 0.0000 0.0000 1.5000 0.0000 0.0000 0.0000# cp-cp-oc-c2 +20 0.0000 0.0000 1.8769 0.0000 0.0000 0.0000# hc-cp-cp-hc +21 0.0000 0.0000 4.4072 0.0000 0.0000 0.0000# cp-cp-cp-c +22 0.0000 0.0000 1.5590 0.0000 0.0000 0.0000# c-cp-cp-hc +23 -0.2802 0.0000 -0.0678 0.0000 -0.0122 0.0000# cp-cp-c-c3 +24 -0.2802 0.0000 -0.0678 0.0000 -0.0122 0.0000# cp-cp-c-cp +25 -0.0228 0.0000 0.0280 0.0000 -0.1863 0.0000# cp-c-c3-hc +26 0.0000 0.0000 0.0316 0.0000 -0.1681 0.0000# c3-c-c3-hc +27 -0.1406 0.0000 0.4168 0.0000 0.0150 0.0000# c2-c2-na-c2 +28 0.1904 0.0000 -0.1342 0.0000 -0.2460 0.0000# hc-c2-na-c2 +29 -1.1506 0.0000 -0.6344 0.0000 -0.1845 0.0000# c2-c2-na-hn +30 -0.5187 0.0000 -0.4837 0.0000 -0.1692 0.0000# hc-c2-na-hn +31 0.3805 0.0000 0.3547 0.0000 -0.1102 0.0000# na-c2-c2-na +32 -0.2428 0.0000 0.4065 0.0000 -0.3079 0.0000# hc-c2-c2-na +33 -0.1432 0.0000 0.0617 0.0000 -0.1083 0.0000# hc-c2-c2-hc +34 0.7137 0.0000 0.2660 0.0000 -0.2545 0.0000# c3m-c3m-c2-oc +35 0.0000 0.0000 0.0316 0.0000 -0.1681 0.0000# c3m-c3m-c2-hc +36 -0.1820 0.0000 -0.1084 0.0000 -0.7047 0.0000# o3e-c3m-c2-oc +37 -0.1435 0.0000 0.2530 0.0000 -0.0905 0.0000# o3e-c3m-c2-hc +38 -0.1435 0.0000 0.2530 0.0000 -0.0905 0.0000# hc-c3m-c2-oc +39 -0.1432 0.0000 0.0617 0.0000 -0.1083 0.0000# hc-c3m-c2-hc +40 0.0000 0.0000 0.0316 0.0000 -0.1681 0.0000# hc-c2-c3-c2 +41 -0.1432 0.0000 0.0617 0.0000 -0.1083 0.0000# hc-c2-c3-hc +42 -0.1435 0.0000 0.2530 0.0000 -0.0905 0.0000# hc-c2-c3-oc +43 0.1764 0.0000 0.1766 0.0000 -0.5206 0.0000# na-c2-c3-c2 +44 -0.2428 0.0000 0.4065 0.0000 -0.3079 0.0000# na-c2-c3-hc +45 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000# na-c2-c3-oc +46 -0.1406 0.0000 0.4168 0.0000 0.0150 0.0000# c3-c2-na-c2 +47 -1.1506 0.0000 -0.6344 0.0000 -0.1845 0.0000# c3-c2-na-hn +48 0.7137 0.0000 0.2660 0.0000 -0.2545 0.0000# oc-c2-c3-c2 +49 -0.1435 0.0000 0.2530 0.0000 -0.0905 0.0000# oc-c2-c3-hc +50 -0.1820 0.0000 -0.1084 0.0000 -0.7047 0.0000# oc-c2-c3-oc +51 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000# c3-c2-oc-cp +52 -0.6732 0.0000 -0.4778 0.0000 -0.1670 0.0000# c2-c3-oc-ho +53 0.1863 0.0000 -0.4338 0.0000 -0.2121 0.0000# hc-c3-oc-ho +54 -0.1435 0.0000 0.2530 0.0000 -0.0905 0.0000# hc-c3m-c3m-o3e +55 0.0000 0.0000 0.0316 0.0000 -0.1681 0.0000# hc-c2-c3m-c2 +56 -0.1435 0.0000 0.2530 0.0000 -0.0905 0.0000# hc-c2-c3m-oc +57 0.1764 0.0000 0.1766 0.0000 -0.5206 0.0000# na-c2-c3m-c2 +58 -0.2428 0.0000 0.4065 0.0000 -0.3079 0.0000# na-c2-c3m-hc +59 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000# na-c2-c3m-oc +60 -0.1406 0.0000 0.4168 0.0000 0.0150 0.0000# c3m-c2-na-c2 +61 0.7137 0.0000 0.2660 0.0000 -0.2545 0.0000# oc-c2-c3m-c2 +62 -0.1820 0.0000 -0.1084 0.0000 -0.7047 0.0000# oc-c2-c3m-oc +63 -0.6732 0.0000 -0.4778 0.0000 -0.1670 0.0000# c2-c3m-oc-ho +64 0.1863 0.0000 -0.4338 0.0000 -0.2121 0.0000# hc-c3m-oc-ho +65 -0.6732 0.0000 -0.4778 0.0000 -0.1670 0.0000# ho-oc-c3-c2 +66 0.1863 0.0000 -0.4338 0.0000 -0.2121 0.0000# ho-oc-c3-hc + +Improper Coeffs # class2 + +1 13.0421 0.0000 # cp-cp-cp-oc +2 4.8912 0.0000 # cp-cp-cp-hc +3 7.8153 0.0000 # cp-cp-cp-c +4 0.0000 0.0000 # c2-na-c2-hn +5 0.0000 0.0000 # c2-na-hn-hn +6 0.0000 0.0000 +7 0.0000 0.0000 +8 0.0000 0.0000 +9 0.0000 0.0000 +10 0.0000 0.0000 +11 0.0000 0.0000 +12 0.0000 0.0000 +13 0.0000 0.0000 +14 0.0000 0.0000 +15 0.0000 0.0000 +16 0.0000 0.0000 +17 0.0000 0.0000 +18 0.0000 0.0000 +19 0.0000 0.0000 +20 0.0000 0.0000 +21 0.0000 0.0000 +22 0.0000 0.0000 # c2-na-c2-c2 + +BondBond Coeffs + +1 3.3872 1.5300 1.1010 +2 5.3316 1.1010 1.1010 +3 23.1979 1.4200 1.1010 +4 11.4318 1.5300 1.4200 +5 11.4318 1.5300 1.4200 +6 0.0000 1.5300 1.5300 +7 3.3872 1.5300 1.1010 +8 11.4318 1.5300 1.4200 +9 23.1979 1.4200 1.1010 +10 3.3872 1.5300 1.1010 +11 5.3316 1.1010 1.1010 +12 -7.1131 1.4200 1.4200 +13 68.2856 1.4170 1.4170 +14 48.4754 1.4170 1.3768 +15 1.0795 1.4170 1.0982 +16 12.0676 1.4170 1.5010 +17 0.0000 1.5010 1.5300 +18 0.0000 1.5010 1.5010 +19 0.0000 1.5300 1.5300 +20 3.3872 1.5300 1.1010 +21 5.3316 1.1010 1.1010 +22 0.0000 1.4200 1.3768 +23 -2.1113 1.4570 1.4570 +24 -6.4168 1.4570 1.0060 +25 4.6217 1.5300 1.4570 +26 12.4260 1.1010 1.4570 +27 3.3872 1.5300 1.1010 +28 -1.8749 1.0060 1.0060 +29 0.0000 1.5300 1.5300 +30 3.3872 1.5300 1.1010 +31 4.6217 1.5300 1.4570 +32 0.0000 1.5300 1.5300 +33 3.3872 1.5300 1.1010 +34 11.4318 1.5300 1.4200 +35 23.1979 1.4200 1.1010 +36 11.4318 1.5300 1.4200 +37 -9.6879 1.4200 0.9650 +38 23.1979 1.1010 1.4200 +39 3.3872 1.1010 1.5300 +40 11.4318 1.4200 1.5300 +41 3.3872 1.1010 1.5300 +42 4.6217 1.5300 1.4570 +43 0.0000 1.5300 1.5300 +44 11.4318 1.5300 1.4200 +45 23.1979 1.4200 1.1010 +46 -9.6879 1.4200 0.9650 +47 4.6217 1.4570 1.5300 +48 3.3872 1.1010 1.5300 +49 11.4318 1.4200 1.5300 +50 -9.6879 0.9650 1.4200 + +BondAngle Coeffs + +1 20.7540 11.4210 1.5300 1.1010 +2 18.1030 18.1030 1.1010 1.1010 +3 55.3270 4.6189 1.4200 1.1010 +4 2.6868 20.4033 1.5300 1.4200 +5 2.6868 20.4033 1.5300 1.4200 +6 8.0160 8.0160 1.5300 1.5300 +7 20.7540 11.4210 1.5300 1.1010 +8 2.6868 20.4033 1.5300 1.4200 +9 55.3270 4.6189 1.4200 1.1010 +10 20.7540 11.4210 1.5300 1.1010 +11 18.1030 18.1030 1.1010 1.1010 +12 -2.8112 -2.8112 1.4200 1.4200 +13 28.8708 28.8708 1.4170 1.4170 +14 58.4790 107.6806 1.4170 1.3768 +15 20.0033 24.2183 1.4170 1.0982 +16 31.0771 47.0579 1.4170 1.5010 +17 0.0000 0.0000 1.5010 1.5300 +18 0.0000 0.0000 1.5010 1.5010 +19 8.0160 8.0160 1.5300 1.5300 +20 20.7540 11.4210 1.5300 1.1010 +21 18.1030 18.1030 1.1010 1.1010 +22 0.0000 0.0000 1.4200 1.3768 +23 -7.2229 -7.2229 1.4570 1.4570 +24 31.8096 20.5799 1.4570 1.0060 +25 6.0876 16.5702 1.5300 1.4570 +26 13.4582 42.4332 1.1010 1.4570 +27 20.7540 11.4210 1.5300 1.1010 +28 28.0322 28.0322 1.0060 1.0060 +29 8.0160 8.0160 1.5300 1.5300 +30 20.7540 11.4210 1.5300 1.1010 +31 6.0876 16.5702 1.5300 1.4570 +32 8.0160 8.0160 1.5300 1.5300 +33 20.7540 11.4210 1.5300 1.1010 +34 2.6868 20.4033 1.5300 1.4200 +35 55.3270 4.6189 1.4200 1.1010 +36 2.6868 20.4033 1.5300 1.4200 +37 28.5800 18.9277 1.4200 0.9650 +38 4.6189 55.3270 1.1010 1.4200 +39 11.4210 20.7540 1.1010 1.5300 +40 20.4033 2.6868 1.4200 1.5300 +41 11.4210 20.7540 1.1010 1.5300 +42 6.0876 16.5702 1.5300 1.4570 +43 8.0160 8.0160 1.5300 1.5300 +44 2.6868 20.4033 1.5300 1.4200 +45 55.3270 4.6189 1.4200 1.1010 +46 28.5800 18.9277 1.4200 0.9650 +47 16.5702 6.0876 1.4570 1.5300 +48 11.4210 20.7540 1.1010 1.5300 +49 20.4033 2.6868 1.4200 1.5300 +50 18.9277 28.5800 0.9650 1.4200 + +AngleAngle Coeffs + +1 0.0000 0.0000 0.0000 118.9000 123.4200 123.4200 +2 0.0000 0.0000 0.0000 118.9000 117.9400 117.9400 +3 0.0000 0.0000 0.0000 118.9000 120.0500 120.0500 +4 0.0000 0.0000 0.0000 112.4436 110.9538 110.9538 +5 0.0000 0.0000 0.0000 110.9538 107.0671 110.9538 +6 0.2738 -0.4825 0.2738 110.7700 107.6600 110.7700 +7 0.1689 2.5926 3.9177 111.2700 108.7280 110.7700 +8 2.4259 2.1283 2.4259 108.7280 107.6600 108.7280 +9 -0.8330 -0.8330 -3.5744 112.6700 111.2700 111.2700 +10 0.1689 2.5926 3.9177 111.2700 108.7280 110.7700 +11 -1.3199 -1.3199 0.1184 112.6700 110.7700 110.7700 +12 0.1689 2.5926 3.9177 111.2700 108.7280 110.7700 +13 0.2738 -0.4825 0.2738 110.7700 107.6600 110.7700 +14 2.4259 2.1283 2.4259 108.7280 107.6600 108.7280 +15 0.0000 0.0000 0.0000 108.4000 112.6700 108.4000 +16 0.0000 0.0000 0.0000 111.0000 108.4000 108.4000 +17 0.2738 -0.4825 0.2738 110.7700 107.6600 110.7700 +18 -0.3157 -0.3157 -0.3157 107.6600 107.6600 107.6600 +19 2.4286 0.5381 -2.5301 110.7700 110.6204 111.9100 +20 2.4321 2.4321 -3.5496 107.6600 110.6204 110.6204 +21 0.2738 -0.4825 0.2738 110.7700 107.6600 110.7700 +22 0.0000 0.0000 0.0000 112.4436 112.4436 112.4436 + +AngleAngleTorsion Coeffs + +1 -20.2006 110.7700 111.2700 +2 -16.1640 110.7700 112.6700 +3 -12.5640 110.7700 110.7700 +4 -14.0484 111.2700 111.2700 +5 -29.0420 111.2700 112.6700 +6 -20.2006 111.2700 110.7700 +7 0.0000 108.7280 102.9695 +8 0.0000 111.2700 102.9695 +9 -19.0059 111.2700 104.5000 +10 -16.4438 108.7280 104.5000 +11 -29.0420 112.6700 111.2700 +12 -16.1640 112.6700 110.7700 +13 -20.2006 111.2700 110.7700 +14 -12.5640 110.7700 110.7700 +15 0.0000 118.9000 118.9000 +16 -4.8141 118.9000 117.9400 +17 -21.0247 118.9000 123.4200 +18 4.2296 123.4200 117.9400 +19 0.0000 123.4200 102.9695 +20 0.3598 117.9400 117.9400 +21 -14.4097 118.9000 120.0500 +22 4.4444 120.0500 117.9400 +23 0.0000 120.0500 108.4000 +24 0.0000 120.0500 111.0000 +25 0.0000 108.4000 110.7700 +26 -16.1640 112.6700 110.7700 +27 -24.3818 111.9100 112.4436 +28 -12.5567 110.6204 112.4436 +29 -7.5499 111.9100 110.9538 +30 -10.4258 110.6204 110.9538 +31 -11.2307 111.9100 111.9100 +32 -15.7572 110.7700 111.9100 +33 -12.5640 110.7700 110.7700 +34 -29.0420 112.6700 111.2700 +35 -16.1640 112.6700 110.7700 +36 -14.0484 111.2700 111.2700 +37 -20.2006 111.2700 110.7700 +38 -20.2006 110.7700 111.2700 +39 -12.5640 110.7700 110.7700 +40 -16.1640 110.7700 112.6700 +41 -12.5640 110.7700 110.7700 +42 -20.2006 110.7700 111.2700 +43 -27.3953 111.9100 112.6700 +44 -15.7572 111.9100 110.7700 +45 0.0000 111.9100 111.2700 +46 -24.3818 111.9100 112.4436 +47 -7.5499 111.9100 110.9538 +48 -29.0420 111.2700 112.6700 +49 -20.2006 111.2700 110.7700 +50 -14.0484 111.2700 111.2700 +51 0.0000 111.2700 102.9695 +52 -12.1038 111.2700 105.8000 +53 -10.5093 108.7280 105.8000 +54 -20.2006 110.7700 111.2700 +55 -16.1640 110.7700 112.6700 +56 -20.2006 110.7700 111.2700 +57 -27.3953 111.9100 112.6700 +58 -15.7572 111.9100 110.7700 +59 0.0000 111.9100 111.2700 +60 -24.3818 111.9100 112.4436 +61 -29.0420 111.2700 112.6700 +62 -14.0484 111.2700 111.2700 +63 -12.1038 111.2700 105.8000 +64 -10.5093 108.7280 105.8000 +65 -12.1038 105.8000 111.2700 +66 -10.5093 105.8000 108.7280 + +EndBondTorsion Coeffs + +1 0.9681 0.9551 0.0436 0.5903 0.6669 0.8584 1.1010 1.4200 +2 0.0814 0.0591 0.2219 0.2486 0.2422 -0.0925 1.1010 1.5300 +3 0.2130 0.3120 0.0777 0.2130 0.3120 0.0777 1.1010 1.1010 +4 1.0165 0.7553 -0.4609 1.0165 0.7553 -0.4609 1.4200 1.4200 +5 1.1538 0.8409 -0.9138 -0.3190 0.4411 -0.7174 1.4200 1.5300 +6 0.5903 0.6669 0.8584 0.9681 0.9551 0.0436 1.4200 1.1010 +7 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 1.1010 1.3768 +8 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 1.5300 1.3768 +9 -0.2456 1.0517 -0.7795 0.4741 1.2635 0.5576 1.5300 1.4200 +10 -0.6054 1.3339 0.9648 -0.1620 0.1564 -1.1408 1.1010 1.4200 +11 -0.3190 0.4411 -0.7174 1.1538 0.8409 -0.9138 1.5300 1.4200 +12 0.2486 0.2422 -0.0925 0.0814 0.0591 0.2219 1.5300 1.1010 +13 0.5903 0.6669 0.8584 0.9681 0.9551 0.0436 1.4200 1.1010 +14 0.2130 0.3120 0.0777 0.2130 0.3120 0.0777 1.1010 1.1010 +15 -0.1185 6.3204 0.0000 -0.1185 6.3204 0.0000 1.4170 1.4170 +16 0.0000 -6.8958 0.0000 0.0000 -0.4669 0.0000 1.4170 1.0982 +17 0.0000 0.2655 0.0000 0.0000 4.8905 0.0000 1.4170 1.3768 +18 0.0000 4.2641 0.0000 0.0000 -1.5867 0.0000 1.3768 1.0982 +19 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 1.4170 1.4200 +20 0.0000 -0.6890 0.0000 0.0000 -0.6890 0.0000 1.0982 1.0982 +21 0.0000 -0.6918 0.0000 0.0000 0.2421 0.0000 1.4170 1.5010 +22 0.0000 -1.7970 0.0000 0.0000 -0.4879 0.0000 1.5010 1.0982 +23 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 1.4170 1.5300 +24 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 1.4170 1.5010 +25 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 1.5010 1.1010 +26 0.2486 0.2422 -0.0925 0.0814 0.0591 0.2219 1.5300 1.1010 +27 0.0997 -0.0046 -0.2657 -0.0128 -0.0495 -0.1079 1.5300 1.4570 +28 -0.5892 0.7140 0.3505 0.0628 0.0873 -0.0882 1.1010 1.4570 +29 -0.9466 0.9356 -0.5542 0.0570 0.0625 0.4112 1.5300 1.0060 +30 -1.1685 0.9266 -0.0993 0.0850 0.3061 0.2104 1.1010 1.0060 +31 0.0286 0.0566 -0.0493 0.0286 0.0566 -0.0493 1.4570 1.4570 +32 0.1960 0.7056 0.1120 0.1022 0.2090 0.6433 1.1010 1.4570 +33 0.2130 0.3120 0.0777 0.2130 0.3120 0.0777 1.1010 1.1010 +34 -0.3190 0.4411 -0.7174 1.1538 0.8409 -0.9138 1.5300 1.4200 +35 0.2486 0.2422 -0.0925 0.0814 0.0591 0.2219 1.5300 1.1010 +36 1.0165 0.7553 -0.4609 1.0165 0.7553 -0.4609 1.4200 1.4200 +37 0.5903 0.6669 0.8584 0.9681 0.9551 0.0436 1.4200 1.1010 +38 0.9681 0.9551 0.0436 0.5903 0.6669 0.8584 1.1010 1.4200 +39 0.2130 0.3120 0.0777 0.2130 0.3120 0.0777 1.1010 1.1010 +40 0.0814 0.0591 0.2219 0.2486 0.2422 -0.0925 1.1010 1.5300 +41 0.2130 0.3120 0.0777 0.2130 0.3120 0.0777 1.1010 1.1010 +42 0.9681 0.9551 0.0436 0.5903 0.6669 0.8584 1.1010 1.4200 +43 0.0579 -0.0043 -0.1906 0.1032 0.5896 -0.4836 1.4570 1.5300 +44 0.1022 0.2090 0.6433 0.1960 0.7056 0.1120 1.4570 1.1010 +45 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 1.4570 1.4200 +46 0.0997 -0.0046 -0.2657 -0.0128 -0.0495 -0.1079 1.5300 1.4570 +47 -0.9466 0.9356 -0.5542 0.0570 0.0625 0.4112 1.5300 1.0060 +48 1.1538 0.8409 -0.9138 -0.3190 0.4411 -0.7174 1.4200 1.5300 +49 0.5903 0.6669 0.8584 0.9681 0.9551 0.0436 1.4200 1.1010 +50 1.0165 0.7553 -0.4609 1.0165 0.7553 -0.4609 1.4200 1.4200 +51 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 1.5300 1.3768 +52 -0.5800 0.9004 0.0000 0.0000 0.5343 0.9025 1.5300 0.9650 +53 -1.7554 1.3145 0.2263 0.2493 0.6803 0.0000 1.1010 0.9650 +54 0.9681 0.9551 0.0436 0.5903 0.6669 0.8584 1.1010 1.4200 +55 0.0814 0.0591 0.2219 0.2486 0.2422 -0.0925 1.1010 1.5300 +56 0.9681 0.9551 0.0436 0.5903 0.6669 0.8584 1.1010 1.4200 +57 0.0579 -0.0043 -0.1906 0.1032 0.5896 -0.4836 1.4570 1.5300 +58 0.1022 0.2090 0.6433 0.1960 0.7056 0.1120 1.4570 1.1010 +59 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 1.4570 1.4200 +60 0.0997 -0.0046 -0.2657 -0.0128 -0.0495 -0.1079 1.5300 1.4570 +61 1.1538 0.8409 -0.9138 -0.3190 0.4411 -0.7174 1.4200 1.5300 +62 1.0165 0.7553 -0.4609 1.0165 0.7553 -0.4609 1.4200 1.4200 +63 -0.5800 0.9004 0.0000 0.0000 0.5343 0.9025 1.5300 0.9650 +64 -1.7554 1.3145 0.2263 0.2493 0.6803 0.0000 1.1010 0.9650 +65 0.0000 0.5343 0.9025 -0.5800 0.9004 0.0000 0.9650 1.5300 +66 0.2493 0.6803 0.0000 -1.7554 1.3145 0.2263 0.9650 1.1010 + +MiddleBondTorsion Coeffs + +1 -16.7975 -1.2296 -0.2750 1.5300 +2 -14.8790 -3.6581 -0.3138 1.5300 +3 -14.2610 -0.5322 -0.4864 1.5300 +4 -17.2585 -3.6157 -0.8364 1.5300 +5 -21.8842 -7.6764 -0.6868 1.5300 +6 -16.7975 -1.2296 -0.2750 1.5300 +7 0.0000 0.0000 0.0000 1.4200 +8 0.0000 0.0000 0.0000 1.4200 +9 -5.9288 -2.7007 -0.3175 1.4200 +10 -6.8007 -4.6546 -1.4101 1.4200 +11 -21.8842 -7.6764 -0.6868 1.5300 +12 -14.8790 -3.6581 -0.3138 1.5300 +13 -16.7975 -1.2296 -0.2750 1.5300 +14 -14.2610 -0.5322 -0.4864 1.5300 +15 27.5989 -2.3120 0.0000 1.4170 +16 0.0000 -1.1521 0.0000 1.4170 +17 0.0000 4.8255 0.0000 1.4170 +18 0.0000 5.5432 0.0000 1.4170 +19 0.0000 0.0000 0.0000 1.3768 +20 0.0000 4.8228 0.0000 1.4170 +21 0.0000 9.1792 0.0000 1.4170 +22 0.0000 3.9421 0.0000 1.4170 +23 0.0000 0.0000 0.0000 1.5010 +24 0.0000 0.0000 0.0000 1.5010 +25 0.0000 0.0000 0.0000 1.5300 +26 -14.8790 -3.6581 -0.3138 1.5300 +27 -8.0036 -7.7321 -3.0640 1.4570 +28 -6.4529 -6.8122 -1.1632 1.4570 +29 -2.2208 0.5479 -0.3527 1.4570 +30 -3.4611 1.6996 -0.6007 1.4570 +31 -3.3497 1.0143 -3.0062 1.5300 +32 -10.4959 -0.7647 -0.0545 1.5300 +33 -14.2610 -0.5322 -0.4864 1.5300 +34 -21.8842 -7.6764 -0.6868 1.5300 +35 -14.8790 -3.6581 -0.3138 1.5300 +36 -17.2585 -3.6157 -0.8364 1.5300 +37 -16.7975 -1.2296 -0.2750 1.5300 +38 -16.7975 -1.2296 -0.2750 1.5300 +39 -14.2610 -0.5322 -0.4864 1.5300 +40 -14.8790 -3.6581 -0.3138 1.5300 +41 -14.2610 -0.5322 -0.4864 1.5300 +42 -16.7975 -1.2296 -0.2750 1.5300 +43 -15.4174 -7.3055 -1.0749 1.5300 +44 -10.4959 -0.7647 -0.0545 1.5300 +45 0.0000 0.0000 0.0000 1.5300 +46 -8.0036 -7.7321 -3.0640 1.4570 +47 -2.2208 0.5479 -0.3527 1.4570 +48 -21.8842 -7.6764 -0.6868 1.5300 +49 -16.7975 -1.2296 -0.2750 1.5300 +50 -17.2585 -3.6157 -0.8364 1.5300 +51 0.0000 0.0000 0.0000 1.4200 +52 1.2472 0.0000 0.7485 1.4200 +53 0.0000 0.9241 -0.5889 1.4200 +54 -16.7975 -1.2296 -0.2750 1.5300 +55 -14.8790 -3.6581 -0.3138 1.5300 +56 -16.7975 -1.2296 -0.2750 1.5300 +57 -15.4174 -7.3055 -1.0749 1.5300 +58 -10.4959 -0.7647 -0.0545 1.5300 +59 0.0000 0.0000 0.0000 1.5300 +60 -8.0036 -7.7321 -3.0640 1.4570 +61 -21.8842 -7.6764 -0.6868 1.5300 +62 -17.2585 -3.6157 -0.8364 1.5300 +63 1.2472 0.0000 0.7485 1.4200 +64 0.0000 0.9241 -0.5889 1.4200 +65 1.2472 0.0000 0.7485 1.4200 +66 0.0000 0.9241 -0.5889 1.4200 + +BondBond13 Coeffs + +1 0.0000 1.1010 1.4200 +2 0.0000 1.1010 1.5300 +3 0.0000 1.1010 1.1010 +4 0.0000 1.4200 1.4200 +5 0.0000 1.4200 1.5300 +6 0.0000 1.4200 1.1010 +7 0.0000 1.1010 1.3768 +8 0.0000 1.5300 1.3768 +9 0.0000 1.5300 1.4200 +10 0.0000 1.1010 1.4200 +11 0.0000 1.5300 1.4200 +12 0.0000 1.5300 1.1010 +13 0.0000 1.4200 1.1010 +14 0.0000 1.1010 1.1010 +15 53.0000 1.4170 1.4170 +16 -6.2741 1.4170 1.0982 +17 -2.2436 1.4170 1.3768 +18 2.0517 1.3768 1.0982 +19 0.0000 1.4170 1.4200 +20 -1.7077 1.0982 1.0982 +21 2.5085 1.4170 1.5010 +22 0.8743 1.5010 1.0982 +23 0.0000 1.4170 1.5300 +24 0.0000 1.4170 1.5010 +25 0.0000 1.5010 1.1010 +26 0.0000 1.5300 1.1010 +27 0.0000 1.5300 1.4570 +28 0.0000 1.1010 1.4570 +29 0.0000 1.5300 1.0060 +30 0.0000 1.1010 1.0060 +31 0.0000 1.4570 1.4570 +32 0.0000 1.1010 1.4570 +33 0.0000 1.1010 1.1010 +34 0.0000 1.5300 1.4200 +35 0.0000 1.5300 1.1010 +36 0.0000 1.4200 1.4200 +37 0.0000 1.4200 1.1010 +38 0.0000 1.1010 1.4200 +39 0.0000 1.1010 1.1010 +40 0.0000 1.1010 1.5300 +41 0.0000 1.1010 1.1010 +42 0.0000 1.1010 1.4200 +43 0.0000 1.4570 1.5300 +44 0.0000 1.4570 1.1010 +45 0.0000 1.4570 1.4200 +46 0.0000 1.5300 1.4570 +47 0.0000 1.5300 1.0060 +48 0.0000 1.4200 1.5300 +49 0.0000 1.4200 1.1010 +50 0.0000 1.4200 1.4200 +51 0.0000 1.5300 1.3768 +52 0.0000 1.5300 0.9650 +53 0.0000 1.1010 0.9650 +54 0.0000 1.1010 1.4200 +55 0.0000 1.1010 1.5300 +56 0.0000 1.1010 1.4200 +57 0.0000 1.4570 1.5300 +58 0.0000 1.4570 1.1010 +59 0.0000 1.4570 1.4200 +60 0.0000 1.5300 1.4570 +61 0.0000 1.4200 1.5300 +62 0.0000 1.4200 1.4200 +63 0.0000 1.5300 0.9650 +64 0.0000 1.1010 0.9650 +65 0.0000 0.9650 1.5300 +66 0.0000 0.9650 1.1010 + +AngleTorsion Coeffs + +1 2.3668 2.4920 -1.0122 -0.1892 0.4918 0.7273 110.7700 111.2700 +2 0.3113 0.4516 -0.1988 -0.2454 0.0000 -0.1136 110.7700 112.6700 +3 -0.8085 0.5569 -0.2466 -0.8085 0.5569 -0.2466 110.7700 110.7700 +4 0.5511 0.9737 -0.6673 0.5511 0.9737 -0.6673 111.2700 111.2700 +5 0.9672 -0.7566 -1.2331 0.5623 -0.3041 -0.4015 111.2700 112.6700 +6 -0.1892 0.4918 0.7273 2.3668 2.4920 -1.0122 111.2700 110.7700 +7 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 108.7280 102.9695 +8 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 111.2700 102.9695 +9 -2.7466 1.4877 -0.8955 0.5676 0.9450 0.0703 111.2700 104.5000 +10 -1.8234 1.6393 0.5144 -0.7777 0.4340 -0.6653 108.7280 104.5000 +11 0.5623 -0.3041 -0.4015 0.9672 -0.7566 -1.2331 112.6700 111.2700 +12 -0.2454 0.0000 -0.1136 0.3113 0.4516 -0.1988 112.6700 110.7700 +13 -0.1892 0.4918 0.7273 2.3668 2.4920 -1.0122 111.2700 110.7700 +14 -0.8085 0.5569 -0.2466 -0.8085 0.5569 -0.2466 110.7700 110.7700 +15 1.9767 1.0239 0.0000 1.9767 1.0239 0.0000 118.9000 118.9000 +16 0.0000 2.5014 0.0000 0.0000 2.7147 0.0000 118.9000 117.9400 +17 0.0000 10.0155 0.0000 0.0000 1.7404 0.0000 118.9000 123.4200 +18 0.0000 2.5706 0.0000 0.0000 1.8729 0.0000 123.4200 117.9400 +19 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 123.4200 102.9695 +20 0.0000 2.4501 0.0000 0.0000 2.4501 0.0000 117.9400 117.9400 +21 0.0000 3.8987 0.0000 0.0000 -4.4683 0.0000 118.9000 120.0500 +22 0.0000 -0.1242 0.0000 0.0000 3.4601 0.0000 120.0500 117.9400 +23 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 120.0500 108.4000 +24 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 120.0500 111.0000 +25 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 108.4000 110.7700 +26 -0.2454 0.0000 -0.1136 0.3113 0.4516 -0.1988 112.6700 110.7700 +27 -2.7883 1.5193 1.4796 1.2031 1.3645 -0.7071 111.9100 112.4436 +28 -2.6321 0.9353 -0.8398 -1.3582 0.1465 -0.5729 110.6204 112.4436 +29 -3.3430 4.4558 -0.0346 0.2873 -0.8072 -0.0960 111.9100 110.9538 +30 -3.9582 2.0063 0.3213 -0.4294 -0.4442 -0.6141 110.6204 110.9538 +31 1.3673 0.4528 -2.7700 1.3673 0.4528 -2.7700 111.9100 111.9100 +32 0.5111 1.6328 -1.0155 -1.1075 0.2820 0.8318 110.7700 111.9100 +33 -0.8085 0.5569 -0.2466 -0.8085 0.5569 -0.2466 110.7700 110.7700 +34 0.5623 -0.3041 -0.4015 0.9672 -0.7566 -1.2331 112.6700 111.2700 +35 -0.2454 0.0000 -0.1136 0.3113 0.4516 -0.1988 112.6700 110.7700 +36 0.5511 0.9737 -0.6673 0.5511 0.9737 -0.6673 111.2700 111.2700 +37 -0.1892 0.4918 0.7273 2.3668 2.4920 -1.0122 111.2700 110.7700 +38 2.3668 2.4920 -1.0122 -0.1892 0.4918 0.7273 110.7700 111.2700 +39 -0.8085 0.5569 -0.2466 -0.8085 0.5569 -0.2466 110.7700 110.7700 +40 0.3113 0.4516 -0.1988 -0.2454 0.0000 -0.1136 110.7700 112.6700 +41 -0.8085 0.5569 -0.2466 -0.8085 0.5569 -0.2466 110.7700 110.7700 +42 2.3668 2.4920 -1.0122 -0.1892 0.4918 0.7273 110.7700 111.2700 +43 2.0125 0.9440 -2.7612 -1.9225 -1.3450 0.2210 111.9100 112.6700 +44 -1.1075 0.2820 0.8318 0.5111 1.6328 -1.0155 111.9100 110.7700 +45 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 111.9100 111.2700 +46 -2.7883 1.5193 1.4796 1.2031 1.3645 -0.7071 111.9100 112.4436 +47 -3.3430 4.4558 -0.0346 0.2873 -0.8072 -0.0960 111.9100 110.9538 +48 0.9672 -0.7566 -1.2331 0.5623 -0.3041 -0.4015 111.2700 112.6700 +49 -0.1892 0.4918 0.7273 2.3668 2.4920 -1.0122 111.2700 110.7700 +50 0.5511 0.9737 -0.6673 0.5511 0.9737 -0.6673 111.2700 111.2700 +51 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 111.2700 102.9695 +52 -3.5903 2.5225 0.4888 0.8726 -0.3577 0.3888 111.2700 105.8000 +53 -3.4060 1.6396 0.0737 0.0000 -0.2810 -0.5944 108.7280 105.8000 +54 2.3668 2.4920 -1.0122 -0.1892 0.4918 0.7273 110.7700 111.2700 +55 0.3113 0.4516 -0.1988 -0.2454 0.0000 -0.1136 110.7700 112.6700 +56 2.3668 2.4920 -1.0122 -0.1892 0.4918 0.7273 110.7700 111.2700 +57 2.0125 0.9440 -2.7612 -1.9225 -1.3450 0.2210 111.9100 112.6700 +58 -1.1075 0.2820 0.8318 0.5111 1.6328 -1.0155 111.9100 110.7700 +59 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 111.9100 111.2700 +60 -2.7883 1.5193 1.4796 1.2031 1.3645 -0.7071 111.9100 112.4436 +61 0.9672 -0.7566 -1.2331 0.5623 -0.3041 -0.4015 111.2700 112.6700 +62 0.5511 0.9737 -0.6673 0.5511 0.9737 -0.6673 111.2700 111.2700 +63 -3.5903 2.5225 0.4888 0.8726 -0.3577 0.3888 111.2700 105.8000 +64 -3.4060 1.6396 0.0737 0.0000 -0.2810 -0.5944 108.7280 105.8000 +65 0.8726 -0.3577 0.3888 -3.5903 2.5225 0.4888 105.8000 111.2700 +66 0.0000 -0.2810 -0.5944 -3.4060 1.6396 0.0737 105.8000 108.7280 + +Atoms # full + +1 1 1 0.000000 25.246496201 -1.871744037 -8.651348114 0 0 0 # c2 +2 1 2 0.000000 25.610639572 -3.288228035 -8.165973663 0 0 0 # c3m +3 1 2 0.000000 24.731319427 -4.483242989 -8.675741196 0 0 0 # c3m +4 1 2 0.000000 18.703355789 9.118826866 -4.174236774 0 0 0 # c3m +5 1 2 0.000000 18.099748611 8.263649940 -5.343001842 0 0 0 # c3m +6 1 1 0.000000 19.081827164 7.609607220 -6.334177017 0 0 0 # c2 +7 1 3 0.100000 26.190139771 -4.295329094 -9.220970154 0 0 0 # o3e +8 1 3 0.100000 17.971729279 9.827675819 -5.367077827 0 0 0 # o3e +9 1 4 0.000000 20.263877869 5.733595848 -6.736782074 0 0 0 # cp +10 1 4 0.000000 19.777191162 4.983679771 -7.809411049 0 0 0 # cp +11 1 4 0.000000 20.667026520 4.390971184 -8.707633972 0 0 0 # cp +12 1 4 0.000000 22.043539047 4.548151016 -8.533248901 0 0 0 # cp +13 1 4 0.000000 22.530214310 5.298062801 -7.460619926 0 0 0 # cp +14 1 4 0.000000 21.640394211 5.890783787 -6.562390804 0 0 0 # cp +15 1 5 0.000000 23.005182266 3.906831026 -9.503917694 0 0 0 # c +16 1 6 0.000000 24.286390305 4.758069992 -9.590908051 0 0 0 # c3 +17 1 6 0.000000 22.342786789 3.812531948 -10.891778946 0 0 0 # c3 +18 1 4 0.000000 23.361906052 2.519830942 -9.029184341 0 0 0 # cp +19 1 4 0.000000 24.458705902 2.330889940 -8.185920715 0 0 0 # cp +20 1 4 0.000000 24.788816452 1.047963977 -7.745534897 0 0 0 # cp +21 1 4 0.000000 24.022008896 -0.046867002 -8.149927139 0 0 0 # cp +22 1 4 0.000000 22.925630569 0.140873000 -8.992565155 0 0 0 # cp +23 1 4 0.000000 22.595729828 1.424777985 -9.432847977 0 0 0 # cp +24 1 7 0.000000 19.414030075 6.299984932 -5.878956795 0 0 0 # oc +25 1 7 0.000000 24.338140488 -1.273216963 -7.729548931 0 0 0 # oc +26 1 8 0.000000 26.150024414 -1.266484976 -8.715751648 0 0 0 # hc +27 1 8 0.000000 24.778566360 -1.933199048 -9.633987427 0 0 0 # hc +28 1 8 0.000000 25.929294586 -2.927781105 -7.187973022 0 0 0 # hc +29 1 8 0.000000 24.549385071 -5.308847904 -7.987242222 0 0 0 # hc +30 1 8 0.000000 23.904827118 -4.254271030 -9.348136902 0 0 0 # hc +31 1 8 0.000000 18.194736481 9.091637611 -3.210949898 0 0 0 # hc +32 1 8 0.000000 19.788938522 9.208558083 -4.119643211 0 0 0 # hc +33 1 8 0.000000 17.399309158 7.432216167 -5.407801151 0 0 0 # hc +34 1 8 0.000000 18.616250992 7.545570850 -7.316913128 0 0 0 # hc +35 1 8 0.000000 19.987047195 8.212498665 -6.399401188 0 0 0 # hc +36 1 8 0.000000 18.713207245 4.862418175 -7.944396973 0 0 0 # hc +37 1 8 0.000000 20.290582657 3.811013937 -9.537291527 0 0 0 # hc +38 1 8 0.000000 23.594188690 5.419342995 -7.325634956 0 0 0 # hc +39 1 8 0.000000 22.016828537 6.470753193 -5.732734203 0 0 0 # hc +40 1 8 0.000000 24.982324600 4.297049999 -10.290958405 0 0 0 # hc +41 1 8 0.000000 24.034254074 5.760886192 -9.936174393 0 0 0 # hc +42 1 8 0.000000 24.749143600 4.819462776 -8.606439590 0 0 0 # hc +43 1 8 0.000000 23.034755707 3.349560976 -11.594371796 0 0 0 # hc +44 1 8 0.000000 21.438467026 3.207982063 -10.822364807 0 0 0 # hc +45 1 8 0.000000 22.084871292 4.811752796 -11.239845276 0 0 0 # hc +46 1 8 0.000000 25.050769806 3.177418947 -7.873311996 0 0 0 # hc +47 1 8 0.000000 25.636974335 0.901705027 -7.093626022 0 0 0 # hc +48 1 8 0.000000 22.333581924 -0.705653012 -9.305183411 0 0 0 # hc +49 1 8 0.000000 21.747369766 1.570054054 -10.084861755 0 0 0 # hc +50 1 1 0.000000 25.222612381 -4.200571060 0.463562995 0 0 0 # c2 +51 1 2 0.000000 25.832977295 -5.360119820 -0.347983003 0 0 0 # c3m +52 1 2 0.000000 27.389345169 -5.551681042 -0.290704012 0 0 0 # c3m +53 1 2 0.000000 20.635538101 8.396902084 -1.535487056 0 0 0 # c3m +54 1 2 0.000000 21.957460403 8.158697128 -0.723941982 0 0 0 # c3m +55 1 1 0.000000 22.041673660 6.895174980 0.154822007 0 0 0 # c2 +56 1 3 0.100000 26.447082520 -6.565405846 0.448491007 0 0 0 # o3e +57 1 3 0.100000 20.959102631 9.287891388 -0.285212994 0 0 0 # o3e +58 1 4 0.000000 22.680345535 4.733430862 0.158248007 0 0 0 # cp +59 1 4 0.000000 23.824728012 4.488029957 0.920358002 0 0 0 # cp +60 1 4 0.000000 23.901163101 3.343113899 1.716701984 0 0 0 # cp +61 1 4 0.000000 22.833225250 2.443607092 1.750934958 0 0 0 # cp +62 1 4 0.000000 21.688846588 2.689002037 0.988831997 0 0 0 # cp +63 1 4 0.000000 21.612403870 3.833913088 0.192488998 0 0 0 # cp +64 1 5 0.000000 22.916360855 1.205785036 2.611289978 0 0 0 # c +65 1 6 0.000000 21.501018524 0.810333014 3.075165987 0 0 0 # c3 +66 1 6 0.000000 23.808341980 1.493147969 3.834667921 0 0 0 # c3 +67 1 4 0.000000 23.514062881 0.070205003 1.817157984 0 0 0 # cp +68 1 4 0.000000 22.684833527 -0.782863975 1.085504055 0 0 0 # cp +69 1 4 0.000000 23.237234116 -1.833225965 0.349765003 0 0 0 # cp +70 1 4 0.000000 24.619955063 -2.031138897 0.346872985 0 0 0 # cp +71 1 4 0.000000 25.449554443 -1.179108977 1.077638030 0 0 0 # cp +72 1 4 0.000000 24.896312714 -0.128257006 1.813575983 0 0 0 # cp +73 1 7 0.000000 22.607131958 5.827101231 -0.602173984 0 0 0 # oc +74 1 7 0.000000 25.147769928 -3.035661936 -0.355791986 0 0 0 # oc +75 1 8 0.000000 24.221906662 -4.476489067 0.794990003 0 0 0 # hc +76 1 8 0.000000 25.849754333 -3.994390965 1.331357956 0 0 0 # hc +77 1 8 0.000000 25.097463608 -5.257826805 -1.146129966 0 0 0 # hc +78 1 8 0.000000 27.892013550 -5.893630028 -1.196079969 0 0 0 # hc +79 1 8 0.000000 27.964216232 -4.855231762 0.319745004 0 0 0 # hc +80 1 8 0.000000 20.720872879 8.854673386 -2.520912886 0 0 0 # hc +81 1 8 0.000000 19.840383530 7.656352043 -1.438712001 0 0 0 # hc +82 1 8 0.000000 23.017726898 8.120765686 -0.970986009 0 0 0 # hc +83 1 8 0.000000 22.669095993 7.097908974 1.022259951 0 0 0 # hc +84 1 8 0.000000 21.041725159 6.616360188 0.486577004 0 0 0 # hc +85 1 8 0.000000 24.650087357 5.183434963 0.894133985 0 0 0 # hc +86 1 8 0.000000 24.786277771 3.153367996 2.306194067 0 0 0 # hc +87 1 8 0.000000 20.863473892 1.993592978 1.015051961 0 0 0 # hc +88 1 8 0.000000 20.727291107 4.023673058 -0.397009999 0 0 0 # hc +89 1 8 0.000000 21.558345795 -0.083162002 3.696341038 0 0 0 # hc +90 1 8 0.000000 21.065618515 1.626867056 3.651936054 0 0 0 # hc +91 1 8 0.000000 20.876825333 0.608124971 2.205033064 0 0 0 # hc +92 1 8 0.000000 23.870355606 0.601037025 4.457283974 0 0 0 # hc +93 1 8 0.000000 24.807676315 1.770614982 3.498578072 0 0 0 # hc +94 1 8 0.000000 23.380037308 2.311306953 4.412462234 0 0 0 # hc +95 1 8 0.000000 21.616291046 -0.629218996 1.087699056 0 0 0 # hc +96 1 8 0.000000 22.596149445 -2.493021011 -0.215893999 0 0 0 # hc +97 1 8 0.000000 26.518102646 -1.332759023 1.075448036 0 0 0 # hc +98 1 8 0.000000 25.538236618 0.531040013 2.379035950 0 0 0 # hc +99 1 9 0.000000 16.072591782 12.338866234 -0.174325004 0 0 0 # na +100 1 1 0.000000 16.557256699 11.130316734 0.587288976 0 0 0 # c2 +101 1 1 0.000000 18.074571609 10.998808861 0.366084993 0 0 0 # c2 +102 1 9 -0.025000 18.353967667 10.832372665 -1.107717037 0 0 0 # na +103 1 9 -0.025000 14.920715332 15.017822266 -0.200534001 0 0 0 # na +104 1 1 0.000000 16.390434265 14.791102409 -0.460442007 0 0 0 # c2 +105 1 1 0.000000 16.852983475 13.538317680 0.304865986 0 0 0 # c2 +106 1 10 0.000000 16.263746262 12.190562248 -1.257431984 0 0 0 # hn +107 1 8 0.000000 16.025363922 10.195071220 0.210473999 0 0 0 # hc +108 1 8 0.000000 16.347120285 11.269214630 1.698830962 0 0 0 # hc +109 1 8 0.000000 18.467184067 10.092565536 0.934801996 0 0 0 # hc +110 1 8 0.000000 18.592388153 11.941304207 0.744638979 0 0 0 # hc +111 1 10 0.000000 17.843862534 9.919928551 -1.479779005 0 0 0 # hn +112 1 10 0.000000 19.448190689 10.736482620 -1.267521024 0 0 0 # hn +113 1 10 0.000000 14.344121933 14.136246681 -0.550131977 0 0 0 # hn +114 1 10 0.000000 14.583471298 15.922760963 -0.747138977 0 0 0 # hn +115 1 8 0.000000 16.984062195 15.696007729 -0.102596000 0 0 0 # hc +116 1 8 0.000000 16.562423706 14.639820099 -1.577000022 0 0 0 # hc +117 1 8 0.000000 16.674821854 13.685671806 1.420761943 0 0 0 # hc +118 1 8 0.000000 17.963953018 13.362975121 0.117853999 0 0 0 # hc + +Bonds + +1 1 1 26 +2 2 1 2 +3 1 1 27 +4 3 1 25 +5 4 2 7 +6 5 2 3 +7 6 2 28 +8 4 3 7 +9 6 3 29 +10 6 3 30 +11 6 4 32 +12 4 4 8 +13 5 4 5 +14 6 4 31 +15 4 5 8 +16 2 6 5 +17 6 5 33 +18 3 6 24 +19 1 6 34 +20 1 6 35 +21 7 9 14 +22 7 9 10 +23 8 9 24 +24 7 10 11 +25 9 10 36 +26 7 11 12 +27 9 11 37 +28 7 12 13 +29 10 12 15 +30 7 13 14 +31 9 13 38 +32 9 14 39 +33 11 15 16 +34 11 15 17 +35 10 18 15 +36 12 16 40 +37 12 16 41 +38 12 16 42 +39 12 17 43 +40 12 17 44 +41 12 17 45 +42 7 18 23 +43 7 18 19 +44 7 19 20 +45 9 19 46 +46 7 20 21 +47 9 20 47 +48 7 21 22 +49 8 21 25 +50 7 22 23 +51 9 22 48 +52 9 23 49 +53 1 50 75 +54 2 50 51 +55 1 50 76 +56 3 50 74 +57 4 51 56 +58 5 51 52 +59 6 51 77 +60 4 52 56 +61 6 52 78 +62 6 52 79 +63 6 53 81 +64 4 53 57 +65 5 53 54 +66 6 53 80 +67 4 54 57 +68 2 55 54 +69 6 54 82 +70 3 55 73 +71 1 55 83 +72 1 55 84 +73 7 58 63 +74 7 58 59 +75 8 58 73 +76 7 59 60 +77 9 59 85 +78 7 60 61 +79 9 60 86 +80 7 61 62 +81 10 61 64 +82 7 62 63 +83 9 62 87 +84 9 63 88 +85 11 64 65 +86 11 64 66 +87 10 67 64 +88 12 65 89 +89 12 65 90 +90 12 65 91 +91 12 66 92 +92 12 66 93 +93 12 66 94 +94 7 67 72 +95 7 67 68 +96 7 68 69 +97 9 68 95 +98 7 69 70 +99 9 69 96 +100 7 70 71 +101 8 70 74 +102 7 71 72 +103 9 71 97 +104 9 72 98 +105 13 100 99 +106 13 105 99 +107 14 99 106 +108 15 100 101 +109 1 100 107 +110 1 100 108 +111 13 101 102 +112 1 101 109 +113 1 101 110 +114 14 102 111 +115 14 102 112 +116 13 104 103 +117 14 103 113 +118 14 103 114 +119 15 104 105 +120 1 104 115 +121 1 104 116 +122 1 105 117 +123 1 105 118 + +Angles + +1 1 2 1 26 +2 2 26 1 27 +3 3 25 1 26 +4 1 2 1 27 +5 4 2 1 25 +6 3 25 1 27 +7 5 1 2 7 +8 6 1 2 3 +9 7 1 2 28 +10 8 3 2 7 +11 9 7 2 28 +12 10 3 2 28 +13 8 2 3 7 +14 10 2 3 29 +15 10 2 3 30 +16 9 7 3 29 +17 9 7 3 30 +18 11 29 3 30 +19 9 8 4 32 +20 10 5 4 32 +21 11 32 4 31 +22 8 5 4 8 +23 9 8 4 31 +24 10 5 4 31 +25 8 4 5 8 +26 6 6 5 4 +27 10 4 5 33 +28 5 6 5 8 +29 9 8 5 33 +30 7 6 5 33 +31 4 5 6 24 +32 1 5 6 34 +33 1 5 6 35 +34 3 24 6 34 +35 3 24 6 35 +36 2 34 6 35 +37 12 2 7 3 +38 12 4 8 5 +39 13 14 9 10 +40 14 14 9 24 +41 14 10 9 24 +42 13 9 10 11 +43 15 9 10 36 +44 15 11 10 36 +45 13 10 11 12 +46 15 10 11 37 +47 15 12 11 37 +48 13 11 12 13 +49 16 11 12 15 +50 16 13 12 15 +51 13 12 13 14 +52 15 12 13 38 +53 15 14 13 38 +54 13 9 14 13 +55 15 9 14 39 +56 15 13 14 39 +57 17 12 15 16 +58 17 12 15 17 +59 18 12 15 18 +60 19 16 15 17 +61 17 18 15 16 +62 17 18 15 17 +63 20 15 16 40 +64 20 15 16 41 +65 20 15 16 42 +66 21 40 16 41 +67 21 40 16 42 +68 21 41 16 42 +69 20 15 17 43 +70 20 15 17 44 +71 20 15 17 45 +72 21 43 17 44 +73 21 43 17 45 +74 21 44 17 45 +75 16 23 18 15 +76 16 19 18 15 +77 13 23 18 19 +78 13 18 19 20 +79 15 18 19 46 +80 15 20 19 46 +81 13 19 20 21 +82 15 19 20 47 +83 15 21 20 47 +84 13 20 21 22 +85 14 20 21 25 +86 14 22 21 25 +87 13 21 22 23 +88 15 21 22 48 +89 15 23 22 48 +90 13 18 23 22 +91 15 18 23 49 +92 15 22 23 49 +93 22 6 24 9 +94 22 1 25 21 +95 1 51 50 75 +96 2 75 50 76 +97 3 74 50 75 +98 1 51 50 76 +99 4 51 50 74 +100 3 74 50 76 +101 5 50 51 56 +102 6 50 51 52 +103 7 50 51 77 +104 8 52 51 56 +105 9 56 51 77 +106 10 52 51 77 +107 8 51 52 56 +108 10 51 52 78 +109 10 51 52 79 +110 9 56 52 78 +111 9 56 52 79 +112 11 78 52 79 +113 9 57 53 81 +114 10 54 53 81 +115 11 81 53 80 +116 8 54 53 57 +117 9 57 53 80 +118 10 54 53 80 +119 8 53 54 57 +120 6 55 54 53 +121 10 53 54 82 +122 5 55 54 57 +123 9 57 54 82 +124 7 55 54 82 +125 4 54 55 73 +126 1 54 55 83 +127 1 54 55 84 +128 3 73 55 83 +129 3 73 55 84 +130 2 83 55 84 +131 12 51 56 52 +132 12 53 57 54 +133 13 63 58 59 +134 14 63 58 73 +135 14 59 58 73 +136 13 58 59 60 +137 15 58 59 85 +138 15 60 59 85 +139 13 59 60 61 +140 15 59 60 86 +141 15 61 60 86 +142 13 60 61 62 +143 16 60 61 64 +144 16 62 61 64 +145 13 61 62 63 +146 15 61 62 87 +147 15 63 62 87 +148 13 58 63 62 +149 15 58 63 88 +150 15 62 63 88 +151 17 61 64 65 +152 17 61 64 66 +153 18 61 64 67 +154 19 65 64 66 +155 17 67 64 65 +156 17 67 64 66 +157 20 64 65 89 +158 20 64 65 90 +159 20 64 65 91 +160 21 89 65 90 +161 21 89 65 91 +162 21 90 65 91 +163 20 64 66 92 +164 20 64 66 93 +165 20 64 66 94 +166 21 92 66 93 +167 21 92 66 94 +168 21 93 66 94 +169 16 72 67 64 +170 16 68 67 64 +171 13 72 67 68 +172 13 67 68 69 +173 15 67 68 95 +174 15 69 68 95 +175 13 68 69 70 +176 15 68 69 96 +177 15 70 69 96 +178 13 69 70 71 +179 14 69 70 74 +180 14 71 70 74 +181 13 70 71 72 +182 15 70 71 97 +183 15 72 71 97 +184 13 67 72 71 +185 15 67 72 98 +186 15 71 72 98 +187 22 55 73 58 +188 22 50 74 70 +189 23 100 99 105 +190 24 100 99 106 +191 24 105 99 106 +192 25 101 100 99 +193 26 107 100 99 +194 26 108 100 99 +195 27 101 100 107 +196 27 101 100 108 +197 2 107 100 108 +198 25 100 101 102 +199 27 100 101 109 +200 27 100 101 110 +201 26 109 101 102 +202 26 110 101 102 +203 2 109 101 110 +204 24 101 102 111 +205 24 101 102 112 +206 28 111 102 112 +207 24 104 103 113 +208 24 104 103 114 +209 28 113 103 114 +210 25 105 104 103 +211 26 115 104 103 +212 26 116 104 103 +213 27 105 104 115 +214 27 105 104 116 +215 2 115 104 116 +216 25 104 105 99 +217 26 117 105 99 +218 26 118 105 99 +219 27 104 105 117 +220 27 104 105 118 +221 2 117 105 118 + +Dihedrals + +1 1 26 1 2 7 +2 2 26 1 2 3 +3 3 26 1 2 28 +4 1 27 1 2 7 +5 2 27 1 2 3 +6 3 27 1 2 28 +7 4 25 1 2 7 +8 5 25 1 2 3 +9 6 25 1 2 28 +10 7 26 1 25 21 +11 8 2 1 25 21 +12 7 27 1 25 21 +13 9 1 2 7 3 +14 10 28 2 7 3 +15 11 1 2 3 7 +16 12 1 2 3 29 +17 12 1 2 3 30 +18 13 7 2 3 29 +19 13 7 2 3 30 +20 13 7 3 2 28 +21 14 28 2 3 29 +22 14 28 2 3 30 +23 10 29 3 7 2 +24 10 30 3 7 2 +25 10 32 4 8 5 +26 10 31 4 8 5 +27 13 8 5 4 32 +28 12 6 5 4 32 +29 14 32 4 5 33 +30 11 6 5 4 8 +31 13 8 4 5 33 +32 13 8 5 4 31 +33 12 6 5 4 31 +34 14 31 4 5 33 +35 9 6 5 8 4 +36 10 33 5 8 4 +37 5 24 6 5 4 +38 2 34 6 5 4 +39 2 35 6 5 4 +40 4 24 6 5 8 +41 1 34 6 5 8 +42 1 35 6 5 8 +43 6 24 6 5 33 +44 3 34 6 5 33 +45 3 35 6 5 33 +46 8 5 6 24 9 +47 7 34 6 24 9 +48 7 35 6 24 9 +49 15 10 9 14 13 +50 16 10 9 14 39 +51 17 13 14 9 24 +52 18 24 9 14 39 +53 15 14 9 10 11 +54 16 14 9 10 36 +55 17 11 10 9 24 +56 18 24 9 10 36 +57 19 14 9 24 6 +58 19 10 9 24 6 +59 15 9 10 11 12 +60 16 9 10 11 37 +61 16 12 11 10 36 +62 20 36 10 11 37 +63 15 10 11 12 13 +64 21 10 11 12 15 +65 16 13 12 11 37 +66 22 15 12 11 37 +67 15 11 12 13 14 +68 16 11 12 13 38 +69 21 14 13 12 15 +70 22 15 12 13 38 +71 23 11 12 15 16 +72 23 11 12 15 17 +73 24 11 12 15 18 +74 23 13 12 15 16 +75 23 13 12 15 17 +76 24 13 12 15 18 +77 15 12 13 14 9 +78 16 12 13 14 39 +79 16 9 14 13 38 +80 20 38 13 14 39 +81 25 12 15 16 40 +82 25 12 15 16 41 +83 25 12 15 16 42 +84 26 17 15 16 40 +85 26 17 15 16 41 +86 26 17 15 16 42 +87 25 18 15 16 40 +88 25 18 15 16 41 +89 25 18 15 16 42 +90 25 12 15 17 43 +91 25 12 15 17 44 +92 25 12 15 17 45 +93 26 16 15 17 43 +94 26 16 15 17 44 +95 26 16 15 17 45 +96 25 18 15 17 43 +97 25 18 15 17 44 +98 25 18 15 17 45 +99 24 23 18 15 12 +100 24 19 18 15 12 +101 23 23 18 15 16 +102 23 19 18 15 16 +103 23 23 18 15 17 +104 23 19 18 15 17 +105 21 22 23 18 15 +106 22 15 18 23 49 +107 15 19 18 23 22 +108 16 19 18 23 49 +109 21 20 19 18 15 +110 22 15 18 19 46 +111 15 23 18 19 20 +112 16 23 18 19 46 +113 15 18 19 20 21 +114 16 18 19 20 47 +115 16 21 20 19 46 +116 20 46 19 20 47 +117 15 19 20 21 22 +118 17 19 20 21 25 +119 16 22 21 20 47 +120 18 25 21 20 47 +121 15 20 21 22 23 +122 16 20 21 22 48 +123 17 23 22 21 25 +124 18 25 21 22 48 +125 19 20 21 25 1 +126 19 22 21 25 1 +127 15 21 22 23 18 +128 16 21 22 23 49 +129 16 18 23 22 48 +130 20 48 22 23 49 +131 1 75 50 51 56 +132 2 75 50 51 52 +133 3 75 50 51 77 +134 1 76 50 51 56 +135 2 76 50 51 52 +136 3 76 50 51 77 +137 4 74 50 51 56 +138 5 74 50 51 52 +139 6 74 50 51 77 +140 7 75 50 74 70 +141 8 51 50 74 70 +142 7 76 50 74 70 +143 9 50 51 56 52 +144 10 77 51 56 52 +145 11 50 51 52 56 +146 12 50 51 52 78 +147 12 50 51 52 79 +148 13 56 51 52 78 +149 13 56 51 52 79 +150 13 56 52 51 77 +151 14 77 51 52 78 +152 14 77 51 52 79 +153 10 78 52 56 51 +154 10 79 52 56 51 +155 10 81 53 57 54 +156 10 80 53 57 54 +157 13 57 54 53 81 +158 12 55 54 53 81 +159 14 81 53 54 82 +160 11 55 54 53 57 +161 13 57 53 54 82 +162 13 57 54 53 80 +163 12 55 54 53 80 +164 14 80 53 54 82 +165 9 55 54 57 53 +166 10 82 54 57 53 +167 5 73 55 54 53 +168 2 83 55 54 53 +169 2 84 55 54 53 +170 4 73 55 54 57 +171 1 83 55 54 57 +172 1 84 55 54 57 +173 6 73 55 54 82 +174 3 83 55 54 82 +175 3 84 55 54 82 +176 8 54 55 73 58 +177 7 83 55 73 58 +178 7 84 55 73 58 +179 15 59 58 63 62 +180 16 59 58 63 88 +181 17 62 63 58 73 +182 18 73 58 63 88 +183 15 63 58 59 60 +184 16 63 58 59 85 +185 17 60 59 58 73 +186 18 73 58 59 85 +187 19 63 58 73 55 +188 19 59 58 73 55 +189 15 58 59 60 61 +190 16 58 59 60 86 +191 16 61 60 59 85 +192 20 85 59 60 86 +193 15 59 60 61 62 +194 21 59 60 61 64 +195 16 62 61 60 86 +196 22 64 61 60 86 +197 15 60 61 62 63 +198 16 60 61 62 87 +199 21 63 62 61 64 +200 22 64 61 62 87 +201 23 60 61 64 65 +202 23 60 61 64 66 +203 24 60 61 64 67 +204 23 62 61 64 65 +205 23 62 61 64 66 +206 24 62 61 64 67 +207 15 61 62 63 58 +208 16 61 62 63 88 +209 16 58 63 62 87 +210 20 87 62 63 88 +211 25 61 64 65 89 +212 25 61 64 65 90 +213 25 61 64 65 91 +214 26 66 64 65 89 +215 26 66 64 65 90 +216 26 66 64 65 91 +217 25 67 64 65 89 +218 25 67 64 65 90 +219 25 67 64 65 91 +220 25 61 64 66 92 +221 25 61 64 66 93 +222 25 61 64 66 94 +223 26 65 64 66 92 +224 26 65 64 66 93 +225 26 65 64 66 94 +226 25 67 64 66 92 +227 25 67 64 66 93 +228 25 67 64 66 94 +229 24 72 67 64 61 +230 24 68 67 64 61 +231 23 72 67 64 65 +232 23 68 67 64 65 +233 23 72 67 64 66 +234 23 68 67 64 66 +235 21 71 72 67 64 +236 22 64 67 72 98 +237 15 68 67 72 71 +238 16 68 67 72 98 +239 21 69 68 67 64 +240 22 64 67 68 95 +241 15 72 67 68 69 +242 16 72 67 68 95 +243 15 67 68 69 70 +244 16 67 68 69 96 +245 16 70 69 68 95 +246 20 95 68 69 96 +247 15 68 69 70 71 +248 17 68 69 70 74 +249 16 71 70 69 96 +250 18 74 70 69 96 +251 15 69 70 71 72 +252 16 69 70 71 97 +253 17 72 71 70 74 +254 18 74 70 71 97 +255 19 69 70 74 50 +256 19 71 70 74 50 +257 15 70 71 72 67 +258 16 70 71 72 98 +259 16 67 72 71 97 +260 20 97 71 72 98 +261 27 101 100 99 105 +262 28 107 100 99 105 +263 28 108 100 99 105 +264 29 101 100 99 106 +265 30 107 100 99 106 +266 30 108 100 99 106 +267 27 104 105 99 100 +268 28 117 105 99 100 +269 28 118 105 99 100 +270 29 104 105 99 106 +271 30 117 105 99 106 +272 30 118 105 99 106 +273 31 99 100 101 102 +274 32 109 101 100 99 +275 32 110 101 100 99 +276 32 107 100 101 102 +277 33 107 100 101 109 +278 33 107 100 101 110 +279 32 108 100 101 102 +280 33 108 100 101 109 +281 33 108 100 101 110 +282 29 100 101 102 111 +283 29 100 101 102 112 +284 30 109 101 102 111 +285 30 109 101 102 112 +286 30 110 101 102 111 +287 30 110 101 102 112 +288 29 105 104 103 113 +289 30 115 104 103 113 +290 30 116 104 103 113 +291 29 105 104 103 114 +292 30 115 104 103 114 +293 30 116 104 103 114 +294 31 103 104 105 99 +295 32 117 105 104 103 +296 32 118 105 104 103 +297 32 115 104 105 99 +298 33 115 104 105 117 +299 33 115 104 105 118 +300 32 116 104 105 99 +301 33 116 104 105 117 +302 33 116 104 105 118 + +Impropers + +1 1 14 9 10 24 +2 2 9 10 11 36 +3 2 10 11 12 37 +4 3 11 12 13 15 +5 2 12 13 14 38 +6 2 9 14 13 39 +7 3 23 18 19 15 +8 2 18 19 20 46 +9 2 19 20 21 47 +10 1 20 21 22 25 +11 2 21 22 23 48 +12 2 18 23 22 49 +13 1 63 58 59 73 +14 2 58 59 60 85 +15 2 59 60 61 86 +16 3 60 61 62 64 +17 2 61 62 63 87 +18 2 58 63 62 88 +19 3 72 67 68 64 +20 2 67 68 69 95 +21 2 68 69 70 96 +22 1 69 70 71 74 +23 2 70 71 72 97 +24 2 67 72 71 98 +25 4 100 99 105 106 +26 5 101 102 111 112 +27 5 104 103 113 114 +28 6 2 1 26 27 +29 7 2 1 25 26 +30 8 25 1 27 26 +31 7 2 1 25 27 +32 9 1 2 3 7 +33 10 1 2 7 28 +34 11 1 2 3 28 +35 12 3 2 7 28 +36 12 2 3 7 29 +37 12 2 3 7 30 +38 13 2 3 29 30 +39 14 7 3 29 30 +40 12 5 4 8 32 +41 14 8 4 32 31 +42 13 5 4 32 31 +43 12 5 4 8 31 +44 9 6 5 4 8 +45 12 4 5 8 33 +46 11 6 5 4 33 +47 10 6 5 8 33 +48 7 5 6 24 34 +49 7 5 6 24 35 +50 6 5 6 34 35 +51 8 24 6 34 35 +52 15 12 15 16 17 +53 16 12 15 18 16 +54 16 12 15 18 17 +55 15 18 15 17 16 +56 17 15 16 40 41 +57 17 15 16 40 42 +58 17 15 16 41 42 +59 18 40 16 41 42 +60 17 15 17 43 44 +61 17 15 17 43 45 +62 17 15 17 44 45 +63 18 43 17 44 45 +64 6 51 50 75 76 +65 7 51 50 74 75 +66 8 74 50 76 75 +67 7 51 50 74 76 +68 9 50 51 52 56 +69 10 50 51 56 77 +70 11 50 51 52 77 +71 12 52 51 56 77 +72 12 51 52 56 78 +73 12 51 52 56 79 +74 13 51 52 78 79 +75 14 56 52 78 79 +76 12 54 53 57 81 +77 14 57 53 81 80 +78 13 54 53 81 80 +79 12 54 53 57 80 +80 9 55 54 53 57 +81 12 53 54 57 82 +82 11 55 54 53 82 +83 10 55 54 57 82 +84 7 54 55 73 83 +85 7 54 55 73 84 +86 6 54 55 83 84 +87 8 73 55 83 84 +88 15 61 64 65 66 +89 16 61 64 67 65 +90 16 61 64 67 66 +91 15 67 64 66 65 +92 17 64 65 89 90 +93 17 64 65 89 91 +94 17 64 65 90 91 +95 18 89 65 90 91 +96 17 64 66 92 93 +97 17 64 66 92 94 +98 17 64 66 93 94 +99 18 92 66 93 94 +100 19 101 100 107 99 +101 19 101 100 108 99 +102 20 107 100 108 99 +103 21 101 100 107 108 +104 19 100 101 109 102 +105 19 100 101 110 102 +106 21 100 101 109 110 +107 20 109 101 110 102 +108 19 105 104 115 103 +109 19 105 104 116 103 +110 20 115 104 116 103 +111 21 105 104 115 116 +112 19 104 105 117 99 +113 19 104 105 118 99 +114 20 117 105 118 99 +115 21 104 105 117 118 -- GitLab From 293e5c3242430e441adb350bb58971512d0691ac Mon Sep 17 00:00:00 2001 From: jrgissing Date: Tue, 31 Dec 2019 19:35:42 -0500 Subject: [PATCH 002/689] bond/react: tiny polystyrene example --- .../bond_react/tiny_polystyrene/2styrene_map | 44 + .../2styrene_reacted.data_template | 312 ++ .../2styrene_unreacted.data_template | 284 ++ .../tiny_polystyrene/chain_chain_map | 67 + .../chain_chain_reacted.data_template | 497 ++++ .../chain_chain_unreacted.data_template | 467 +++ .../tiny_polystyrene/chain_plus_styrene_map | 62 + .../chain_plus_styrene_reacted.data_template | 451 +++ ...chain_plus_styrene_unreacted.data_template | 422 +++ .../in.tiny_polystyrene.stabilized | 56 + ....20Nov19.tiny_polystyrene.stabilized.g++.1 | 245 ++ ....20Nov19.tiny_polystyrene.stabilized.g++.4 | 255 ++ .../tiny_polystyrene/tiny_polystyrene.data | 2643 +++++++++++++++++ 13 files changed, 5805 insertions(+) create mode 100644 examples/USER/misc/bond_react/tiny_polystyrene/2styrene_map create mode 100644 examples/USER/misc/bond_react/tiny_polystyrene/2styrene_reacted.data_template create mode 100644 examples/USER/misc/bond_react/tiny_polystyrene/2styrene_unreacted.data_template create mode 100644 examples/USER/misc/bond_react/tiny_polystyrene/chain_chain_map create mode 100644 examples/USER/misc/bond_react/tiny_polystyrene/chain_chain_reacted.data_template create mode 100644 examples/USER/misc/bond_react/tiny_polystyrene/chain_chain_unreacted.data_template create mode 100644 examples/USER/misc/bond_react/tiny_polystyrene/chain_plus_styrene_map create mode 100644 examples/USER/misc/bond_react/tiny_polystyrene/chain_plus_styrene_reacted.data_template create mode 100644 examples/USER/misc/bond_react/tiny_polystyrene/chain_plus_styrene_unreacted.data_template create mode 100644 examples/USER/misc/bond_react/tiny_polystyrene/in.tiny_polystyrene.stabilized create mode 100644 examples/USER/misc/bond_react/tiny_polystyrene/log.20Nov19.tiny_polystyrene.stabilized.g++.1 create mode 100644 examples/USER/misc/bond_react/tiny_polystyrene/log.20Nov19.tiny_polystyrene.stabilized.g++.4 create mode 100644 examples/USER/misc/bond_react/tiny_polystyrene/tiny_polystyrene.data diff --git a/examples/USER/misc/bond_react/tiny_polystyrene/2styrene_map b/examples/USER/misc/bond_react/tiny_polystyrene/2styrene_map new file mode 100644 index 0000000000..be2a789671 --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_polystyrene/2styrene_map @@ -0,0 +1,44 @@ +this is a map file + +0 edgeIDs +32 equivalences + +BondingIDs + +4 +30 + +Equivalences + +1 1 +2 2 +3 3 +4 4 +5 5 +6 6 +7 7 +8 8 +9 9 +10 10 +11 11 +12 12 +13 13 +14 14 +15 15 +16 16 +17 17 +18 18 +19 19 +20 20 +21 21 +22 22 +23 23 +24 24 +25 25 +26 26 +27 27 +28 28 +29 29 +30 30 +31 31 +32 32 diff --git a/examples/USER/misc/bond_react/tiny_polystyrene/2styrene_reacted.data_template b/examples/USER/misc/bond_react/tiny_polystyrene/2styrene_reacted.data_template new file mode 100644 index 0000000000..c4fa646e9f --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_polystyrene/2styrene_reacted.data_template @@ -0,0 +1,312 @@ +2styrene_reacted + +32 atoms +33 bonds +54 angles +79 dihedrals +22 impropers + +Types + +1 1 +2 2 +3 1 +4 5 +5 1 +6 2 +7 1 +8 2 +9 1 +10 2 +11 1 +12 2 +13 2 +14 6 +15 2 +16 2 +17 1 +18 2 +19 1 +20 5 +21 1 +22 2 +23 1 +24 2 +25 1 +26 2 +27 1 +28 2 +29 2 +30 6 +31 2 +32 2 + +Charges + +1 -0.129000 +2 0.123700 +3 0.026600 +4 -0.018200 +5 -0.129000 +6 0.123700 +7 -0.173400 +8 0.140300 +9 -0.113400 +10 0.128800 +11 -0.173400 +12 0.140300 +13 0.051600 +14 -0.069600 +15 0.035400 +16 0.035400 +17 -0.129000 +18 0.123700 +19 0.026600 +20 -0.018200 +21 -0.129000 +22 0.123700 +23 -0.173400 +24 0.140300 +25 -0.113400 +26 0.128800 +27 -0.173400 +28 0.140300 +29 0.051600 +30 -0.069600 +31 0.035400 +32 0.035400 + +Coords + +1 13.465810 0.682530 -1.658940 +2 14.397820 1.221530 -1.658940 +3 12.235820 1.392530 -1.658940 +4 12.235820 2.892530 -1.658940 +5 11.005820 0.682530 -1.658940 +6 10.073820 1.221530 -1.658940 +7 11.005820 -0.737470 -1.658940 +8 10.073820 -1.276460 -1.658940 +9 12.235820 -1.447460 -1.658940 +10 12.235820 -2.524470 -1.658940 +11 13.465810 -0.737470 -1.658940 +12 14.397820 -1.276460 -1.658940 +13 13.101820 3.297530 -1.301940 +14 10.957820 3.441530 -2.220940 +15 11.007810 4.183540 -2.319940 +16 10.314820 2.618530 -2.514940 +17 18.663521 0.855480 -1.372130 +18 19.595510 1.394480 -1.372130 +19 17.433510 1.565480 -1.372130 +20 17.433510 3.065480 -1.372130 +21 16.203510 0.855480 -1.372130 +22 15.271510 1.394480 -1.372130 +23 16.203510 -0.564520 -1.372130 +24 15.271510 -1.103520 -1.372130 +25 17.433510 -1.274520 -1.372130 +26 17.433510 -2.351520 -1.372130 +27 18.663521 -0.564520 -1.372130 +28 19.595510 -1.103520 -1.372130 +29 18.299509 3.470480 -1.015130 +30 16.155510 3.614480 -1.934130 +31 16.205509 4.356480 -2.033130 +32 15.512510 2.791480 -2.228130 + +Bonds + +1 1 1 2 +2 2 1 3 +3 2 1 11 +4 7 3 4 +5 2 3 5 +6 8 13 4 +7 9 4 14 +8 9 4 30 +9 1 5 6 +10 2 5 7 +11 1 7 8 +12 2 7 9 +13 1 9 10 +14 2 9 11 +15 1 11 12 +16 10 15 14 +17 10 16 14 +18 1 17 18 +19 2 17 19 +20 2 17 27 +21 7 19 20 +22 2 19 21 +23 8 29 20 +24 9 20 30 +25 1 21 22 +26 2 21 23 +27 1 23 24 +28 2 23 25 +29 1 25 26 +30 2 25 27 +31 1 27 28 +32 10 31 30 +33 10 32 30 + +Angles + +1 1 3 1 2 +2 1 11 1 2 +3 2 3 1 11 +4 9 1 3 4 +5 2 1 3 5 +6 9 5 3 4 +7 10 3 4 13 +8 11 3 4 14 +9 11 3 4 30 +10 12 13 4 14 +11 12 13 4 30 +12 13 14 4 30 +13 1 3 5 6 +14 2 3 5 7 +15 1 7 5 6 +16 1 5 7 8 +17 2 5 7 9 +18 1 9 7 8 +19 1 7 9 10 +20 2 7 9 11 +21 1 11 9 10 +22 2 1 11 9 +23 1 1 11 12 +24 1 9 11 12 +25 14 15 14 4 +26 14 16 14 4 +27 15 15 14 16 +28 1 19 17 18 +29 1 27 17 18 +30 2 19 17 27 +31 9 17 19 20 +32 2 17 19 21 +33 9 21 19 20 +34 10 19 20 29 +35 11 19 20 30 +36 12 29 20 30 +37 1 19 21 22 +38 2 19 21 23 +39 1 23 21 22 +40 1 21 23 24 +41 2 21 23 25 +42 1 25 23 24 +43 1 23 25 26 +44 2 23 25 27 +45 1 27 25 26 +46 2 17 27 25 +47 1 17 27 28 +48 1 25 27 28 +49 16 4 30 20 +50 14 31 30 4 +51 14 32 30 4 +52 14 31 30 20 +53 14 32 30 20 +54 15 31 30 32 + +Dihedrals + +1 10 2 1 3 4 +2 2 5 3 1 2 +3 11 11 1 3 4 +4 4 11 1 3 5 +5 2 9 11 1 2 +6 5 2 1 11 12 +7 4 3 1 11 9 +8 2 3 1 11 12 +9 12 1 3 4 13 +10 13 1 3 4 14 +11 13 1 3 4 30 +12 12 5 3 4 13 +13 13 5 3 4 14 +14 13 5 3 4 30 +15 2 1 3 5 6 +16 4 1 3 5 7 +17 10 6 5 3 4 +18 11 7 5 3 4 +19 14 3 4 14 15 +20 14 3 4 14 16 +21 15 13 4 14 15 +22 15 13 4 14 16 +23 16 30 4 14 15 +24 16 30 4 14 16 +25 17 3 4 30 20 +26 14 3 4 30 31 +27 14 3 4 30 32 +28 18 13 4 30 20 +29 15 13 4 30 31 +30 15 13 4 30 32 +31 19 14 4 30 20 +32 16 14 4 30 31 +33 16 14 4 30 32 +34 2 3 5 7 8 +35 4 3 5 7 9 +36 5 6 5 7 8 +37 2 9 7 5 6 +38 2 5 7 9 10 +39 4 5 7 9 11 +40 5 8 7 9 10 +41 2 11 9 7 8 +42 4 7 9 11 1 +43 2 7 9 11 12 +44 2 1 11 9 10 +45 5 10 9 11 12 +46 10 18 17 19 20 +47 2 21 19 17 18 +48 11 27 17 19 20 +49 4 27 17 19 21 +50 2 25 27 17 18 +51 5 18 17 27 28 +52 4 19 17 27 25 +53 2 19 17 27 28 +54 12 17 19 20 29 +55 13 17 19 20 30 +56 12 21 19 20 29 +57 13 21 19 20 30 +58 2 17 19 21 22 +59 4 17 19 21 23 +60 10 22 21 19 20 +61 11 23 21 19 20 +62 17 19 20 30 4 +63 14 19 20 30 31 +64 14 19 20 30 32 +65 18 29 20 30 4 +66 15 29 20 30 31 +67 15 29 20 30 32 +68 2 19 21 23 24 +69 4 19 21 23 25 +70 5 22 21 23 24 +71 2 25 23 21 22 +72 2 21 23 25 26 +73 4 21 23 25 27 +74 5 24 23 25 26 +75 2 27 25 23 24 +76 4 23 25 27 17 +77 2 23 25 27 28 +78 2 17 27 25 26 +79 5 26 25 27 28 + +Impropers + +1 1 3 1 11 2 +2 5 1 3 5 4 +3 1 3 5 7 6 +4 1 5 7 9 8 +5 1 7 9 11 10 +6 1 1 11 9 12 +7 6 15 14 16 4 +8 1 19 17 27 18 +9 5 17 19 21 20 +10 7 19 20 29 30 +11 1 19 21 23 22 +12 1 21 23 25 24 +13 1 23 25 27 26 +14 1 17 27 25 28 +15 1 3 4 13 14 +16 1 3 4 13 30 +17 1 3 4 14 30 +18 1 13 4 14 30 +19 1 31 30 20 4 +20 1 32 30 20 4 +21 1 31 30 32 4 +22 1 31 30 32 20 diff --git a/examples/USER/misc/bond_react/tiny_polystyrene/2styrene_unreacted.data_template b/examples/USER/misc/bond_react/tiny_polystyrene/2styrene_unreacted.data_template new file mode 100644 index 0000000000..fc0a893191 --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_polystyrene/2styrene_unreacted.data_template @@ -0,0 +1,284 @@ +2styrene_unreacted + +32 atoms +32 bonds +48 angles +64 dihedrals +16 impropers + +Types + +1 1 +2 2 +3 1 +4 3 +5 1 +6 2 +7 1 +8 2 +9 1 +10 2 +11 1 +12 2 +13 2 +14 4 +15 2 +16 2 +17 1 +18 2 +19 1 +20 3 +21 1 +22 2 +23 1 +24 2 +25 1 +26 2 +27 1 +28 2 +29 2 +30 4 +31 2 +32 2 + +Charges + +1 -0.129000 +2 0.123700 +3 0.026600 +4 -0.018200 +5 -0.129000 +6 0.123700 +7 -0.173400 +8 0.140300 +9 -0.113400 +10 0.128800 +11 -0.173400 +12 0.140300 +13 0.051600 +14 -0.069600 +15 0.035400 +16 0.035400 +17 -0.129000 +18 0.123700 +19 0.026600 +20 -0.018200 +21 -0.129000 +22 0.123700 +23 -0.173400 +24 0.140300 +25 -0.113400 +26 0.128800 +27 -0.173400 +28 0.140300 +29 0.051600 +30 -0.069600 +31 0.035400 +32 0.035400 + +Coords + +1 13.465815 0.682534 -1.658941 +2 14.397816 1.221534 -1.658941 +3 12.235815 1.392534 -1.658941 +4 12.235815 2.892534 -1.658941 +5 11.005816 0.682534 -1.658941 +6 10.073815 1.221534 -1.658941 +7 11.005816 -0.737466 -1.658941 +8 10.073815 -1.276465 -1.658941 +9 12.235815 -1.447465 -1.658941 +10 12.235815 -2.524465 -1.658941 +11 13.465815 -0.737466 -1.658941 +12 14.397816 -1.276465 -1.658941 +13 13.101815 3.297535 -1.301941 +14 10.957815 3.441535 -2.220941 +15 11.007814 4.183536 -2.319941 +16 10.314816 2.618534 -2.514940 +17 18.663515 0.855482 -1.372128 +18 19.595514 1.394482 -1.372128 +19 17.433512 1.565481 -1.372128 +20 17.433512 3.065482 -1.372128 +21 16.203512 0.855482 -1.372128 +22 15.271511 1.394482 -1.372128 +23 16.203512 -0.564518 -1.372128 +24 15.271511 -1.103518 -1.372128 +25 17.433512 -1.274518 -1.372128 +26 17.433512 -2.351518 -1.372128 +27 18.663515 -0.564518 -1.372128 +28 19.595514 -1.103518 -1.372128 +29 18.299513 3.470482 -1.015128 +30 16.155512 3.614482 -1.934128 +31 16.205513 4.356482 -2.033128 +32 15.512512 2.791482 -2.228127 + +Bonds + +1 1 1 2 +2 2 1 3 +3 2 1 11 +4 3 3 4 +5 2 3 5 +6 4 13 4 +7 5 4 14 +8 1 5 6 +9 2 5 7 +10 1 7 8 +11 2 7 9 +12 1 9 10 +13 2 9 11 +14 1 11 12 +15 6 15 14 +16 6 16 14 +17 1 17 18 +18 2 17 19 +19 2 17 27 +20 3 19 20 +21 2 19 21 +22 4 29 20 +23 5 20 30 +24 1 21 22 +25 2 21 23 +26 1 23 24 +27 2 23 25 +28 1 25 26 +29 2 25 27 +30 1 27 28 +31 6 31 30 +32 6 32 30 + +Angles + +1 1 3 1 2 +2 1 11 1 2 +3 2 3 1 11 +4 3 1 3 4 +5 2 1 3 5 +6 3 5 3 4 +7 4 3 4 13 +8 5 3 4 14 +9 6 13 4 14 +10 1 3 5 6 +11 2 3 5 7 +12 1 7 5 6 +13 1 5 7 8 +14 2 5 7 9 +15 1 9 7 8 +16 1 7 9 10 +17 2 7 9 11 +18 1 11 9 10 +19 2 1 11 9 +20 1 1 11 12 +21 1 9 11 12 +22 7 15 14 4 +23 7 16 14 4 +24 8 15 14 16 +25 1 19 17 18 +26 1 27 17 18 +27 2 19 17 27 +28 3 17 19 20 +29 2 17 19 21 +30 3 21 19 20 +31 4 19 20 29 +32 5 19 20 30 +33 6 29 20 30 +34 1 19 21 22 +35 2 19 21 23 +36 1 23 21 22 +37 1 21 23 24 +38 2 21 23 25 +39 1 25 23 24 +40 1 23 25 26 +41 2 23 25 27 +42 1 27 25 26 +43 2 17 27 25 +44 1 17 27 28 +45 1 25 27 28 +46 7 31 30 20 +47 7 32 30 20 +48 8 31 30 32 + +Dihedrals + +1 1 2 1 3 4 +2 2 5 3 1 2 +3 3 11 1 3 4 +4 4 11 1 3 5 +5 2 9 11 1 2 +6 5 2 1 11 12 +7 4 3 1 11 9 +8 2 3 1 11 12 +9 6 1 3 4 13 +10 7 1 3 4 14 +11 6 5 3 4 13 +12 7 5 3 4 14 +13 2 1 3 5 6 +14 4 1 3 5 7 +15 1 6 5 3 4 +16 3 7 5 3 4 +17 8 3 4 14 15 +18 8 3 4 14 16 +19 9 13 4 14 15 +20 9 13 4 14 16 +21 2 3 5 7 8 +22 4 3 5 7 9 +23 5 6 5 7 8 +24 2 9 7 5 6 +25 2 5 7 9 10 +26 4 5 7 9 11 +27 5 8 7 9 10 +28 2 11 9 7 8 +29 4 7 9 11 1 +30 2 7 9 11 12 +31 2 1 11 9 10 +32 5 10 9 11 12 +33 1 18 17 19 20 +34 2 21 19 17 18 +35 3 27 17 19 20 +36 4 27 17 19 21 +37 2 25 27 17 18 +38 5 18 17 27 28 +39 4 19 17 27 25 +40 2 19 17 27 28 +41 6 17 19 20 29 +42 7 17 19 20 30 +43 6 21 19 20 29 +44 7 21 19 20 30 +45 2 17 19 21 22 +46 4 17 19 21 23 +47 1 22 21 19 20 +48 3 23 21 19 20 +49 8 19 20 30 31 +50 8 19 20 30 32 +51 9 29 20 30 31 +52 9 29 20 30 32 +53 2 19 21 23 24 +54 4 19 21 23 25 +55 5 22 21 23 24 +56 2 25 23 21 22 +57 2 21 23 25 26 +58 4 21 23 25 27 +59 5 24 23 25 26 +60 2 27 25 23 24 +61 4 23 25 27 17 +62 2 23 25 27 28 +63 2 17 27 25 26 +64 5 26 25 27 28 + +Impropers + +1 1 3 1 11 2 +2 2 1 3 5 4 +3 3 3 4 13 14 +4 1 3 5 7 6 +5 1 5 7 9 8 +6 1 7 9 11 10 +7 1 1 11 9 12 +8 4 15 14 16 4 +9 1 19 17 27 18 +10 2 17 19 21 20 +11 3 19 20 29 30 +12 1 19 21 23 22 +13 1 21 23 25 24 +14 1 23 25 27 26 +15 1 17 27 25 28 +16 4 31 30 32 20 diff --git a/examples/USER/misc/bond_react/tiny_polystyrene/chain_chain_map b/examples/USER/misc/bond_react/tiny_polystyrene/chain_chain_map new file mode 100644 index 0000000000..5a0fde6742 --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_polystyrene/chain_chain_map @@ -0,0 +1,67 @@ +this is a map file + +2 edgeIDs +50 equivalences + +EdgeIDs + +17 +34 + +BondingIDs + +14 +38 + +Equivalences + +1 1 +2 2 +3 3 +4 4 +5 5 +6 6 +7 7 +8 8 +9 9 +10 10 +11 11 +12 12 +13 13 +14 14 +15 15 +16 16 +17 17 +18 18 +19 19 +20 20 +21 21 +22 22 +23 23 +24 24 +25 25 +26 26 +27 27 +28 28 +29 29 +30 30 +31 31 +32 32 +33 33 +34 34 +35 35 +36 36 +37 37 +38 38 +39 39 +40 40 +41 41 +42 42 +43 43 +44 44 +45 45 +46 46 +47 47 +48 48 +49 49 +50 50 diff --git a/examples/USER/misc/bond_react/tiny_polystyrene/chain_chain_reacted.data_template b/examples/USER/misc/bond_react/tiny_polystyrene/chain_chain_reacted.data_template new file mode 100644 index 0000000000..e01d42b7fb --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_polystyrene/chain_chain_reacted.data_template @@ -0,0 +1,497 @@ +chain_chain_reacted + +50 atoms +52 bonds +90 angles +135 dihedrals +42 impropers + +Types + +1 1 +2 2 +3 1 +4 5 +5 1 +6 2 +7 1 +8 2 +9 1 +10 2 +11 1 +12 2 +13 2 +14 6 +15 2 +16 2 +17 5 +18 6 +19 2 +20 2 +21 1 +22 2 +23 1 +24 5 +25 1 +26 2 +27 1 +28 2 +29 1 +30 2 +31 1 +32 2 +33 2 +34 6 +35 1 +36 2 +37 1 +38 5 +39 1 +40 2 +41 1 +42 2 +43 1 +44 2 +45 1 +46 2 +47 2 +48 6 +49 2 +50 2 + +Charges + +1 -0.129000 +2 0.123700 +3 0.026600 +4 -0.018200 +5 -0.129000 +6 0.123700 +7 -0.173400 +8 0.140300 +9 -0.113400 +10 0.128800 +11 -0.173400 +12 0.140300 +13 0.051600 +14 -0.069600 +15 0.035400 +16 0.035400 +17 -0.018200 +18 -0.069600 +19 0.035400 +20 0.035400 +21 -0.129000 +22 0.123700 +23 0.026600 +24 -0.018200 +25 -0.129000 +26 0.123700 +27 -0.173400 +28 0.140300 +29 -0.113400 +30 0.128800 +31 -0.173400 +32 0.140300 +33 0.051600 +34 -0.069600 +35 -0.129000 +36 0.123700 +37 0.026600 +38 -0.018200 +39 -0.129000 +40 0.123700 +41 -0.173400 +42 0.140300 +43 -0.113400 +44 0.128800 +45 -0.173400 +46 0.140300 +47 0.051600 +48 -0.069600 +49 0.035400 +50 0.035400 + +Coords + +1 24.391510 0.871570 -1.658940 +2 25.323530 1.410570 -1.658940 +3 23.161520 1.581570 -1.658940 +4 23.161520 3.081570 -1.658940 +5 21.931530 0.871570 -1.658940 +6 20.999531 1.410570 -1.658940 +7 21.931530 -0.548430 -1.658940 +8 20.999531 -1.087420 -1.658940 +9 23.161520 -1.258420 -1.658940 +10 23.161520 -2.335430 -1.658940 +11 24.391510 -0.548430 -1.658940 +12 25.323530 -1.087420 -1.658940 +13 24.027519 3.486570 -1.301940 +14 21.883520 3.630570 -2.220940 +15 21.933510 4.372580 -2.319940 +16 21.240520 2.807570 -2.514940 +17 28.359209 3.254520 -1.372130 +18 27.081209 3.803520 -1.934130 +19 27.131210 4.545520 -2.033130 +20 26.438219 2.980520 -2.228130 +21 13.465810 0.682530 -1.658940 +22 14.397820 1.221530 -1.658940 +23 12.235820 1.392530 -1.658940 +24 12.235820 2.892530 -1.658940 +25 11.005820 0.682530 -1.658940 +26 10.073820 1.221530 -1.658940 +27 11.005820 -0.737470 -1.658940 +28 10.073820 -1.276460 -1.658940 +29 12.235820 -1.447460 -1.658940 +30 12.235820 -2.524470 -1.658940 +31 13.465810 -0.737470 -1.658940 +32 14.397820 -1.276460 -1.658940 +33 13.101820 3.297530 -1.301940 +34 10.957820 3.441530 -2.220940 +35 18.663521 0.855480 -1.372130 +36 19.595510 1.394480 -1.372130 +37 17.433510 1.565480 -1.372130 +38 17.433510 3.065480 -1.372130 +39 16.203510 0.855480 -1.372130 +40 15.271510 1.394480 -1.372130 +41 16.203510 -0.564520 -1.372130 +42 15.271510 -1.103520 -1.372130 +43 17.433510 -1.274520 -1.372130 +44 17.433510 -2.351520 -1.372130 +45 18.663521 -0.564520 -1.372130 +46 19.595510 -1.103520 -1.372130 +47 18.299509 3.470480 -1.015130 +48 16.155510 3.614480 -1.934130 +49 16.205509 4.356480 -2.033130 +50 15.512510 2.791480 -2.228130 + +Bonds + +1 1 1 2 +2 2 1 3 +3 2 1 11 +4 7 3 4 +5 2 3 5 +6 8 13 4 +7 9 4 14 +8 9 4 18 +9 1 5 6 +10 2 5 7 +11 1 7 8 +12 2 7 9 +13 1 9 10 +14 2 9 11 +15 1 11 12 +16 10 15 14 +17 10 16 14 +18 9 38 14 +19 9 17 18 +20 10 19 18 +21 10 20 18 +22 1 21 22 +23 2 21 23 +24 2 21 31 +25 7 23 24 +26 2 23 25 +27 8 33 24 +28 9 24 34 +29 9 24 48 +30 1 25 26 +31 2 25 27 +32 1 27 28 +33 2 27 29 +34 1 29 30 +35 2 29 31 +36 1 31 32 +37 1 35 36 +38 2 35 37 +39 2 35 45 +40 7 37 38 +41 2 37 39 +42 8 47 38 +43 9 38 48 +44 1 39 40 +45 2 39 41 +46 1 41 42 +47 2 41 43 +48 1 43 44 +49 2 43 45 +50 1 45 46 +51 10 49 48 +52 10 50 48 + +Angles + +1 1 3 1 2 +2 1 11 1 2 +3 2 3 1 11 +4 9 1 3 4 +5 2 1 3 5 +6 9 5 3 4 +7 10 3 4 13 +8 11 3 4 14 +9 11 3 4 18 +10 12 13 4 14 +11 12 13 4 18 +12 13 14 4 18 +13 1 3 5 6 +14 2 3 5 7 +15 1 7 5 6 +16 1 5 7 8 +17 2 5 7 9 +18 1 9 7 8 +19 1 7 9 10 +20 2 7 9 11 +21 1 11 9 10 +22 2 1 11 9 +23 1 1 11 12 +24 1 9 11 12 +25 14 15 14 4 +26 14 16 14 4 +27 16 4 14 38 +28 15 15 14 16 +29 14 15 14 38 +30 14 16 14 38 +31 16 4 18 17 +32 14 19 18 4 +33 14 20 18 4 +34 14 19 18 17 +35 14 20 18 17 +36 15 19 18 20 +37 1 23 21 22 +38 1 31 21 22 +39 2 23 21 31 +40 9 21 23 24 +41 2 21 23 25 +42 9 25 23 24 +43 10 23 24 33 +44 11 23 24 34 +45 11 23 24 48 +46 12 33 24 34 +47 12 33 24 48 +48 13 34 24 48 +49 1 23 25 26 +50 2 23 25 27 +51 1 27 25 26 +52 1 25 27 28 +53 2 25 27 29 +54 1 29 27 28 +55 1 27 29 30 +56 2 27 29 31 +57 1 31 29 30 +58 2 21 31 29 +59 1 21 31 32 +60 1 29 31 32 +61 1 37 35 36 +62 1 45 35 36 +63 2 37 35 45 +64 9 35 37 38 +65 2 35 37 39 +66 9 39 37 38 +67 11 37 38 14 +68 12 47 38 14 +69 13 14 38 48 +70 10 37 38 47 +71 11 37 38 48 +72 12 47 38 48 +73 1 37 39 40 +74 2 37 39 41 +75 1 41 39 40 +76 1 39 41 42 +77 2 39 41 43 +78 1 43 41 42 +79 1 41 43 44 +80 2 41 43 45 +81 1 45 43 44 +82 2 35 45 43 +83 1 35 45 46 +84 1 43 45 46 +85 16 24 48 38 +86 14 49 48 24 +87 14 50 48 24 +88 14 49 48 38 +89 14 50 48 38 +90 15 49 48 50 + +Dihedrals + +1 10 2 1 3 4 +2 2 5 3 1 2 +3 11 11 1 3 4 +4 4 11 1 3 5 +5 2 9 11 1 2 +6 5 2 1 11 12 +7 4 3 1 11 9 +8 2 3 1 11 12 +9 12 1 3 4 13 +10 13 1 3 4 14 +11 13 1 3 4 18 +12 12 5 3 4 13 +13 13 5 3 4 14 +14 13 5 3 4 18 +15 2 1 3 5 6 +16 4 1 3 5 7 +17 10 6 5 3 4 +18 11 7 5 3 4 +19 14 3 4 14 15 +20 14 3 4 14 16 +21 17 3 4 14 38 +22 15 13 4 14 15 +23 15 13 4 14 16 +24 18 13 4 14 38 +25 16 18 4 14 15 +26 16 18 4 14 16 +27 19 18 4 14 38 +28 17 3 4 18 17 +29 14 3 4 18 19 +30 14 3 4 18 20 +31 18 13 4 18 17 +32 15 13 4 18 19 +33 15 13 4 18 20 +34 19 14 4 18 17 +35 16 14 4 18 19 +36 16 14 4 18 20 +37 2 3 5 7 8 +38 4 3 5 7 9 +39 5 6 5 7 8 +40 2 9 7 5 6 +41 2 5 7 9 10 +42 4 5 7 9 11 +43 5 8 7 9 10 +44 2 11 9 7 8 +45 4 7 9 11 1 +46 2 7 9 11 12 +47 2 1 11 9 10 +48 5 10 9 11 12 +49 17 37 38 14 4 +50 18 47 38 14 4 +51 19 48 38 14 4 +52 14 37 38 14 15 +53 15 47 38 14 15 +54 16 48 38 14 15 +55 14 37 38 14 16 +56 15 47 38 14 16 +57 16 48 38 14 16 +58 10 22 21 23 24 +59 2 25 23 21 22 +60 11 31 21 23 24 +61 4 31 21 23 25 +62 2 29 31 21 22 +63 5 22 21 31 32 +64 4 23 21 31 29 +65 2 23 21 31 32 +66 12 21 23 24 33 +67 13 21 23 24 34 +68 13 21 23 24 48 +69 12 25 23 24 33 +70 13 25 23 24 34 +71 13 25 23 24 48 +72 2 21 23 25 26 +73 4 21 23 25 27 +74 10 26 25 23 24 +75 11 27 25 23 24 +76 17 23 24 48 38 +77 14 23 24 48 49 +78 14 23 24 48 50 +79 18 33 24 48 38 +80 15 33 24 48 49 +81 15 33 24 48 50 +82 19 34 24 48 38 +83 16 34 24 48 49 +84 16 34 24 48 50 +85 2 23 25 27 28 +86 4 23 25 27 29 +87 5 26 25 27 28 +88 2 29 27 25 26 +89 2 25 27 29 30 +90 4 25 27 29 31 +91 5 28 27 29 30 +92 2 31 29 27 28 +93 4 27 29 31 21 +94 2 27 29 31 32 +95 2 21 31 29 30 +96 5 30 29 31 32 +97 10 36 35 37 38 +98 2 39 37 35 36 +99 11 45 35 37 38 +100 4 45 35 37 39 +101 2 43 45 35 36 +102 5 36 35 45 46 +103 4 37 35 45 43 +104 2 37 35 45 46 +105 13 35 37 38 14 +106 12 35 37 38 47 +107 13 35 37 38 48 +108 13 39 37 38 14 +109 12 39 37 38 47 +110 13 39 37 38 48 +111 2 35 37 39 40 +112 4 35 37 39 41 +113 10 40 39 37 38 +114 11 41 39 37 38 +115 19 14 38 48 24 +116 16 14 38 48 49 +117 16 14 38 48 50 +118 17 37 38 48 24 +119 14 37 38 48 49 +120 14 37 38 48 50 +121 18 47 38 48 24 +122 15 47 38 48 49 +123 15 47 38 48 50 +124 2 37 39 41 42 +125 4 37 39 41 43 +126 5 40 39 41 42 +127 2 43 41 39 40 +128 2 39 41 43 44 +129 4 39 41 43 45 +130 5 42 41 43 44 +131 2 45 43 41 42 +132 4 41 43 45 35 +133 2 41 43 45 46 +134 2 35 45 43 44 +135 5 44 43 45 46 + +Impropers + +1 1 3 1 11 2 +2 5 1 3 5 4 +3 1 3 5 7 6 +4 1 5 7 9 8 +5 1 7 9 11 10 +6 1 1 11 9 12 +7 1 23 21 31 22 +8 5 21 23 25 24 +9 1 23 25 27 26 +10 1 25 27 29 28 +11 1 27 29 31 30 +12 1 21 31 29 32 +13 1 37 35 45 36 +14 5 35 37 39 38 +15 1 37 39 41 40 +16 1 39 41 43 42 +17 1 41 43 45 44 +18 1 35 45 43 46 +19 1 3 4 13 14 +20 1 3 4 13 18 +21 1 3 4 14 18 +22 1 13 4 14 18 +23 1 15 14 16 4 +24 1 15 14 4 38 +25 1 16 14 4 38 +26 1 15 14 16 38 +27 1 19 18 17 4 +28 1 20 18 17 4 +29 1 19 18 20 4 +30 1 19 18 20 17 +31 1 23 24 33 34 +32 1 23 24 33 48 +33 1 23 24 34 48 +34 1 33 24 34 48 +35 1 37 38 47 14 +36 1 37 38 14 48 +37 1 47 38 14 48 +38 1 37 38 47 48 +39 1 49 48 38 24 +40 1 50 48 38 24 +41 1 49 48 50 24 +42 1 49 48 50 38 diff --git a/examples/USER/misc/bond_react/tiny_polystyrene/chain_chain_unreacted.data_template b/examples/USER/misc/bond_react/tiny_polystyrene/chain_chain_unreacted.data_template new file mode 100644 index 0000000000..d8e0d977df --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_polystyrene/chain_chain_unreacted.data_template @@ -0,0 +1,467 @@ +chain_chain_unreacted + +50 atoms +51 bonds +84 angles +118 dihedrals +36 impropers + +Types + +1 1 +2 2 +3 1 +4 5 +5 1 +6 2 +7 1 +8 2 +9 1 +10 2 +11 1 +12 2 +13 2 +14 6 +15 2 +16 2 +17 5 +18 6 +19 2 +20 2 +21 1 +22 2 +23 1 +24 5 +25 1 +26 2 +27 1 +28 2 +29 1 +30 2 +31 1 +32 2 +33 2 +34 6 +35 1 +36 2 +37 1 +38 5 +39 1 +40 2 +41 1 +42 2 +43 1 +44 2 +45 1 +46 2 +47 2 +48 6 +49 2 +50 2 + +Charges + +1 -0.129000 +2 0.123700 +3 0.026600 +4 -0.018200 +5 -0.129000 +6 0.123700 +7 -0.173400 +8 0.140300 +9 -0.113400 +10 0.128800 +11 -0.173400 +12 0.140300 +13 0.051600 +14 -0.069600 +15 0.035400 +16 0.035400 +17 -0.018200 +18 -0.069600 +19 0.035400 +20 0.035400 +21 -0.129000 +22 0.123700 +23 0.026600 +24 -0.018200 +25 -0.129000 +26 0.123700 +27 -0.173400 +28 0.140300 +29 -0.113400 +30 0.128800 +31 -0.173400 +32 0.140300 +33 0.051600 +34 -0.069600 +35 -0.129000 +36 0.123700 +37 0.026600 +38 -0.018200 +39 -0.129000 +40 0.123700 +41 -0.173400 +42 0.140300 +43 -0.113400 +44 0.128800 +45 -0.173400 +46 0.140300 +47 0.051600 +48 -0.069600 +49 0.035400 +50 0.035400 + +Coords + +1 24.391510 0.871570 -1.658940 +2 25.323530 1.410570 -1.658940 +3 23.161520 1.581570 -1.658940 +4 23.161520 3.081570 -1.658940 +5 21.931530 0.871570 -1.658940 +6 20.999531 1.410570 -1.658940 +7 21.931530 -0.548430 -1.658940 +8 20.999531 -1.087420 -1.658940 +9 23.161520 -1.258420 -1.658940 +10 23.161520 -2.335430 -1.658940 +11 24.391510 -0.548430 -1.658940 +12 25.323530 -1.087420 -1.658940 +13 24.027519 3.486570 -1.301940 +14 21.883520 3.630570 -2.220940 +15 21.933510 4.372580 -2.319940 +16 21.240520 2.807570 -2.514940 +17 28.359209 3.254520 -1.372130 +18 27.081209 3.803520 -1.934130 +19 27.131210 4.545520 -2.033130 +20 26.438219 2.980520 -2.228130 +21 13.465810 0.682530 -1.658940 +22 14.397820 1.221530 -1.658940 +23 12.235820 1.392530 -1.658940 +24 12.235820 2.892530 -1.658940 +25 11.005820 0.682530 -1.658940 +26 10.073820 1.221530 -1.658940 +27 11.005820 -0.737470 -1.658940 +28 10.073820 -1.276460 -1.658940 +29 12.235820 -1.447460 -1.658940 +30 12.235820 -2.524470 -1.658940 +31 13.465810 -0.737470 -1.658940 +32 14.397820 -1.276460 -1.658940 +33 13.101820 3.297530 -1.301940 +34 10.957820 3.441530 -2.220940 +35 18.663521 0.855480 -1.372130 +36 19.595510 1.394480 -1.372130 +37 17.433510 1.565480 -1.372130 +38 17.433510 3.065480 -1.372130 +39 16.203510 0.855480 -1.372130 +40 15.271510 1.394480 -1.372130 +41 16.203510 -0.564520 -1.372130 +42 15.271510 -1.103520 -1.372130 +43 17.433510 -1.274520 -1.372130 +44 17.433510 -2.351520 -1.372130 +45 18.663521 -0.564520 -1.372130 +46 19.595510 -1.103520 -1.372130 +47 18.299509 3.470480 -1.015130 +48 16.155510 3.614480 -1.934130 +49 16.205509 4.356480 -2.033130 +50 15.512510 2.791480 -2.228130 + +Bonds + +1 1 1 2 +2 2 1 3 +3 2 1 11 +4 7 3 4 +5 2 3 5 +6 8 13 4 +7 9 4 14 +8 9 4 18 +9 1 5 6 +10 2 5 7 +11 1 7 8 +12 2 7 9 +13 1 9 10 +14 2 9 11 +15 1 11 12 +16 10 15 14 +17 10 16 14 +18 9 17 18 +19 10 19 18 +20 10 20 18 +21 1 21 22 +22 2 21 23 +23 2 21 31 +24 7 23 24 +25 2 23 25 +26 8 33 24 +27 9 24 34 +28 9 24 48 +29 1 25 26 +30 2 25 27 +31 1 27 28 +32 2 27 29 +33 1 29 30 +34 2 29 31 +35 1 31 32 +36 1 35 36 +37 2 35 37 +38 2 35 45 +39 7 37 38 +40 2 37 39 +41 8 47 38 +42 9 38 48 +43 1 39 40 +44 2 39 41 +45 1 41 42 +46 2 41 43 +47 1 43 44 +48 2 43 45 +49 1 45 46 +50 10 49 48 +51 10 50 48 + +Angles + +1 1 3 1 2 +2 1 11 1 2 +3 2 3 1 11 +4 9 1 3 4 +5 2 1 3 5 +6 9 5 3 4 +7 10 3 4 13 +8 11 3 4 14 +9 11 3 4 18 +10 12 13 4 14 +11 12 13 4 18 +12 13 14 4 18 +13 1 3 5 6 +14 2 3 5 7 +15 1 7 5 6 +16 1 5 7 8 +17 2 5 7 9 +18 1 9 7 8 +19 1 7 9 10 +20 2 7 9 11 +21 1 11 9 10 +22 2 1 11 9 +23 1 1 11 12 +24 1 9 11 12 +25 14 15 14 4 +26 14 16 14 4 +27 15 15 14 16 +28 16 4 18 17 +29 14 19 18 4 +30 14 20 18 4 +31 14 19 18 17 +32 14 20 18 17 +33 15 19 18 20 +34 1 23 21 22 +35 1 31 21 22 +36 2 23 21 31 +37 9 21 23 24 +38 2 21 23 25 +39 9 25 23 24 +40 10 23 24 33 +41 11 23 24 34 +42 11 23 24 48 +43 12 33 24 34 +44 12 33 24 48 +45 13 34 24 48 +46 1 23 25 26 +47 2 23 25 27 +48 1 27 25 26 +49 1 25 27 28 +50 2 25 27 29 +51 1 29 27 28 +52 1 27 29 30 +53 2 27 29 31 +54 1 31 29 30 +55 2 21 31 29 +56 1 21 31 32 +57 1 29 31 32 +58 1 37 35 36 +59 1 45 35 36 +60 2 37 35 45 +61 9 35 37 38 +62 2 35 37 39 +63 9 39 37 38 +64 10 37 38 47 +65 11 37 38 48 +66 12 47 38 48 +67 1 37 39 40 +68 2 37 39 41 +69 1 41 39 40 +70 1 39 41 42 +71 2 39 41 43 +72 1 43 41 42 +73 1 41 43 44 +74 2 41 43 45 +75 1 45 43 44 +76 2 35 45 43 +77 1 35 45 46 +78 1 43 45 46 +79 16 24 48 38 +80 14 49 48 24 +81 14 50 48 24 +82 14 49 48 38 +83 14 50 48 38 +84 15 49 48 50 + +Dihedrals + +1 10 2 1 3 4 +2 2 5 3 1 2 +3 11 11 1 3 4 +4 4 11 1 3 5 +5 2 9 11 1 2 +6 5 2 1 11 12 +7 4 3 1 11 9 +8 2 3 1 11 12 +9 12 1 3 4 13 +10 13 1 3 4 14 +11 13 1 3 4 18 +12 12 5 3 4 13 +13 13 5 3 4 14 +14 13 5 3 4 18 +15 2 1 3 5 6 +16 4 1 3 5 7 +17 10 6 5 3 4 +18 11 7 5 3 4 +19 14 3 4 14 15 +20 14 3 4 14 16 +21 15 13 4 14 15 +22 15 13 4 14 16 +23 16 18 4 14 15 +24 16 18 4 14 16 +25 17 3 4 18 17 +26 14 3 4 18 19 +27 14 3 4 18 20 +28 18 13 4 18 17 +29 15 13 4 18 19 +30 15 13 4 18 20 +31 19 14 4 18 17 +32 16 14 4 18 19 +33 16 14 4 18 20 +34 2 3 5 7 8 +35 4 3 5 7 9 +36 5 6 5 7 8 +37 2 9 7 5 6 +38 2 5 7 9 10 +39 4 5 7 9 11 +40 5 8 7 9 10 +41 2 11 9 7 8 +42 4 7 9 11 1 +43 2 7 9 11 12 +44 2 1 11 9 10 +45 5 10 9 11 12 +46 10 22 21 23 24 +47 2 25 23 21 22 +48 11 31 21 23 24 +49 4 31 21 23 25 +50 2 29 31 21 22 +51 5 22 21 31 32 +52 4 23 21 31 29 +53 2 23 21 31 32 +54 12 21 23 24 33 +55 13 21 23 24 34 +56 13 21 23 24 48 +57 12 25 23 24 33 +58 13 25 23 24 34 +59 13 25 23 24 48 +60 2 21 23 25 26 +61 4 21 23 25 27 +62 10 26 25 23 24 +63 11 27 25 23 24 +64 17 23 24 48 38 +65 14 23 24 48 49 +66 14 23 24 48 50 +67 18 33 24 48 38 +68 15 33 24 48 49 +69 15 33 24 48 50 +70 19 34 24 48 38 +71 16 34 24 48 49 +72 16 34 24 48 50 +73 2 23 25 27 28 +74 4 23 25 27 29 +75 5 26 25 27 28 +76 2 29 27 25 26 +77 2 25 27 29 30 +78 4 25 27 29 31 +79 5 28 27 29 30 +80 2 31 29 27 28 +81 4 27 29 31 21 +82 2 27 29 31 32 +83 2 21 31 29 30 +84 5 30 29 31 32 +85 10 36 35 37 38 +86 2 39 37 35 36 +87 11 45 35 37 38 +88 4 45 35 37 39 +89 2 43 45 35 36 +90 5 36 35 45 46 +91 4 37 35 45 43 +92 2 37 35 45 46 +93 12 35 37 38 47 +94 13 35 37 38 48 +95 12 39 37 38 47 +96 13 39 37 38 48 +97 2 35 37 39 40 +98 4 35 37 39 41 +99 10 40 39 37 38 +100 11 41 39 37 38 +101 17 37 38 48 24 +102 14 37 38 48 49 +103 14 37 38 48 50 +104 18 47 38 48 24 +105 15 47 38 48 49 +106 15 47 38 48 50 +107 2 37 39 41 42 +108 4 37 39 41 43 +109 5 40 39 41 42 +110 2 43 41 39 40 +111 2 39 41 43 44 +112 4 39 41 43 45 +113 5 42 41 43 44 +114 2 45 43 41 42 +115 4 41 43 45 35 +116 2 41 43 45 46 +117 2 35 45 43 44 +118 5 44 43 45 46 + +Impropers + +1 1 3 1 11 2 +2 5 1 3 5 4 +3 1 3 5 7 6 +4 1 5 7 9 8 +5 1 7 9 11 10 +6 1 1 11 9 12 +7 6 15 14 16 4 +8 1 23 21 31 22 +9 5 21 23 25 24 +10 1 23 25 27 26 +11 1 25 27 29 28 +12 1 27 29 31 30 +13 1 21 31 29 32 +14 1 37 35 45 36 +15 5 35 37 39 38 +16 7 37 38 47 48 +17 1 37 39 41 40 +18 1 39 41 43 42 +19 1 41 43 45 44 +20 1 35 45 43 46 +21 1 3 4 13 14 +22 1 3 4 13 18 +23 1 3 4 14 18 +24 1 13 4 14 18 +25 1 19 18 17 4 +26 1 20 18 17 4 +27 1 19 18 20 4 +28 1 19 18 20 17 +29 1 23 24 33 34 +30 1 23 24 33 48 +31 1 23 24 34 48 +32 1 33 24 34 48 +33 1 49 48 38 24 +34 1 50 48 38 24 +35 1 49 48 50 24 +36 1 49 48 50 38 diff --git a/examples/USER/misc/bond_react/tiny_polystyrene/chain_plus_styrene_map b/examples/USER/misc/bond_react/tiny_polystyrene/chain_plus_styrene_map new file mode 100644 index 0000000000..56808b0962 --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_polystyrene/chain_plus_styrene_map @@ -0,0 +1,62 @@ +this is a map file + +1 edgeIDs +46 equivalences + +EdgeIDs + +30 + +BondingIDs + +14 +34 + +Equivalences + +1 1 +2 2 +3 3 +4 4 +5 5 +6 6 +7 7 +8 8 +9 9 +10 10 +11 11 +12 12 +13 13 +14 14 +15 15 +16 16 +17 17 +18 18 +19 19 +20 20 +21 21 +22 22 +23 23 +24 24 +25 25 +26 26 +27 27 +28 28 +29 29 +30 30 +31 31 +32 32 +33 33 +34 34 +35 35 +36 36 +37 37 +38 38 +39 39 +40 40 +41 41 +42 42 +43 43 +44 44 +45 45 +46 46 diff --git a/examples/USER/misc/bond_react/tiny_polystyrene/chain_plus_styrene_reacted.data_template b/examples/USER/misc/bond_react/tiny_polystyrene/chain_plus_styrene_reacted.data_template new file mode 100644 index 0000000000..352d88737d --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_polystyrene/chain_plus_styrene_reacted.data_template @@ -0,0 +1,451 @@ +chain_plus_styrene_reacted + +46 atoms +48 bonds +81 angles +121 dihedrals +35 impropers + +Types + +1 1 +2 2 +3 1 +4 5 +5 1 +6 2 +7 1 +8 2 +9 1 +10 2 +11 1 +12 2 +13 2 +14 6 +15 2 +16 2 +17 1 +18 2 +19 1 +20 5 +21 1 +22 2 +23 1 +24 2 +25 1 +26 2 +27 1 +28 2 +29 2 +30 6 +31 1 +32 2 +33 1 +34 5 +35 1 +36 2 +37 1 +38 2 +39 1 +40 2 +41 1 +42 2 +43 2 +44 6 +45 2 +46 2 + +Charges + +1 -0.129000 +2 0.123700 +3 0.026600 +4 -0.018200 +5 -0.129000 +6 0.123700 +7 -0.173400 +8 0.140300 +9 -0.113400 +10 0.128800 +11 -0.173400 +12 0.140300 +13 0.051600 +14 -0.069600 +15 0.035400 +16 0.035400 +17 -0.129000 +18 0.123700 +19 0.026600 +20 -0.018200 +21 -0.129000 +22 0.123700 +23 -0.173400 +24 0.140300 +25 -0.113400 +26 0.128800 +27 -0.173400 +28 0.140300 +29 0.051600 +30 -0.069600 +31 -0.129000 +32 0.123700 +33 0.026600 +34 -0.018200 +35 -0.129000 +36 0.123700 +37 -0.173400 +38 0.140300 +39 -0.113400 +40 0.128800 +41 -0.173400 +42 0.140300 +43 0.051600 +44 -0.069600 +45 0.035400 +46 0.035400 + +Coords + +1 24.130699 1.043900 -1.309300 +2 25.062700 1.582900 -1.309300 +3 22.900700 1.753900 -1.309300 +4 22.900700 3.253900 -1.309300 +5 21.670700 1.043900 -1.309300 +6 20.738701 1.582900 -1.309300 +7 21.670700 -0.376100 -1.309300 +8 20.738701 -0.915100 -1.309300 +9 22.900700 -1.086100 -1.309300 +10 22.900700 -2.163100 -1.309300 +11 24.130699 -0.376100 -1.309300 +12 25.062700 -0.915100 -1.309300 +13 23.766701 3.658900 -0.952300 +14 21.622700 3.802900 -1.871300 +15 21.672701 4.544900 -1.970300 +16 20.979700 2.979900 -2.165300 +17 13.465800 0.682500 -1.658900 +18 14.397800 1.221500 -1.658900 +19 12.235800 1.392500 -1.658900 +20 12.235800 2.892500 -1.658900 +21 11.005800 0.682500 -1.658900 +22 10.073800 1.221500 -1.658900 +23 11.005800 -0.737500 -1.658900 +24 10.073800 -1.276500 -1.658900 +25 12.235800 -1.447500 -1.658900 +26 12.235800 -2.524500 -1.658900 +27 13.465800 -0.737500 -1.658900 +28 14.397800 -1.276500 -1.658900 +29 13.101800 3.297500 -1.301900 +30 10.957800 3.441500 -2.220900 +31 18.663500 0.855500 -1.372100 +32 19.595501 1.394500 -1.372100 +33 17.433500 1.565500 -1.372100 +34 17.433500 3.065500 -1.372100 +35 16.203501 0.855500 -1.372100 +36 15.271500 1.394500 -1.372100 +37 16.203501 -0.564500 -1.372100 +38 15.271500 -1.103500 -1.372100 +39 17.433500 -1.274500 -1.372100 +40 17.433500 -2.351500 -1.372100 +41 18.663500 -0.564500 -1.372100 +42 19.595501 -1.103500 -1.372100 +43 18.299500 3.470500 -1.015100 +44 16.155500 3.614500 -1.934100 +45 16.205500 4.356500 -2.033100 +46 15.512500 2.791500 -2.228100 + +Bonds + +1 1 1 2 +2 2 1 3 +3 2 1 11 +4 11 3 4 +5 2 3 5 +6 12 13 4 +7 13 4 14 +8 1 5 6 +9 2 5 7 +10 1 7 8 +11 2 7 9 +12 1 9 10 +13 2 9 11 +14 1 11 12 +15 10 15 14 +16 10 16 14 +17 9 14 34 +18 1 17 18 +19 2 17 19 +20 2 17 27 +21 7 19 20 +22 2 19 21 +23 8 29 20 +24 9 30 20 +25 9 44 20 +26 1 21 22 +27 2 21 23 +28 1 23 24 +29 2 23 25 +30 1 25 26 +31 2 25 27 +32 1 27 28 +33 1 31 32 +34 2 31 33 +35 2 31 41 +36 7 33 34 +37 2 33 35 +38 8 43 34 +39 9 44 34 +40 1 35 36 +41 2 35 37 +42 1 37 38 +43 2 37 39 +44 1 39 40 +45 2 39 41 +46 1 41 42 +47 10 45 44 +48 10 46 44 + +Angles + +1 1 3 1 2 +2 1 11 1 2 +3 2 3 1 11 +4 17 1 3 4 +5 2 1 3 5 +6 17 5 3 4 +7 18 3 4 13 +8 19 3 4 14 +9 20 13 4 14 +10 1 3 5 6 +11 2 3 5 7 +12 1 7 5 6 +13 1 5 7 8 +14 2 5 7 9 +15 1 9 7 8 +16 1 7 9 10 +17 2 7 9 11 +18 1 11 9 10 +19 2 1 11 9 +20 1 1 11 12 +21 1 9 11 12 +22 21 15 14 4 +23 21 16 14 4 +24 22 4 14 34 +25 15 15 14 16 +26 14 15 14 34 +27 14 16 14 34 +28 1 19 17 18 +29 1 27 17 18 +30 2 19 17 27 +31 9 17 19 20 +32 2 17 19 21 +33 9 21 19 20 +34 10 19 20 29 +35 11 19 20 30 +36 11 19 20 44 +37 12 29 20 30 +38 12 29 20 44 +39 13 30 20 44 +40 1 19 21 22 +41 2 19 21 23 +42 1 23 21 22 +43 1 21 23 24 +44 2 21 23 25 +45 1 25 23 24 +46 1 23 25 26 +47 2 23 25 27 +48 1 27 25 26 +49 2 17 27 25 +50 1 17 27 28 +51 1 25 27 28 +52 1 33 31 32 +53 1 41 31 32 +54 2 33 31 41 +55 9 31 33 34 +56 2 31 33 35 +57 9 35 33 34 +58 11 33 34 14 +59 12 43 34 14 +60 13 14 34 44 +61 10 33 34 43 +62 11 33 34 44 +63 12 43 34 44 +64 1 33 35 36 +65 2 33 35 37 +66 1 37 35 36 +67 1 35 37 38 +68 2 35 37 39 +69 1 39 37 38 +70 1 37 39 40 +71 2 37 39 41 +72 1 41 39 40 +73 2 31 41 39 +74 1 31 41 42 +75 1 39 41 42 +76 16 20 44 34 +77 14 45 44 20 +78 14 46 44 20 +79 14 45 44 34 +80 14 46 44 34 +81 15 45 44 46 + +Dihedrals + +1 20 2 1 3 4 +2 2 5 3 1 2 +3 21 11 1 3 4 +4 4 11 1 3 5 +5 2 9 11 1 2 +6 5 2 1 11 12 +7 4 3 1 11 9 +8 2 3 1 11 12 +9 22 1 3 4 13 +10 23 1 3 4 14 +11 22 5 3 4 13 +12 23 5 3 4 14 +13 2 1 3 5 6 +14 4 1 3 5 7 +15 20 6 5 3 4 +16 21 7 5 3 4 +17 24 3 4 14 15 +18 24 3 4 14 16 +19 25 3 4 14 34 +20 26 13 4 14 15 +21 26 13 4 14 16 +22 27 13 4 14 34 +23 2 3 5 7 8 +24 4 3 5 7 9 +25 5 6 5 7 8 +26 2 9 7 5 6 +27 2 5 7 9 10 +28 4 5 7 9 11 +29 5 8 7 9 10 +30 2 11 9 7 8 +31 4 7 9 11 1 +32 2 7 9 11 12 +33 2 1 11 9 10 +34 5 10 9 11 12 +35 28 4 14 34 33 +36 29 4 14 34 43 +37 30 4 14 34 44 +38 31 15 14 34 33 +39 32 15 14 34 43 +40 33 15 14 34 44 +41 31 16 14 34 33 +42 32 16 14 34 43 +43 33 16 14 34 44 +44 10 18 17 19 20 +45 2 21 19 17 18 +46 11 27 17 19 20 +47 4 27 17 19 21 +48 2 25 27 17 18 +49 5 18 17 27 28 +50 4 19 17 27 25 +51 2 19 17 27 28 +52 12 17 19 20 29 +53 13 17 19 20 30 +54 13 17 19 20 44 +55 12 21 19 20 29 +56 13 21 19 20 30 +57 13 21 19 20 44 +58 2 17 19 21 22 +59 4 17 19 21 23 +60 10 22 21 19 20 +61 11 23 21 19 20 +62 34 34 44 20 19 +63 31 45 44 20 19 +64 31 46 44 20 19 +65 35 34 44 20 29 +66 32 45 44 20 29 +67 32 46 44 20 29 +68 36 34 44 20 30 +69 33 45 44 20 30 +70 33 46 44 20 30 +71 2 19 21 23 24 +72 4 19 21 23 25 +73 5 22 21 23 24 +74 2 25 23 21 22 +75 2 21 23 25 26 +76 4 21 23 25 27 +77 5 24 23 25 26 +78 2 27 25 23 24 +79 4 23 25 27 17 +80 2 23 25 27 28 +81 2 17 27 25 26 +82 5 26 25 27 28 +83 10 32 31 33 34 +84 2 35 33 31 32 +85 11 41 31 33 34 +86 4 41 31 33 35 +87 2 39 41 31 32 +88 5 32 31 41 42 +89 4 33 31 41 39 +90 2 33 31 41 42 +91 13 31 33 34 14 +92 12 31 33 34 43 +93 13 31 33 34 44 +94 13 35 33 34 14 +95 12 35 33 34 43 +96 13 35 33 34 44 +97 2 31 33 35 36 +98 4 31 33 35 37 +99 10 36 35 33 34 +100 11 37 35 33 34 +101 36 20 44 34 14 +102 33 45 44 34 14 +103 33 46 44 34 14 +104 34 20 44 34 33 +105 31 45 44 34 33 +106 31 46 44 34 33 +107 35 20 44 34 43 +108 32 45 44 34 43 +109 32 46 44 34 43 +110 2 33 35 37 38 +111 4 33 35 37 39 +112 5 36 35 37 38 +113 2 39 37 35 36 +114 2 35 37 39 40 +115 4 35 37 39 41 +116 5 38 37 39 40 +117 2 41 39 37 38 +118 4 37 39 41 31 +119 2 37 39 41 42 +120 2 31 41 39 40 +121 5 40 39 41 42 + +Impropers + +1 1 3 1 11 2 +2 8 1 3 5 4 +3 9 3 4 13 14 +4 1 3 5 7 6 +5 1 5 7 9 8 +6 1 7 9 11 10 +7 1 1 11 9 12 +8 1 19 17 27 18 +9 5 17 19 21 20 +10 1 19 21 23 22 +11 1 21 23 25 24 +12 1 23 25 27 26 +13 1 17 27 25 28 +14 1 33 31 41 32 +15 5 31 33 35 34 +16 1 33 35 37 36 +17 1 35 37 39 38 +18 1 37 39 41 40 +19 1 31 41 39 42 +20 1 15 14 16 4 +21 1 15 14 4 34 +22 1 16 14 4 34 +23 1 15 14 16 34 +24 1 19 20 29 30 +25 1 19 20 29 44 +26 1 19 20 30 44 +27 1 29 20 30 44 +28 1 33 34 43 14 +29 1 33 34 14 44 +30 1 43 34 14 44 +31 1 33 34 43 44 +32 1 45 44 34 20 +33 1 46 44 34 20 +34 1 45 44 46 20 +35 1 45 44 46 34 diff --git a/examples/USER/misc/bond_react/tiny_polystyrene/chain_plus_styrene_unreacted.data_template b/examples/USER/misc/bond_react/tiny_polystyrene/chain_plus_styrene_unreacted.data_template new file mode 100644 index 0000000000..f76aad50e6 --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_polystyrene/chain_plus_styrene_unreacted.data_template @@ -0,0 +1,422 @@ +chain_plus_styrene_unreacted + +46 atoms +47 bonds +75 angles +105 dihedrals +29 impropers + +Types + +1 1 +2 2 +3 1 +4 3 +5 1 +6 2 +7 1 +8 2 +9 1 +10 2 +11 1 +12 2 +13 2 +14 4 +15 2 +16 2 +17 1 +18 2 +19 1 +20 5 +21 1 +22 2 +23 1 +24 2 +25 1 +26 2 +27 1 +28 2 +29 2 +30 6 +31 1 +32 2 +33 1 +34 5 +35 1 +36 2 +37 1 +38 2 +39 1 +40 2 +41 1 +42 2 +43 2 +44 6 +45 2 +46 2 + +Charges + +1 -0.129000 +2 0.123700 +3 0.026600 +4 -0.018200 +5 -0.129000 +6 0.123700 +7 -0.173400 +8 0.140300 +9 -0.113400 +10 0.128800 +11 -0.173400 +12 0.140300 +13 0.051600 +14 -0.069600 +15 0.035400 +16 0.035400 +17 -0.129000 +18 0.123700 +19 0.026600 +20 -0.018200 +21 -0.129000 +22 0.123700 +23 -0.173400 +24 0.140300 +25 -0.113400 +26 0.128800 +27 -0.173400 +28 0.140300 +29 0.051600 +30 -0.069600 +31 -0.129000 +32 0.123700 +33 0.026600 +34 -0.018200 +35 -0.129000 +36 0.123700 +37 -0.173400 +38 0.140300 +39 -0.113400 +40 0.128800 +41 -0.173400 +42 0.140300 +43 0.051600 +44 -0.069600 +45 0.035400 +46 0.035400 + +Coords + +1 24.130699 1.043900 -1.309300 +2 25.062700 1.582900 -1.309300 +3 22.900700 1.753900 -1.309300 +4 22.900700 3.253900 -1.309300 +5 21.670700 1.043900 -1.309300 +6 20.738701 1.582900 -1.309300 +7 21.670700 -0.376100 -1.309300 +8 20.738701 -0.915100 -1.309300 +9 22.900700 -1.086100 -1.309300 +10 22.900700 -2.163100 -1.309300 +11 24.130699 -0.376100 -1.309300 +12 25.062700 -0.915100 -1.309300 +13 23.766701 3.658900 -0.952300 +14 21.622700 3.802900 -1.871300 +15 21.672701 4.544900 -1.970300 +16 20.979700 2.979900 -2.165300 +17 13.465800 0.682500 -1.658900 +18 14.397800 1.221500 -1.658900 +19 12.235800 1.392500 -1.658900 +20 12.235800 2.892500 -1.658900 +21 11.005800 0.682500 -1.658900 +22 10.073800 1.221500 -1.658900 +23 11.005800 -0.737500 -1.658900 +24 10.073800 -1.276500 -1.658900 +25 12.235800 -1.447500 -1.658900 +26 12.235800 -2.524500 -1.658900 +27 13.465800 -0.737500 -1.658900 +28 14.397800 -1.276500 -1.658900 +29 13.101800 3.297500 -1.301900 +30 10.957800 3.441500 -2.220900 +31 18.663500 0.855500 -1.372100 +32 19.595501 1.394500 -1.372100 +33 17.433500 1.565500 -1.372100 +34 17.433500 3.065500 -1.372100 +35 16.203501 0.855500 -1.372100 +36 15.271500 1.394500 -1.372100 +37 16.203501 -0.564500 -1.372100 +38 15.271500 -1.103500 -1.372100 +39 17.433500 -1.274500 -1.372100 +40 17.433500 -2.351500 -1.372100 +41 18.663500 -0.564500 -1.372100 +42 19.595501 -1.103500 -1.372100 +43 18.299500 3.470500 -1.015100 +44 16.155500 3.614500 -1.934100 +45 16.205500 4.356500 -2.033100 +46 15.512500 2.791500 -2.228100 + +Bonds + +1 1 1 2 +2 2 1 3 +3 2 1 11 +4 3 3 4 +5 2 3 5 +6 4 13 4 +7 5 4 14 +8 1 5 6 +9 2 5 7 +10 1 7 8 +11 2 7 9 +12 1 9 10 +13 2 9 11 +14 1 11 12 +15 6 15 14 +16 6 16 14 +17 1 17 18 +18 2 17 19 +19 2 17 27 +20 7 19 20 +21 2 19 21 +22 8 29 20 +23 9 20 30 +24 9 20 44 +25 1 21 22 +26 2 21 23 +27 1 23 24 +28 2 23 25 +29 1 25 26 +30 2 25 27 +31 1 27 28 +32 1 31 32 +33 2 31 33 +34 2 31 41 +35 7 33 34 +36 2 33 35 +37 8 43 34 +38 9 34 44 +39 1 35 36 +40 2 35 37 +41 1 37 38 +42 2 37 39 +43 1 39 40 +44 2 39 41 +45 1 41 42 +46 10 45 44 +47 10 46 44 + +Angles + +1 1 3 1 2 +2 1 11 1 2 +3 2 3 1 11 +4 3 1 3 4 +5 2 1 3 5 +6 3 5 3 4 +7 4 3 4 13 +8 5 3 4 14 +9 6 13 4 14 +10 1 3 5 6 +11 2 3 5 7 +12 1 7 5 6 +13 1 5 7 8 +14 2 5 7 9 +15 1 9 7 8 +16 1 7 9 10 +17 2 7 9 11 +18 1 11 9 10 +19 2 1 11 9 +20 1 1 11 12 +21 1 9 11 12 +22 7 15 14 4 +23 7 16 14 4 +24 8 15 14 16 +25 1 19 17 18 +26 1 27 17 18 +27 2 19 17 27 +28 9 17 19 20 +29 2 17 19 21 +30 9 21 19 20 +31 10 19 20 29 +32 11 19 20 30 +33 11 19 20 44 +34 12 29 20 30 +35 12 29 20 44 +36 13 30 20 44 +37 1 19 21 22 +38 2 19 21 23 +39 1 23 21 22 +40 1 21 23 24 +41 2 21 23 25 +42 1 25 23 24 +43 1 23 25 26 +44 2 23 25 27 +45 1 27 25 26 +46 2 17 27 25 +47 1 17 27 28 +48 1 25 27 28 +49 1 33 31 32 +50 1 41 31 32 +51 2 33 31 41 +52 9 31 33 34 +53 2 31 33 35 +54 9 35 33 34 +55 10 33 34 43 +56 11 33 34 44 +57 12 43 34 44 +58 1 33 35 36 +59 2 33 35 37 +60 1 37 35 36 +61 1 35 37 38 +62 2 35 37 39 +63 1 39 37 38 +64 1 37 39 40 +65 2 37 39 41 +66 1 41 39 40 +67 2 31 41 39 +68 1 31 41 42 +69 1 39 41 42 +70 16 20 44 34 +71 14 45 44 20 +72 14 46 44 20 +73 14 45 44 34 +74 14 46 44 34 +75 15 45 44 46 + +Dihedrals + +1 1 2 1 3 4 +2 2 5 3 1 2 +3 3 11 1 3 4 +4 4 11 1 3 5 +5 2 9 11 1 2 +6 5 2 1 11 12 +7 4 3 1 11 9 +8 2 3 1 11 12 +9 6 1 3 4 13 +10 7 1 3 4 14 +11 6 5 3 4 13 +12 7 5 3 4 14 +13 2 1 3 5 6 +14 4 1 3 5 7 +15 1 6 5 3 4 +16 3 7 5 3 4 +17 8 3 4 14 15 +18 8 3 4 14 16 +19 9 13 4 14 15 +20 9 13 4 14 16 +21 2 3 5 7 8 +22 4 3 5 7 9 +23 5 6 5 7 8 +24 2 9 7 5 6 +25 2 5 7 9 10 +26 4 5 7 9 11 +27 5 8 7 9 10 +28 2 11 9 7 8 +29 4 7 9 11 1 +30 2 7 9 11 12 +31 2 1 11 9 10 +32 5 10 9 11 12 +33 10 18 17 19 20 +34 2 21 19 17 18 +35 11 27 17 19 20 +36 4 27 17 19 21 +37 2 25 27 17 18 +38 5 18 17 27 28 +39 4 19 17 27 25 +40 2 19 17 27 28 +41 12 17 19 20 29 +42 13 17 19 20 30 +43 13 17 19 20 44 +44 12 21 19 20 29 +45 13 21 19 20 30 +46 13 21 19 20 44 +47 2 17 19 21 22 +48 4 17 19 21 23 +49 10 22 21 19 20 +50 11 23 21 19 20 +51 17 19 20 44 34 +52 14 19 20 44 45 +53 14 19 20 44 46 +54 18 29 20 44 34 +55 15 29 20 44 45 +56 15 29 20 44 46 +57 19 30 20 44 34 +58 16 30 20 44 45 +59 16 30 20 44 46 +60 2 19 21 23 24 +61 4 19 21 23 25 +62 5 22 21 23 24 +63 2 25 23 21 22 +64 2 21 23 25 26 +65 4 21 23 25 27 +66 5 24 23 25 26 +67 2 27 25 23 24 +68 4 23 25 27 17 +69 2 23 25 27 28 +70 2 17 27 25 26 +71 5 26 25 27 28 +72 10 32 31 33 34 +73 2 35 33 31 32 +74 11 41 31 33 34 +75 4 41 31 33 35 +76 2 39 41 31 32 +77 5 32 31 41 42 +78 4 33 31 41 39 +79 2 33 31 41 42 +80 12 31 33 34 43 +81 13 31 33 34 44 +82 12 35 33 34 43 +83 13 35 33 34 44 +84 2 31 33 35 36 +85 4 31 33 35 37 +86 10 36 35 33 34 +87 11 37 35 33 34 +88 17 33 34 44 20 +89 14 33 34 44 45 +90 14 33 34 44 46 +91 18 43 34 44 20 +92 15 43 34 44 45 +93 15 43 34 44 46 +94 2 33 35 37 38 +95 4 33 35 37 39 +96 5 36 35 37 38 +97 2 39 37 35 36 +98 2 35 37 39 40 +99 4 35 37 39 41 +100 5 38 37 39 40 +101 2 41 39 37 38 +102 4 37 39 41 31 +103 2 37 39 41 42 +104 2 31 41 39 40 +105 5 40 39 41 42 + +Impropers + +1 1 3 1 11 2 +2 2 1 3 5 4 +3 3 3 4 13 14 +4 1 3 5 7 6 +5 1 5 7 9 8 +6 1 7 9 11 10 +7 1 1 11 9 12 +8 4 15 14 16 4 +9 1 19 17 27 18 +10 5 17 19 21 20 +11 1 19 21 23 22 +12 1 21 23 25 24 +13 1 23 25 27 26 +14 1 17 27 25 28 +15 1 33 31 41 32 +16 5 31 33 35 34 +17 7 33 34 43 44 +18 1 33 35 37 36 +19 1 35 37 39 38 +20 1 37 39 41 40 +21 1 31 41 39 42 +22 1 19 20 29 30 +23 1 19 20 29 44 +24 1 19 20 30 44 +25 1 29 20 30 44 +26 1 45 44 34 20 +27 1 46 44 34 20 +28 1 45 44 46 20 +29 1 45 44 46 34 diff --git a/examples/USER/misc/bond_react/tiny_polystyrene/in.tiny_polystyrene.stabilized b/examples/USER/misc/bond_react/tiny_polystyrene/in.tiny_polystyrene.stabilized new file mode 100644 index 0000000000..a711f3eaa9 --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_polystyrene/in.tiny_polystyrene.stabilized @@ -0,0 +1,56 @@ +# 20 styrene molecules +# three reactions defined + +units real + +boundary p p p + +atom_style full + +kspace_style pppm 1.0e-4 + +pair_style lj/class2/coul/long 8.5 + +angle_style class2 + +bond_style class2 + +dihedral_style class2 + +improper_style class2 + +variable T equal 530 + +read_data tiny_polystyrene.data & + extra/bond/per/atom 5 & + extra/angle/per/atom 15 & + extra/dihedral/per/atom 15 & + extra/improper/per/atom 25 & + extra/special/per/atom 25 + +molecule mol1 2styrene_unreacted.data_template +molecule mol2 2styrene_reacted.data_template +molecule mol3 chain_plus_styrene_unreacted.data_template +molecule mol4 chain_plus_styrene_reacted.data_template +molecule mol5 chain_chain_unreacted.data_template +molecule mol6 chain_chain_reacted.data_template + +thermo 100 + +# dump 1 all xyz 5 test_vis.xyz + +fix rxn1 all bond/react stabilization yes statted_grp .03 & + react rxn1 all 1 0 3.0 mol1 mol2 2styrene_map stabilize_steps 100 & + react rxn2 all 1 0 3.0 mol3 mol4 chain_plus_styrene_map stabilize_steps 100 & + react rxn3 all 1 0 5.0 mol5 mol6 chain_chain_map stabilize_steps 100 + +fix 1 statted_grp_REACT nvt temp $T $T 100 + +fix 4 bond_react_MASTER_group temp/rescale 1 $T $T 1 1 + +thermo_style custom step temp press density f_rxn1[1] f_rxn1[2] f_rxn1[3] + +run 10000 + +# write_restart restart_longrun nofix +# write_data restart_longrun.data diff --git a/examples/USER/misc/bond_react/tiny_polystyrene/log.20Nov19.tiny_polystyrene.stabilized.g++.1 b/examples/USER/misc/bond_react/tiny_polystyrene/log.20Nov19.tiny_polystyrene.stabilized.g++.1 new file mode 100644 index 0000000000..274c72ece9 --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_polystyrene/log.20Nov19.tiny_polystyrene.stabilized.g++.1 @@ -0,0 +1,245 @@ +LAMMPS (20 Nov 2019) + +WARNING-WARNING-WARNING-WARNING-WARNING +This LAMMPS executable was compiled using C++98 compatibility. +Please report the compiler info below at https://github.com/lammps/lammps/issues/1659 +GNU C++ 4.8.5 +WARNING-WARNING-WARNING-WARNING-WARNING + +Reading data file ... + orthogonal box = (1.74267 1.74267 1.74267) to (18.2573 18.2573 18.2573) + 1 by 1 by 1 MPI processor grid + reading atoms ... + 320 atoms + reading velocities ... + 320 velocities + scanning bonds ... + 8 = max bonds/atom + scanning angles ... + 18 = max angles/atom + scanning dihedrals ... + 22 = max dihedrals/atom + scanning impropers ... + 26 = max impropers/atom + reading bonds ... + 320 bonds + reading angles ... + 480 angles + reading dihedrals ... + 640 dihedrals + reading impropers ... + 160 impropers +Finding 1-2 1-3 1-4 neighbors ... + special bond factors lj: 0 0 0 + special bond factors coul: 0 0 0 + 3 = max # of 1-2 neighbors + 6 = max # of 1-3 neighbors + 12 = max # of 1-4 neighbors + 39 = max # of special neighbors + special bonds CPU = 0.000929056 secs + read_data CPU = 0.00930568 secs +Read molecule mol1: + 32 atoms with max type 4 + 32 bonds with max type 6 + 48 angles with max type 8 + 64 dihedrals with max type 9 + 16 impropers with max type 4 +Read molecule mol2: + 32 atoms with max type 6 + 33 bonds with max type 10 + 54 angles with max type 16 + 79 dihedrals with max type 19 + 22 impropers with max type 7 +Read molecule mol3: + 46 atoms with max type 6 + 47 bonds with max type 10 + 75 angles with max type 16 + 105 dihedrals with max type 19 + 29 impropers with max type 7 +Read molecule mol4: + 46 atoms with max type 6 + 48 bonds with max type 13 + 81 angles with max type 22 + 121 dihedrals with max type 36 + 35 impropers with max type 9 +Read molecule mol5: + 50 atoms with max type 6 + 51 bonds with max type 10 + 84 angles with max type 16 + 118 dihedrals with max type 19 + 36 impropers with max type 7 +Read molecule mol6: + 50 atoms with max type 6 + 52 bonds with max type 10 + 90 angles with max type 16 + 135 dihedrals with max type 19 + 42 impropers with max type 5 +dynamic group bond_react_MASTER_group defined +dynamic group statted_grp_REACT defined +PPPM initialization ... +WARNING: System is not charge neutral, net charge = -0.004 (../kspace.cpp:304) + using 12-bit tables for long-range coulomb (../kspace.cpp:323) + G vector (1/distance) = 0.255611 + grid = 6 6 6 + stencil order = 5 + estimated absolute RMS force accuracy = 0.00974692 + estimated relative force accuracy = 2.93525e-05 + using double precision FFTs + 3d grid and FFT values/proc = 1331 216 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 10.5 + ghost atom cutoff = 10.5 + binsize = 5.25, bins = 4 4 4 + 2 neighbor lists, perpetual/occasional/extra = 1 1 0 + (1) pair lj/class2/coul/long, perpetual + attributes: half, newton on + pair build: half/bin/newton + stencil: half/bin/3d/newton + bin: standard + (2) fix bond/react, occasional, copy from (1) + attributes: half, newton on + pair build: copy + stencil: none + bin: none +Setting up Verlet run ... + Unit style : real + Current step : 0 + Time step : 1 +Per MPI rank memory allocation (min/avg/max) = 31.14 | 31.14 | 31.14 Mbytes +Step Temp Press Density f_rxn1[1] f_rxn1[2] f_rxn1[3] + 0 320.13638 -376.0844 0.76796752 0 0 0 + 100 520.00782 3952.7008 0.76796752 8 0 0 + 200 499.9174 2360.8219 0.76796752 8 3 1 + 300 583.93895 2453.7374 0.76796752 8 3 2 + 400 560.65536 -2243.3464 0.76796752 8 3 3 + 500 556.27995 3598.7044 0.76796752 8 3 3 + 600 570.8397 -3340.1826 0.76796752 8 4 4 + 700 456.89894 -1087.8081 0.76796752 8 4 4 + 800 572.91817 -776.19188 0.76796752 8 4 4 + 900 530.13621 -246734.46 0.76796752 8 4 5 + 1000 542.34698 1044.0793 0.76796752 8 4 5 + 1100 562.86339 1207.1715 0.76796752 8 4 5 + 1200 520.1559 2725.6523 0.76796752 8 4 5 + 1300 534.01667 951.0972 0.76796752 8 4 5 + 1400 478.68681 1184.9224 0.76796752 8 4 5 + 1500 509.05445 2020.5224 0.76796752 8 4 5 + 1600 549.5382 810.17577 0.76796752 8 4 5 + 1700 549.46882 -6349.7751 0.76796752 8 4 5 + 1800 496.77334 3953.1043 0.76796752 8 4 5 + 1900 522.28719 -2271.7599 0.76796752 8 4 6 + 2000 569.95975 5633.4352 0.76796752 8 4 6 + 2100 590.8418 2355.8447 0.76796752 8 4 6 + 2200 537.64787 6459.6743 0.76796752 8 4 6 + 2300 548.38487 -1566.3528 0.76796752 8 4 6 + 2400 533.50353 6755.664 0.76796752 8 4 6 + 2500 512.57053 325.30968 0.76796752 8 4 6 + 2600 498.4597 -2468.1165 0.76796752 8 4 6 + 2700 559.03937 2428.3446 0.76796752 8 4 6 + 2800 585.85721 -2896.3607 0.76796752 8 4 6 + 2900 523.18635 1391.254 0.76796752 8 4 6 + 3000 524.62076 375.02973 0.76796752 8 4 6 + 3100 534.65688 -1522.7879 0.76796752 8 4 6 + 3200 499.42665 3725.5476 0.76796752 8 4 6 + 3300 514.36972 1725.8329 0.76796752 8 4 6 + 3400 482.52662 4648.5013 0.76796752 8 4 6 + 3500 495.36836 967.3482 0.76796752 8 4 6 + 3600 583.28736 745.21794 0.76796752 8 4 6 + 3700 531.99717 -804.39572 0.76796752 8 4 6 + 3800 555.08359 -2381.363 0.76796752 8 4 6 + 3900 520.1818 -547.34169 0.76796752 8 4 6 + 4000 444.38804 -2488.7881 0.76796752 8 4 6 + 4100 518.65622 -3135.9573 0.76796752 8 4 6 + 4200 484.15227 -1040.2447 0.76796752 8 4 6 + 4300 514.58006 550.14626 0.76796752 8 4 6 + 4400 579.81405 -849.81454 0.76796752 8 4 6 + 4500 522.8698 5222.654 0.76796752 8 4 6 + 4600 490.78275 3251.2892 0.76796752 8 4 6 + 4700 492.64299 3785.3482 0.76796752 8 4 6 + 4800 500.11059 4441.8978 0.76796752 8 4 6 + 4900 536.80009 965.33724 0.76796752 8 4 6 + 5000 516.98575 -3794.4213 0.76796752 8 4 6 + 5100 516.76648 -3593.9106 0.76796752 8 4 6 + 5200 521.6379 -6532.7773 0.76796752 8 4 6 + 5300 535.64798 2931.412 0.76796752 8 4 6 + 5400 559.83266 7628.1659 0.76796752 8 4 6 + 5500 538.91756 2841.6746 0.76796752 8 4 6 + 5600 539.13999 10445.173 0.76796752 8 4 6 + 5700 501.56603 -2106.3309 0.76796752 8 4 6 + 5800 496.72952 -4831.0565 0.76796752 8 4 6 + 5900 536.12979 -3916.8197 0.76796752 8 4 6 + 6000 553.10092 3142.6871 0.76796752 8 4 6 + 6100 558.09546 3154.584 0.76796752 8 4 6 + 6200 523.48472 9807.0034 0.76796752 8 4 6 + 6300 551.80343 -3608.2078 0.76796752 8 4 6 + 6400 484.28359 2255.4675 0.76796752 8 4 6 + 6500 560.68443 -4826.4868 0.76796752 8 4 6 + 6600 604.50797 402.32183 0.76796752 8 4 6 + 6700 538.84714 -7670.3312 0.76796752 8 4 6 + 6800 528.82853 -380.32058 0.76796752 8 4 6 + 6900 579.30919 4438.4574 0.76796752 8 4 6 + 7000 540.3406 3738.0524 0.76796752 8 4 6 + 7100 519.53645 -1825.5563 0.76796752 8 4 6 + 7200 474.136 1657.3863 0.76796752 8 4 6 + 7300 485.55159 -221.84939 0.76796752 8 4 6 + 7400 527.38494 1037.1777 0.76796752 8 4 6 + 7500 517.14767 -2313.5823 0.76796752 8 4 6 + 7600 517.95967 -4763.4709 0.76796752 8 4 6 + 7700 513.63507 4819.0253 0.76796752 8 4 6 + 7800 503.56828 1295.1212 0.76796752 8 4 6 + 7900 520.87804 1506.9417 0.76796752 8 4 6 + 8000 509.46453 -5800.0971 0.76796752 8 4 6 + 8100 566.67059 6065.4607 0.76796752 8 4 6 + 8200 592.53068 1097.2277 0.76796752 8 4 6 + 8300 529.55235 -580.81757 0.76796752 8 4 6 + 8400 518.22587 560.45589 0.76796752 8 4 6 + 8500 521.94561 5325.9459 0.76796752 8 4 6 + 8600 510.54416 -1929.1967 0.76796752 8 4 6 + 8700 562.71252 -629.90392 0.76796752 8 4 6 + 8800 540.23123 -3484.3893 0.76796752 8 4 6 + 8900 513.82411 -5227.152 0.76796752 8 4 6 + 9000 534.3307 -3299.088 0.76796752 8 4 6 + 9100 509.24467 -5676.2775 0.76796752 8 4 6 + 9200 506.3216 -7043.8493 0.76796752 8 4 7 + 9300 480.37682 2380.4696 0.76796752 8 4 7 + 9400 546.15532 1831.0103 0.76796752 8 4 7 + 9500 567.18341 3839.9843 0.76796752 8 4 7 + 9600 536.14883 4258.5304 0.76796752 8 4 7 + 9700 496.04153 3321.3561 0.76796752 8 4 7 + 9800 531.78927 3124.9156 0.76796752 8 4 7 + 9900 530.91395 38.987859 0.76796752 8 4 7 + 10000 551.22761 1027.5706 0.76796752 8 4 7 +Loop time of 57.7096 on 1 procs for 10000 steps with 320 atoms + +Performance: 14.972 ns/day, 1.603 hours/ns, 173.281 timesteps/s +99.9% CPU use with 1 MPI tasks x no OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 11.621 | 11.621 | 11.621 | 0.0 | 20.14 +Bond | 11.151 | 11.151 | 11.151 | 0.0 | 19.32 +Kspace | 2.2403 | 2.2403 | 2.2403 | 0.0 | 3.88 +Neigh | 25.467 | 25.467 | 25.467 | 0.0 | 44.13 +Comm | 0.90467 | 0.90467 | 0.90467 | 0.0 | 1.57 +Output | 0.0017984 | 0.0017984 | 0.0017984 | 0.0 | 0.00 +Modify | 6.2622 | 6.2622 | 6.2622 | 0.0 | 10.85 +Other | | 0.06192 | | | 0.11 + +Nlocal: 320 ave 320 max 320 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 3240 ave 3240 max 3240 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 54336 ave 54336 max 54336 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 54336 +Ave neighs/atom = 169.8 +Ave special neighs/atom = 11.3063 +Neighbor list builds = 10000 +Dangerous builds = 0 + +Please see the log.cite file for references relevant to this simulation + +Total wall time: 0:00:58 diff --git a/examples/USER/misc/bond_react/tiny_polystyrene/log.20Nov19.tiny_polystyrene.stabilized.g++.4 b/examples/USER/misc/bond_react/tiny_polystyrene/log.20Nov19.tiny_polystyrene.stabilized.g++.4 new file mode 100644 index 0000000000..29aae1cd0b --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_polystyrene/log.20Nov19.tiny_polystyrene.stabilized.g++.4 @@ -0,0 +1,255 @@ +LAMMPS (20 Nov 2019) + +WARNING-WARNING-WARNING-WARNING-WARNING +This LAMMPS executable was compiled using C++98 compatibility. +Please report the compiler info below at https://github.com/lammps/lammps/issues/1659 +GNU C++ 4.8.5 +WARNING-WARNING-WARNING-WARNING-WARNING + +Reading data file ... + orthogonal box = (1.74267 1.74267 1.74267) to (18.2573 18.2573 18.2573) + 1 by 2 by 2 MPI processor grid + reading atoms ... + 320 atoms + reading velocities ... + 320 velocities + scanning bonds ... + 8 = max bonds/atom + scanning angles ... + 18 = max angles/atom + scanning dihedrals ... + 22 = max dihedrals/atom + scanning impropers ... + 26 = max impropers/atom + reading bonds ... + 320 bonds + reading angles ... + 480 angles + reading dihedrals ... + 640 dihedrals + reading impropers ... + 160 impropers +Finding 1-2 1-3 1-4 neighbors ... + special bond factors lj: 0 0 0 + special bond factors coul: 0 0 0 + 3 = max # of 1-2 neighbors + 6 = max # of 1-3 neighbors + 12 = max # of 1-4 neighbors + 39 = max # of special neighbors + special bonds CPU = 0.000751222 secs + read_data CPU = 0.0268223 secs +Read molecule mol1: + 32 atoms with max type 4 + 32 bonds with max type 6 + 48 angles with max type 8 + 64 dihedrals with max type 9 + 16 impropers with max type 4 +Read molecule mol2: + 32 atoms with max type 6 + 33 bonds with max type 10 + 54 angles with max type 16 + 79 dihedrals with max type 19 + 22 impropers with max type 7 +Read molecule mol3: + 46 atoms with max type 6 + 47 bonds with max type 10 + 75 angles with max type 16 + 105 dihedrals with max type 19 + 29 impropers with max type 7 +Read molecule mol4: + 46 atoms with max type 6 + 48 bonds with max type 13 + 81 angles with max type 22 + 121 dihedrals with max type 36 + 35 impropers with max type 9 +Read molecule mol5: + 50 atoms with max type 6 + 51 bonds with max type 10 + 84 angles with max type 16 + 118 dihedrals with max type 19 + 36 impropers with max type 7 +Read molecule mol6: + 50 atoms with max type 6 + 52 bonds with max type 10 + 90 angles with max type 16 + 135 dihedrals with max type 19 + 42 impropers with max type 5 +dynamic group bond_react_MASTER_group defined +dynamic group statted_grp_REACT defined +PPPM initialization ... +WARNING: System is not charge neutral, net charge = -0.004 (../kspace.cpp:304) + using 12-bit tables for long-range coulomb (../kspace.cpp:323) + G vector (1/distance) = 0.255611 + grid = 6 6 6 + stencil order = 5 + estimated absolute RMS force accuracy = 0.00974692 + estimated relative force accuracy = 2.93525e-05 + using double precision FFTs + 3d grid and FFT values/proc = 704 72 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 10.5 + ghost atom cutoff = 10.5 + binsize = 5.25, bins = 4 4 4 + 2 neighbor lists, perpetual/occasional/extra = 1 1 0 + (1) pair lj/class2/coul/long, perpetual + attributes: half, newton on + pair build: half/bin/newton + stencil: half/bin/3d/newton + bin: standard + (2) fix bond/react, occasional, copy from (1) + attributes: half, newton on + pair build: copy + stencil: none + bin: none +Setting up Verlet run ... + Unit style : real + Current step : 0 + Time step : 1 +Per MPI rank memory allocation (min/avg/max) = 30.66 | 30.68 | 30.69 Mbytes +Step Temp Press Density f_rxn1[1] f_rxn1[2] f_rxn1[3] + 0 320.13638 -376.0844 0.76796752 0 0 0 + 100 522.71544 6623.0579 0.76796752 8 0 0 + 200 500.86716 -9439.5519 0.76796752 8 3 2 + 300 594.60588 6714.1323 0.76796752 8 3 3 + 400 598.68768 683.70457 0.76796752 8 3 3 + 500 563.1011 3576.6857 0.76796752 8 3 4 + 600 510.29713 -196148.37 0.76796752 8 3 5 + 700 494.14346 -118517.45 0.76796752 8 3 6 + 800 565.62849 7678.1235 0.76796752 8 3 6 + 900 515.74468 554.84571 0.76796752 8 3 6 + 1000 500.64636 450.15932 0.76796752 8 3 6 + 1100 463.34973 6023.8346 0.76796752 8 3 6 + 1200 529.88483 2748.185 0.76796752 8 3 6 + 1300 546.84049 1353.4891 0.76796752 8 3 6 + 1400 552.27356 1446.5807 0.76796752 8 3 6 + 1500 557.70874 -2745.1523 0.76796752 8 3 6 + 1600 572.0005 629.36722 0.76796752 8 3 6 + 1700 503.96569 5937.0231 0.76796752 8 3 6 + 1800 491.34262 -1175.8104 0.76796752 8 3 6 + 1900 538.24798 -81.197397 0.76796752 8 3 6 + 2000 523.89324 2857.2466 0.76796752 8 3 6 + 2100 515.1424 2288.2405 0.76796752 8 3 6 + 2200 546.80854 3807.1038 0.76796752 8 3 6 + 2300 500.31231 -135.33933 0.76796752 8 4 6 + 2400 497.16354 5516.857 0.76796752 8 4 6 + 2500 545.34187 3485.5645 0.76796752 8 4 6 + 2600 522.70122 3114.1284 0.76796752 8 4 6 + 2700 531.76604 6633.5518 0.76796752 8 4 6 + 2800 521.97643 -279.83682 0.76796752 8 4 6 + 2900 497.29575 7052.9409 0.76796752 8 4 6 + 3000 524.5942 2284.8918 0.76796752 8 4 6 + 3100 567.61329 -3667.4557 0.76796752 8 4 6 + 3200 506.82452 -2934.4936 0.76796752 8 4 6 + 3300 510.8521 313.36263 0.76796752 8 4 6 + 3400 516.70206 3671.1899 0.76796752 8 4 6 + 3500 535.12788 2645.2564 0.76796752 8 4 6 + 3600 580.14214 2604.3079 0.76796752 8 4 6 + 3700 529.77869 2684.0812 0.76796752 8 4 6 + 3800 502.93191 2838.6698 0.76796752 8 4 6 + 3900 585.91492 5308.0828 0.76796752 8 4 6 + 4000 548.89917 5262.5775 0.76796752 8 4 6 + 4100 550.7662 -1066.6807 0.76796752 8 4 6 + 4200 519.19198 2777.5276 0.76796752 8 4 6 + 4300 521.46332 -3429.7171 0.76796752 8 4 6 + 4400 532.64173 2301.3135 0.76796752 8 4 6 + 4500 528.96107 1369.0991 0.76796752 8 4 6 + 4600 564.66443 9687.2531 0.76796752 8 4 6 + 4700 558.49446 2322.6085 0.76796752 8 4 6 + 4800 497.78614 -442.45053 0.76796752 8 4 6 + 4900 511.09435 -10251.159 0.76796752 8 4 6 + 5000 525.6642 -1202.0584 0.76796752 8 4 6 + 5100 521.76974 1821.7811 0.76796752 8 4 6 + 5200 555.9859 7256.9632 0.76796752 8 4 6 + 5300 551.51971 -122893.16 0.76796752 8 4 7 + 5400 524.34705 2905.1033 0.76796752 8 4 7 + 5500 567.09396 2896.4824 0.76796752 8 4 7 + 5600 487.57746 1417.1715 0.76796752 8 4 7 + 5700 547.37304 3900.8734 0.76796752 8 4 7 + 5800 536.17647 -4048.7522 0.76796752 8 4 7 + 5900 536.85051 4497.9847 0.76796752 8 4 7 + 6000 548.58212 -4880.4979 0.76796752 8 4 7 + 6100 500.94692 6004.2105 0.76796752 8 4 7 + 6200 486.82494 402.5875 0.76796752 8 4 7 + 6300 478.09381 6600.767 0.76796752 8 4 7 + 6400 559.90398 2868.0805 0.76796752 8 4 7 + 6500 526.01866 -3398.4788 0.76796752 8 4 7 + 6600 539.68471 -1202.0012 0.76796752 8 4 7 + 6700 507.51217 -378.71164 0.76796752 8 4 7 + 6800 526.15958 -4536.9888 0.76796752 8 4 7 + 6900 511.37134 -2522.3553 0.76796752 8 4 7 + 7000 538.86918 -2028.0323 0.76796752 8 4 7 + 7100 523.25566 2911.9962 0.76796752 8 4 7 + 7200 513.28464 -1000.4758 0.76796752 8 4 7 + 7300 510.19826 5181.7976 0.76796752 8 4 7 + 7400 493.46528 -1166.3996 0.76796752 8 4 7 + 7500 491.51305 5669.2213 0.76796752 8 4 7 + 7600 506.72032 -2840.301 0.76796752 8 4 7 + 7700 513.4319 2802.1719 0.76796752 8 4 7 + 7800 543.7658 -7477.3623 0.76796752 8 4 7 + 7900 527.35619 -3182.3155 0.76796752 8 4 7 + 8000 533.50993 613.16561 0.76796752 8 4 7 + 8100 512.44958 -5037.3414 0.76796752 8 4 7 + 8200 494.88981 1799.3513 0.76796752 8 4 7 + 8300 554.81474 -2436.0507 0.76796752 8 4 7 + 8400 523.22917 364.30593 0.76796752 8 4 7 + 8500 515.12395 525.24581 0.76796752 8 4 7 + 8600 511.6321 -1679.8669 0.76796752 8 4 7 + 8700 531.6327 -1168.1215 0.76796752 8 4 7 + 8800 548.14438 -5222.7573 0.76796752 8 4 7 + 8900 517.72579 2073.9695 0.76796752 8 4 7 + 9000 543.11894 -5307.0759 0.76796752 8 4 7 + 9100 521.13747 -5546.8552 0.76796752 8 4 7 + 9200 509.66142 -1584.019 0.76796752 8 4 7 + 9300 488.73821 -277.85847 0.76796752 8 4 7 + 9400 513.67282 989.60653 0.76796752 8 4 7 + 9500 509.98833 -1754.8786 0.76796752 8 4 7 + 9600 558.72497 5616.6969 0.76796752 8 4 7 + 9700 533.74988 811.48871 0.76796752 8 4 7 + 9800 510.94641 -3136.5876 0.76796752 8 4 7 + 9900 517.80127 -1962.0837 0.76796752 8 4 7 + 10000 477.50428 -3768.1653 0.76796752 8 4 7 +Loop time of 20.9963 on 4 procs for 10000 steps with 320 atoms + +Performance: 41.150 ns/day, 0.583 hours/ns, 476.276 timesteps/s +100.0% CPU use with 4 MPI tasks x no OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 2.4968 | 3.0329 | 3.3607 | 18.6 | 14.45 +Bond | 2.3164 | 2.8835 | 3.456 | 26.0 | 13.73 +Kspace | 1.3332 | 2.2082 | 3.285 | 48.0 | 10.52 +Neigh | 7.4831 | 7.4922 | 7.5012 | 0.3 | 35.68 +Comm | 1.2809 | 1.3121 | 1.3297 | 1.6 | 6.25 +Output | 0.0012138 | 0.0013506 | 0.0017552 | 0.6 | 0.01 +Modify | 4.0269 | 4.0301 | 4.0335 | 0.1 | 19.19 +Other | | 0.03583 | | | 0.17 + +Nlocal: 80 ave 94 max 66 min +Histogram: 2 0 0 0 0 0 0 0 0 2 +Nghost: 2243.75 ave 2260 max 2221 min +Histogram: 1 0 0 1 0 0 0 0 0 2 +Neighs: 13658.5 ave 17096 max 9421 min +Histogram: 1 0 0 0 0 1 1 0 0 1 + +Total # of neighbors = 54634 +Ave neighs/atom = 170.731 +Ave special neighs/atom = 11.3063 +Neighbor list builds = 10000 +Dangerous builds = 0 +System init for write_data ... +PPPM initialization ... + using 12-bit tables for long-range coulomb (../kspace.cpp:323) + G vector (1/distance) = 0.255611 + grid = 6 6 6 + stencil order = 5 + estimated absolute RMS force accuracy = 0.00974692 + estimated relative force accuracy = 2.93525e-05 + using double precision FFTs + 3d grid and FFT values/proc = 704 72 + +Please see the log.cite file for references relevant to this simulation + +Total wall time: 0:00:21 diff --git a/examples/USER/misc/bond_react/tiny_polystyrene/tiny_polystyrene.data b/examples/USER/misc/bond_react/tiny_polystyrene/tiny_polystyrene.data new file mode 100644 index 0000000000..5f0ed4cfa6 --- /dev/null +++ b/examples/USER/misc/bond_react/tiny_polystyrene/tiny_polystyrene.data @@ -0,0 +1,2643 @@ +LAMMPS data file via write_data, version 20 Nov 2019, timestep = 25000 + +320 atoms +7 atom types +320 bonds +13 bond types +480 angles +22 angle types +640 dihedrals +36 dihedral types +160 impropers +9 improper types + +1.7426663385337786e+00 1.8257333661465619e+01 xlo xhi +1.7426663385337786e+00 1.8257333661465619e+01 ylo yhi +1.7426663385337786e+00 1.8257333661465619e+01 zlo zhi + +Masses + +1 12.0112 +2 1.00797 +3 12.0112 +4 12.0112 +5 12.0112 +6 12.0112 +7 12.0112 + +Pair Coeffs # lj/class2/coul/long + +1 0.064 4.01 +2 0.02 2.7 +3 0.064 4.01 +4 0.064 3.9 +5 0.054 4.01 +6 0.054 4.01 +7 0.054 4.01 + +Bond Coeffs # class2 + +1 1.0982 372.825 -803.453 894.317 +2 1.417 470.836 -627.618 1327.63 +3 1.501 321.902 -521.821 572.163 +4 1.0883 365.768 -725.54 781.662 +5 1.34 543.99 -1238.2 1644.03 +6 1.0883 365.768 -725.54 781.662 +7 1.501 321.902 -521.821 572.163 +8 1.101 345 -691.89 844.6 +9 1.53 299.67 -501.77 679.81 +10 1.101 345 -691.89 844.6 +11 1.501 321.902 -521.821 572.163 +12 1.101 345 -691.89 844.6 +13 1.53 299.67 -501.77 679.81 + +Angle Coeffs # class2 + +1 117.94 35.1558 -12.4682 0 +2 118.9 61.0226 -34.9931 0 +3 120.05 44.7148 -22.7352 0 +4 111 44.3234 -9.4454 0 +5 108.4 43.9594 -8.3924 -9.3379 +6 124.88 35.2766 -17.774 -1.6215 +7 124.88 35.2766 -17.774 -1.6215 +8 115.49 29.6363 -12.4853 -6.2218 +9 120.05 44.7148 -22.7352 0 +10 111 44.3234 -9.4454 0 +11 108.4 43.9594 -8.3924 -9.3379 +12 110.77 41.453 -10.604 5.129 +13 112.67 39.516 -7.443 -9.5583 +14 110.77 41.453 -10.604 5.129 +15 107.66 39.641 -12.921 -2.4318 +16 112.67 39.516 -7.443 -9.5583 +17 120.05 44.7148 -22.7352 0 +18 111 44.3234 -9.4454 0 +19 108.4 43.9594 -8.3924 -9.3379 +20 110.77 41.453 -10.604 5.129 +21 110.77 41.453 -10.604 5.129 +22 112.67 39.516 -7.443 -9.5583 + +BondBond Coeffs + +1 1.0795 1.417 1.0982 +2 68.2856 1.417 1.417 +3 12.0676 1.417 1.501 +4 2.9168 1.501 1.0883 +5 0 1.501 1.34 +6 10.1047 1.0883 1.34 +7 10.1047 1.0883 1.34 +8 4.8506 1.0883 1.0883 +9 12.0676 1.417 1.501 +10 2.9168 1.501 1.101 +11 0 1.501 1.53 +12 3.3872 1.101 1.53 +13 0 1.53 1.53 +14 3.3872 1.101 1.53 +15 5.3316 1.101 1.101 +16 0 1.53 1.53 +17 12.0676 1.417 1.501 +18 2.9168 1.501 1.101 +19 0 1.501 1.53 +20 3.3872 1.101 1.53 +21 3.3872 1.101 1.53 +22 0 1.53 1.53 + +BondAngle Coeffs + +1 20.0033 24.2183 1.417 1.0982 +2 28.8708 28.8708 1.417 1.417 +3 31.0771 47.0579 1.417 1.501 +4 26.4608 11.7717 1.501 1.0883 +5 0 0 1.501 1.34 +6 19.0592 23.3588 1.0883 1.34 +7 19.0592 23.3588 1.0883 1.34 +8 17.9795 17.9795 1.0883 1.0883 +9 31.0771 47.0579 1.417 1.501 +10 26.4608 11.7717 1.501 1.101 +11 0 0 1.501 1.53 +12 11.421 20.754 1.101 1.53 +13 8.016 8.016 1.53 1.53 +14 11.421 20.754 1.101 1.53 +15 18.103 18.103 1.101 1.101 +16 8.016 8.016 1.53 1.53 +17 31.0771 47.0579 1.417 1.501 +18 26.4608 11.7717 1.501 1.101 +19 0 0 1.501 1.53 +20 11.421 20.754 1.101 1.53 +21 11.421 20.754 1.101 1.53 +22 8.016 8.016 1.53 1.53 + +Dihedral Coeffs # class2 + +1 0 0 1.559 0 0 0 +2 0 0 3.9661 0 0 0 +3 0 0 4.4072 0 0 0 +4 8.3667 0 1.1932 0 0 0 +5 0 0 1.8769 0 0 0 +6 0 0 0 0 0 0 +7 0 0 0 0 0 0 +8 0 0 0 0 0 0 +9 0 0 4.8974 0 0 0 +10 0 0 1.559 0 0 0 +11 0 0 4.4072 0 0 0 +12 -0.2801 0 -0.0678 0 -0.0122 0 +13 -0.2802 0 -0.0678 0 -0.0122 0 +14 -0.0228 0 0.028 0 -0.1863 0 +15 -0.1432 0 0.0617 0 -0.1083 0 +16 0 0 0.0316 0 -0.1681 0 +17 0 0 0 0 0 0 +18 0 0 0.0316 0 -0.1681 0 +19 0 0 0.0514 0 -0.143 0 +20 0 0 1.559 0 0 0 +21 0 0 4.4072 0 0 0 +22 -0.2801 0 -0.0678 0 -0.0122 0 +23 -0.2802 0 -0.0678 0 -0.0122 0 +24 -0.0228 0 0.028 0 -0.1863 0 +25 0 0 0 0 0 0 +26 -0.1432 0 0.0617 0 -0.1083 0 +27 0 0 0.0316 0 -0.1681 0 +28 0 0 0 0 0 0 +29 0 0 0.0316 0 -0.1681 0 +30 0 0 0.0514 0 -0.143 0 +31 -0.0228 0 0.028 0 -0.1863 0 +32 -0.1432 0 0.0617 0 -0.1083 0 +33 0 0 0.0316 0 -0.1681 0 +34 0 0 0 0 0 0 +35 0 0 0.0316 0 -0.1681 0 +36 0 0 0.0514 0 -0.143 0 + +AngleAngleTorsion Coeffs + +1 4.4444 117.94 120.05 +2 -4.8141 118.9 117.94 +3 -14.4097 118.9 120.05 +4 0 118.9 118.9 +5 0.3598 117.94 117.94 +6 0 120.05 111 +7 0 120.05 108.4 +8 0 108.4 124.88 +9 -7.0058 124.88 124.88 +10 4.4444 117.94 120.05 +11 -14.4097 118.9 120.05 +12 -5.8888 120.05 111 +13 0 120.05 108.4 +14 0 108.4 110.77 +15 -12.564 110.77 110.77 +16 -16.164 112.67 110.77 +17 0 108.4 112.67 +18 -16.164 110.77 112.67 +19 -22.045 112.67 112.67 +20 4.4444 117.94 120.05 +21 -14.4097 118.9 120.05 +22 -5.8888 120.05 111 +23 0 120.05 108.4 +24 0 108.4 110.77 +25 0 108.4 112.67 +26 -12.564 110.77 110.77 +27 -16.164 110.77 112.67 +28 0 112.67 108.4 +29 -16.164 112.67 110.77 +30 -22.045 112.67 112.67 +31 0 110.77 108.4 +32 -12.564 110.77 110.77 +33 -16.164 110.77 112.67 +34 0 112.67 108.4 +35 -16.164 112.67 110.77 +36 -22.045 112.67 112.67 + +EndBondTorsion Coeffs + +1 0 -0.4879 0 0 -1.797 0 1.0982 1.501 +2 0 -6.8958 0 0 -0.4669 0 1.417 1.0982 +3 0 -0.6918 0 0 0.2421 0 1.417 1.501 +4 -0.1185 6.3204 0 -0.1185 6.3204 0 1.417 1.417 +5 0 -0.689 0 0 -0.689 0 1.0982 1.0982 +6 0 0 0 0 0 0 1.417 1.0883 +7 0 0 0 0 0 0 1.417 1.34 +8 0 0 0 0 0 0 1.501 1.0883 +9 0.7129 0.5161 0 0.7129 0.5161 0 1.0883 1.0883 +10 0 -0.4879 0 0 -1.797 0 1.0982 1.501 +11 0 -0.6918 0 0 0.2421 0 1.417 1.501 +12 -0.5835 1.122 0.3978 1.3997 0.7756 0 1.417 1.101 +13 0 0 0 0 0 0 1.417 1.53 +14 0 0 0 0 0 0 1.501 1.101 +15 0.213 0.312 0.0777 0.213 0.312 0.0777 1.101 1.101 +16 0.2486 0.2422 -0.0925 0.0814 0.0591 0.2219 1.53 1.101 +17 0 0 0 0 0 0 1.501 1.53 +18 0.0814 0.0591 0.2219 0.2486 0.2422 -0.0925 1.101 1.53 +19 -0.0732 0 0 -0.0732 0 0 1.53 1.53 +20 0 -0.4879 0 0 -1.797 0 1.0982 1.501 +21 0 -0.6918 0 0 0.2421 0 1.417 1.501 +22 -0.5835 1.122 0.3978 1.3997 0.7756 0 1.417 1.101 +23 0 0 0 0 0 0 1.417 1.53 +24 0 0 0 0 0 0 1.501 1.101 +25 0 0 0 0 0 0 1.501 1.53 +26 0.213 0.312 0.0777 0.213 0.312 0.0777 1.101 1.101 +27 0.0814 0.0591 0.2219 0.2486 0.2422 -0.0925 1.101 1.53 +28 0 0 0 0 0 0 1.53 1.501 +29 0.2486 0.2422 -0.0925 0.0814 0.0591 0.2219 1.53 1.101 +30 -0.0732 0 0 -0.0732 0 0 1.53 1.53 +31 0 0 0 0 0 0 1.101 1.501 +32 0.213 0.312 0.0777 0.213 0.312 0.0777 1.101 1.101 +33 0.0814 0.0591 0.2219 0.2486 0.2422 -0.0925 1.101 1.53 +34 0 0 0 0 0 0 1.53 1.501 +35 0.2486 0.2422 -0.0925 0.0814 0.0591 0.2219 1.53 1.101 +36 -0.0732 0 0 -0.0732 0 0 1.53 1.53 + +MiddleBondTorsion Coeffs + +1 0 3.9421 0 1.417 +2 0 -1.1521 0 1.417 +3 0 9.1792 0 1.417 +4 27.5989 -2.312 0 1.417 +5 0 4.8228 0 1.417 +6 0 0 0 1.501 +7 0 0 0 1.501 +8 0 0 0 1.34 +9 0.8558 6.3911 0 1.34 +10 0 3.9421 0 1.417 +11 0 9.1792 0 1.417 +12 -5.5679 1.4083 0.301 1.501 +13 0 0 0 1.501 +14 0 0 0 1.53 +15 -14.261 -0.5322 -0.4864 1.53 +16 -14.879 -3.6581 -0.3138 1.53 +17 0 0 0 1.53 +18 -14.879 -3.6581 -0.3138 1.53 +19 -17.787 -7.1877 0 1.53 +20 0 3.9421 0 1.417 +21 0 9.1792 0 1.417 +22 -5.5679 1.4083 0.301 1.501 +23 0 0 0 1.501 +24 0 0 0 1.53 +25 0 0 0 1.53 +26 -14.261 -0.5322 -0.4864 1.53 +27 -14.879 -3.6581 -0.3138 1.53 +28 0 0 0 1.53 +29 -14.879 -3.6581 -0.3138 1.53 +30 -17.787 -7.1877 0 1.53 +31 0 0 0 1.53 +32 -14.261 -0.5322 -0.4864 1.53 +33 -14.879 -3.6581 -0.3138 1.53 +34 0 0 0 1.53 +35 -14.879 -3.6581 -0.3138 1.53 +36 -17.787 -7.1877 0 1.53 + +BondBond13 Coeffs + +1 0.8743 1.0982 1.501 +2 -6.2741 1.417 1.0982 +3 2.5085 1.417 1.501 +4 53 1.417 1.417 +5 -1.7077 1.0982 1.0982 +6 0 1.417 1.0883 +7 0 1.417 1.34 +8 0 1.501 1.0883 +9 0 1.0883 1.0883 +10 0.8743 1.0982 1.501 +11 2.5085 1.417 1.501 +12 -3.4826 1.417 1.101 +13 0 1.417 1.53 +14 0 1.501 1.101 +15 0 1.101 1.101 +16 0 1.53 1.101 +17 0 1.501 1.53 +18 0 1.101 1.53 +19 0 1.53 1.53 +20 0.8743 1.0982 1.501 +21 2.5085 1.417 1.501 +22 -3.4826 1.417 1.101 +23 0 1.417 1.53 +24 0 1.501 1.101 +25 0 1.501 1.53 +26 0 1.101 1.101 +27 0 1.101 1.53 +28 0 1.53 1.501 +29 0 1.53 1.101 +30 0 1.53 1.53 +31 0 1.101 1.501 +32 0 1.101 1.101 +33 0 1.101 1.53 +34 0 1.53 1.501 +35 0 1.53 1.101 +36 0 1.53 1.53 + +AngleTorsion Coeffs + +1 0 3.4601 0 0 -0.1242 0 117.94 120.05 +2 0 2.5014 0 0 2.7147 0 118.9 117.94 +3 0 3.8987 0 0 -4.4683 0 118.9 120.05 +4 1.9767 1.0239 0 1.9767 1.0239 0 118.9 118.9 +5 0 2.4501 0 0 2.4501 0 117.94 117.94 +6 0 0 0 0 0 0 120.05 111 +7 0 0 0 0 0 0 120.05 108.4 +8 0 0 0 0 0 0 108.4 124.88 +9 -1.8911 3.254 0 -1.8911 3.254 0 124.88 124.88 +10 0 3.4601 0 0 -0.1242 0 117.94 120.05 +11 0 3.8987 0 0 -4.4683 0 118.9 120.05 +12 0.2251 0.6548 0.1237 4.6266 0.1632 0.0461 120.05 111 +13 0 0 0 0 0 0 120.05 108.4 +14 0 0 0 0 0 0 108.4 110.77 +15 -0.8085 0.5569 -0.2466 -0.8085 0.5569 -0.2466 110.77 110.77 +16 -0.2454 0 -0.1136 0.3113 0.4516 -0.1988 112.67 110.77 +17 0 0 0 0 0 0 108.4 112.67 +18 0.3113 0.4516 -0.1988 -0.2454 0 -0.1136 110.77 112.67 +19 0.3886 -0.3139 0.1389 0.3886 -0.3139 0.1389 112.67 112.67 +20 0 3.4601 0 0 -0.1242 0 117.94 120.05 +21 0 3.8987 0 0 -4.4683 0 118.9 120.05 +22 0.2251 0.6548 0.1237 4.6266 0.1632 0.0461 120.05 111 +23 0 0 0 0 0 0 120.05 108.4 +24 0 0 0 0 0 0 108.4 110.77 +25 0 0 0 0 0 0 108.4 112.67 +26 -0.8085 0.5569 -0.2466 -0.8085 0.5569 -0.2466 110.77 110.77 +27 0.3113 0.4516 -0.1988 -0.2454 0 -0.1136 110.77 112.67 +28 0 0 0 0 0 0 112.67 108.4 +29 -0.2454 0 -0.1136 0.3113 0.4516 -0.1988 112.67 110.77 +30 0.3886 -0.3139 0.1389 0.3886 -0.3139 0.1389 112.67 112.67 +31 0 0 0 0 0 0 110.77 108.4 +32 -0.8085 0.5569 -0.2466 -0.8085 0.5569 -0.2466 110.77 110.77 +33 0.3113 0.4516 -0.1988 -0.2454 0 -0.1136 110.77 112.67 +34 0 0 0 0 0 0 112.67 108.4 +35 -0.2454 0 -0.1136 0.3113 0.4516 -0.1988 112.67 110.77 +36 0.3886 -0.3139 0.1389 0.3886 -0.3139 0.1389 112.67 112.67 + +Improper Coeffs # class2 + +1 4.8912 0 +2 7.8153 0 +3 0 0 +4 2.8561 0 +5 7.8153 0 +6 0 0 +7 0 0 +8 7.8153 0 +9 0 0 + +AngleAngle Coeffs + +1 0 0 0 118.9 117.94 117.94 +2 0 0 0 118.9 120.05 120.05 +3 0 0 0 111 124.88 108.4 +4 0 0 0 115.49 124.88 124.88 +5 0 0 0 118.9 120.05 120.05 +6 0 0 0 107.66 110.77 110.77 +7 0 0 0 111 110.77 108.4 +8 0 0 0 118.9 120.05 120.05 +9 0 0 0 111 110.77 108.4 + +Atoms # full + +40602 2538 2 1.2880000000000000e-01 3.3609401967585955e+00 4.4067042595247594e+00 1.7652703015153694e+01 0 1 -1 +111366 6961 2 1.2370000000000000e-01 2.5287450867535228e+00 3.4595752969959102e+00 5.5197750474116489e+00 0 0 0 +111365 6961 1 -1.2900000000000000e-01 2.2477552210789034e+00 4.1940380679220048e+00 6.2531010916436118e+00 0 0 0 +111364 6961 3 -1.8200000000000001e-02 4.6534606713809783e+00 4.0872493335204627e+00 6.6406706800933657e+00 0 0 0 +111373 6961 2 5.1600000000000000e-02 4.7065862756318362e+00 3.1388066541018711e+00 7.1483388517476536e+00 0 0 0 +107224 6702 2 1.4030000000000001e-01 4.3747823735813256e+00 6.6777036283374303e+00 1.8126826734147052e+01 1 0 -1 +107223 6702 1 -1.7340000000000000e-01 3.3819489105921479e+00 7.1051571061898393e+00 1.9476793708830493e+00 1 0 0 +40599 2538 1 -1.7340000000000000e-01 1.7897991574638404e+01 3.7109360216682128e+00 1.7502909648810935e+01 -1 1 -1 +40600 2538 2 1.4030000000000001e-01 1.7761669662555619e+01 4.2961185209612616e+00 1.6631333893439564e+01 -1 1 -1 +41356 2585 2 1.4030000000000001e-01 5.9156631480771527e+00 1.0478394367195754e+01 8.3875585503933614e+00 0 1 1 +107222 6702 2 1.2370000000000000e-01 3.6715671896819093e+00 6.6024431064152225e+00 4.0510480747089339e+00 1 0 0 +40597 2538 1 -1.2900000000000000e-01 1.6955889539378134e+01 2.7829267678458436e+00 1.7962156465993502e+01 -1 1 -1 +40598 2538 2 1.2370000000000000e-01 1.5942867471528109e+01 2.6001610609395129e+00 1.7514042185813334e+01 -1 1 -1 +111367 6961 1 -1.7340000000000000e-01 1.7495745294265745e+01 4.6877369518904199e+00 6.4410612543144401e+00 -1 0 0 +111368 6961 2 1.4030000000000001e-01 1.6684286240405104e+01 4.1990863000633958e+00 5.8354395711206708e+00 -1 0 0 +188723 11796 1 2.6599999999999999e-02 1.2794445780805036e+01 4.8153878517226305e+00 2.8366538199234208e+00 0 2 0 +188726 11796 2 1.2370000000000000e-01 1.1307621657711582e+01 6.0648965933332004e+00 3.8852435658831435e+00 0 2 0 +188736 11796 2 3.5400000000000001e-02 1.0942691320187310e+01 2.8660493976532067e+00 3.6592390992421064e+00 0 2 0 +41360 2585 2 3.5400000000000001e-02 8.5172276274172862e+00 6.6772583543717241e+00 4.6258553568569134e+00 0 1 1 +111375 6961 2 3.5400000000000001e-02 5.1160863341697551e+00 3.1557498302500560e+00 4.8281676316055648e+00 0 0 0 +41346 2585 2 1.2370000000000000e-01 5.2803967127973479e+00 8.3738447196883783e+00 7.1113512659172891e+00 0 1 1 +41359 2585 2 3.5400000000000001e-02 7.0805979681390792e+00 5.5480506789621362e+00 4.1107885168230087e+00 0 1 1 +188725 11796 1 -1.2900000000000000e-01 1.2408079703909788e+01 5.7336269491919198e+00 3.7349335138244366e+00 0 2 0 +188729 11796 1 -1.1340000000000000e-01 1.4703709315154203e+01 6.4426943408965585e+00 4.1248777022829106e+00 0 2 0 +188727 11796 1 -1.7340000000000000e-01 1.3333557950108901e+01 6.5153791380185462e+00 4.4423297264254140e+00 0 2 0 +20158 1260 4 -6.9599999999999995e-02 1.3854962450513005e+01 1.7558158358296474e+01 6.0985091703687049e+00 -1 0 0 +20160 1260 2 3.5400000000000001e-02 1.2918711114031632e+01 1.7814458238382855e+01 5.7425825995785100e+00 -1 0 0 +20148 1260 3 -1.8200000000000001e-02 1.4873275896132416e+01 1.9084526466056861e+00 6.2828310713786459e+00 -1 1 0 +188728 11796 2 1.4030000000000001e-01 1.2869094657766244e+01 7.2098256594356229e+00 5.1535483885770113e+00 0 2 0 +20157 1260 2 5.1600000000000000e-02 1.5744980877568938e+01 1.8128011607429414e+01 6.7646315462574487e+00 -1 0 0 +188730 11796 2 1.2880000000000000e-01 1.5413809605693494e+01 7.1215792753373064e+00 4.6045554272301157e+00 0 2 0 +41355 2585 1 -1.7340000000000000e-01 6.6267551131373832e+00 1.0027638223239382e+01 7.7182869694089700e+00 0 1 1 +108389 6775 1 -1.2900000000000000e-01 7.0133566713184710e+00 1.1863505693448808e+01 3.0100421026579314e+00 0 0 1 +41327 2583 2 3.5400000000000001e-02 1.8025151826355874e+01 1.5680601368303122e+01 5.4799644916431216e+00 -1 0 1 +41326 2583 4 -6.9599999999999995e-02 2.5704711045235697e+00 1.5575122040069637e+01 5.4065270673139985e+00 0 0 1 +41328 2583 2 3.5400000000000001e-02 2.9997429592273956e+00 1.4685386861680085e+01 4.9759285267091098e+00 0 0 1 +108390 6775 2 1.2370000000000000e-01 6.9836751439323628e+00 1.0846526933351964e+01 3.4784800869303512e+00 0 0 1 +108391 6775 1 -1.7340000000000000e-01 6.8087445208925681e+00 1.3003486840032258e+01 3.7761607679871307e+00 0 0 1 +41353 2585 1 -1.1340000000000000e-01 7.8573883366696089e+00 1.0627162455737775e+01 7.3859043657940493e+00 0 1 1 +41351 2585 1 -1.7340000000000000e-01 8.6981014387032438e+00 1.0201900398046481e+01 6.3533593539380941e+00 0 1 1 +107221 6702 1 -1.2900000000000000e-01 3.1758840802872599e+00 7.1678179098614141e+00 3.2854613341877181e+00 1 0 0 +107219 6702 1 2.6599999999999999e-02 2.0748866096178964e+00 7.9461425898687992e+00 3.7753484383081610e+00 1 0 0 +107232 6702 2 3.5400000000000001e-02 1.7648721744994319e+01 1.0103122840036239e+01 4.7798275704340671e+00 0 0 0 +108392 6775 2 1.4030000000000001e-01 6.3995996961287833e+00 1.2731343992705472e+01 4.7487947462305771e+00 0 0 1 +41354 2585 2 1.2880000000000000e-01 8.1692015925027768e+00 1.1493632013886158e+01 7.9544056830537269e+00 0 1 1 +69384 4337 2 1.4030000000000001e-01 1.2507275934560081e+01 9.2207766533505673e+00 7.3246588169625140e+00 0 1 1 +41345 2585 1 -1.2900000000000000e-01 6.3195931272585391e+00 8.8692855685170500e+00 6.9676292860762716e+00 0 1 1 +41347 2585 1 2.6599999999999999e-02 7.0702614826346544e+00 8.4743337141795241e+00 5.8547594819621187e+00 0 1 1 +41357 2585 2 5.1600000000000000e-02 5.5016574767426301e+00 7.4706228475946332e+00 4.6418688283853040e+00 0 1 1 +41358 2585 4 -6.9599999999999995e-02 7.4737228534116324e+00 6.4899475004190332e+00 4.5180419190464987e+00 0 1 1 +41348 2585 3 -1.8200000000000001e-02 6.6062265756796981e+00 7.5175310927852941e+00 4.7713364455934872e+00 0 1 1 +41349 2585 1 -1.2900000000000000e-01 8.2441070780215853e+00 9.1470326477281088e+00 5.5160478380515663e+00 0 1 1 +41350 2585 2 1.2370000000000000e-01 8.8604728777063109e+00 8.8987664442336971e+00 4.6534059979647555e+00 0 1 1 +69382 4337 2 1.2370000000000000e-01 1.2037994406712755e+01 1.1438693923544918e+01 6.6961121531796941e+00 0 1 1 +108400 6775 2 3.5400000000000001e-02 9.4434155310323717e+00 1.0779831061177935e+01 1.7308995238384654e+01 0 0 0 +107220 6702 3 -1.8200000000000001e-02 1.8511457716678090e+00 8.2067707732304527e+00 5.1884876711911101e+00 1 0 0 +107229 6702 2 5.1600000000000000e-02 2.3229493400774794e+00 7.4350000572163024e+00 5.7660915302438154e+00 1 0 0 +65551 4097 2 3.5400000000000001e-02 1.8064251645249804e+01 1.2963289176981608e+01 5.4842508762037534e+00 0 0 0 +107230 6702 4 -6.9599999999999995e-02 1.8228240499767143e+00 9.5598483570416146e+00 5.3379848839478363e+00 1 0 0 +107231 6702 2 3.5400000000000001e-02 2.5955528839673567e+00 1.0106560918497969e+01 5.9757939945393543e+00 1 0 0 +148088 9256 2 1.4030000000000001e-01 1.1762030797439378e+01 1.1693785579271282e+01 4.4638937261529295e+00 0 0 1 +148090 9256 2 1.2880000000000000e-01 1.4099636105822544e+01 1.2327433192859456e+01 4.0225129791140546e+00 0 0 1 +148087 9256 1 -1.7340000000000000e-01 1.1979028403125646e+01 1.2633659013855903e+01 3.9376689709327510e+00 0 0 1 +148089 9256 1 -1.1340000000000000e-01 1.3280445370302795e+01 1.3014281950759539e+01 3.7240436336308522e+00 0 0 1 +40604 2538 2 1.4030000000000001e-01 4.0250594599637042e+00 2.7167655841048841e+00 2.9671010133230107e+00 0 1 0 +40603 2538 1 -1.7340000000000000e-01 2.9715213077297893e+00 2.8387700187263976e+00 2.6496011286331638e+00 0 1 0 +40601 2538 1 -1.1340000000000000e-01 2.6436717484652190e+00 3.7161784029911313e+00 1.8118381074995945e+01 0 1 -1 +41314 2583 2 1.2370000000000000e-01 6.1655197061189391e+00 1.6429093178302054e+01 5.2634660717283719e+00 0 0 1 +40594 2538 2 1.2370000000000000e-01 2.3106168557244260e+00 1.7574548555023910e+01 3.6114577101537471e+00 0 0 0 +40593 2538 1 -1.2900000000000000e-01 2.0192147877585960e+00 1.8971927062618956e+00 2.9622660579545812e+00 0 1 0 +40595 2538 1 2.6599999999999999e-02 1.7291779626197169e+01 1.8599578675608062e+00 2.3904540665275351e+00 -1 1 0 +41316 2583 3 -1.8200000000000001e-02 3.4212771996318807e+00 1.6520636908143409e+01 5.7386914040715045e+00 0 0 1 +108393 6775 1 -1.1340000000000000e-01 6.6499881779146026e+00 1.4259117018515532e+01 3.0584002634074370e+00 0 0 1 +108394 6775 2 1.2880000000000000e-01 6.1964048810474663e+00 1.5224374946621646e+01 3.4935080873808033e+00 0 0 1 +41313 2583 1 -1.2900000000000000e-01 5.8827015465618375e+00 1.5865587321912503e+01 6.1431437364315027e+00 0 0 1 +108395 6775 1 -1.7340000000000000e-01 7.1097892289262878e+00 1.4350613194723607e+01 1.7470717630973838e+00 0 0 1 +108396 6775 2 1.4030000000000001e-01 6.9903337205295530e+00 1.5224750453488815e+01 1.7644673266894884e+01 0 0 0 +148096 9256 2 3.5400000000000001e-02 1.0752335098968890e+01 1.7218144880618222e+01 3.5500932917187793e+00 0 0 1 +148095 9256 2 3.5400000000000001e-02 1.0359671951490158e+01 1.7522361890554926e+01 1.8218190609141388e+01 0 0 0 +148094 9256 4 -6.9599999999999995e-02 1.0424710670624640e+01 1.6814346694132169e+01 2.5033401382466907e+00 0 0 1 +40608 2538 2 3.5400000000000001e-02 1.6659811918729936e+01 1.5824060712051581e+01 1.7856371334575492e+01 -1 0 -1 +40607 2538 2 3.5400000000000001e-02 1.7068652155067138e+01 1.5312925579361091e+01 3.0807371681198257e+00 -1 0 0 +40605 2538 2 5.1600000000000000e-02 1.6526035362495449e+01 1.7247373568378688e+01 3.9930857730966038e+00 -1 0 0 +40606 2538 4 -6.9599999999999995e-02 1.6690607482896461e+01 1.6080613680347298e+01 2.3857659847545456e+00 -1 0 0 +40596 2538 3 -1.8200000000000001e-02 1.6426787646343708e+01 1.7312070439154404e+01 2.8996717936988108e+00 -1 0 0 +148093 9256 2 5.1600000000000000e-02 9.7084895751228579e+00 1.5206903985177071e+01 1.7929781969852563e+01 0 0 0 +148084 9256 3 -1.8200000000000001e-02 1.0037261004726227e+01 1.5553915685523059e+01 2.3820334888623931e+00 0 0 1 +148086 9256 2 1.2370000000000000e-01 9.8538164885967223e+00 1.3122374408103786e+01 3.7386171094020604e+00 0 0 1 +148085 9256 1 -1.2900000000000000e-01 1.0915815138831038e+01 1.3468093486840369e+01 3.5699140224340207e+00 0 0 1 +148083 9256 1 2.6599999999999999e-02 1.1127532644580404e+01 1.4687297959113698e+01 2.8927936993164374e+00 0 0 1 +20159 1260 2 3.5400000000000001e-02 1.3926944139015212e+01 1.6557995485351512e+01 6.3887938420848460e+00 -1 0 0 +148081 9256 1 -1.2900000000000000e-01 1.2492118565628704e+01 1.4979897838545488e+01 2.6436586008146001e+00 0 0 1 +148091 9256 1 -1.7340000000000000e-01 1.3530995074380009e+01 1.4213674981946097e+01 3.1123918617731032e+00 0 0 1 +148092 9256 2 1.4030000000000001e-01 1.4623143267492075e+01 1.4535351487479833e+01 2.9973381899213969e+00 0 0 1 +148082 9256 2 1.2370000000000000e-01 1.2782518572888232e+01 1.5903925404629245e+01 2.1259561679744268e+00 0 0 1 +111363 6961 1 2.6599999999999999e-02 3.3251830344800792e+00 4.7485757568569973e+00 6.9113558564667130e+00 0 0 0 +111369 6961 1 -1.1340000000000000e-01 1.7274039940012614e+01 5.7584093577092439e+00 7.2910114349614759e+00 -1 0 0 +111371 6961 1 -1.7340000000000000e-01 1.8312835551908693e+00 6.2232465111479911e+00 8.1114550764182880e+00 0 0 0 +111372 6961 2 1.4030000000000001e-01 1.8184339590637627e+01 7.0555999825672302e+00 8.7298916963317161e+00 -1 0 0 +111362 6961 2 1.2370000000000000e-01 3.9289971116618676e+00 6.1185293409164041e+00 8.4690798450222537e+00 0 0 0 +111361 6961 1 -1.2900000000000000e-01 3.1341751882158055e+00 5.7178553096834150e+00 7.8335342183333747e+00 0 0 0 +43056 2691 2 3.5400000000000001e-02 7.3303403250812371e+00 4.9319934647318124e+00 1.0162980877015160e+01 0 1 0 +195807 12238 2 3.5400000000000001e-02 3.1236778954925324e+00 2.4452125090877095e+00 1.1400842410014139e+01 2 2 1 +195808 12238 2 3.5400000000000001e-02 2.0398723702262984e+00 2.7431930858712024e+00 9.8739778618202809e+00 2 2 1 +195806 12238 4 -6.9599999999999995e-02 2.7616033282961303e+00 2.1041460428116832e+00 1.0438344594844656e+01 2 2 1 +43041 2691 1 -1.2900000000000000e-01 6.3733220978070637e+00 4.4203611180779721e+00 1.3517632502395033e+01 0 1 0 +43042 2691 2 1.2370000000000000e-01 5.6489085759325306e+00 4.6150266566474185e+00 1.2719368891868069e+01 0 1 0 +43043 2691 1 2.6599999999999999e-02 7.7212675306349068e+00 4.4431128372749367e+00 1.3317902516492849e+01 0 1 0 +43055 2691 2 3.5400000000000001e-02 7.5569470416398614e+00 3.2145118903989083e+00 1.1016915970754408e+01 0 1 0 +43044 2691 3 -1.8200000000000001e-02 8.3614898082720455e+00 4.8362903846004572e+00 1.1991757246671359e+01 0 1 0 +43054 2691 4 -6.9599999999999995e-02 7.6774180518032056e+00 4.2978431680872893e+00 1.1030363927900430e+01 0 1 0 +150156 9385 2 1.4030000000000001e-01 6.9383382514086422e+00 1.7437119221893461e+01 9.1021782978174173e+00 1 1 -1 +150155 9385 1 -1.7340000000000000e-01 8.0221029992533950e+00 1.7834769921916759e+01 9.1631290455798435e+00 1 1 -1 +111374 6961 4 -6.9599999999999995e-02 4.7656438943583348e+00 4.0654137347449968e+00 5.3046612893154670e+00 0 0 0 +111376 6961 2 3.5400000000000001e-02 4.7963400068324304e+00 4.9709930653728112e+00 4.7188309040401490e+00 0 0 0 +150154 9385 2 1.2880000000000000e-01 8.1369513264721434e+00 2.0263974595218754e+00 7.1494567261751296e+00 1 2 -1 +150153 9385 1 -1.1340000000000000e-01 8.6608899042584291e+00 1.8888977494944439e+00 8.0784138030671233e+00 1 2 -1 +150151 9385 1 -1.7340000000000000e-01 1.0018867708590742e+01 2.2567570866800981e+00 8.0675401866229777e+00 1 2 -1 +43046 2691 2 1.2370000000000000e-01 9.6303640603892067e+00 4.2459259032489243e+00 1.4177008871757124e+01 0 1 0 +43053 2691 2 5.1600000000000000e-02 8.6562690567036107e+00 5.8993116724868262e+00 1.2016505189049507e+01 0 1 0 +20146 1260 2 1.2370000000000000e-01 1.2925937029105093e+01 3.6154428198559656e+00 5.6919997433898892e+00 -1 1 0 +111370 6961 2 1.2880000000000000e-01 1.6276841578468378e+01 6.1680557812999490e+00 7.4004318736634556e+00 -1 0 0 +20155 1260 1 -1.7340000000000000e-01 1.2881099375913237e+01 4.8772017009451076e+00 7.4144207441793428e+00 -1 1 0 +20145 1260 1 -1.2900000000000000e-01 1.3325636094702979e+01 3.8506374415214806e+00 6.6335193494241205e+00 -1 1 0 +20149 1260 1 -1.2900000000000000e-01 1.4803237282058465e+01 3.1721920915819846e+00 8.3854646584058017e+00 -1 1 0 +20153 1260 1 -1.1340000000000000e-01 1.3361990235494616e+01 5.0962782885434859e+00 8.6895105180563945e+00 -1 1 0 +20154 1260 2 1.2880000000000000e-01 1.3027697793413543e+01 5.9629979486703641e+00 9.2441017743763290e+00 -1 1 0 +20151 1260 1 -1.7340000000000000e-01 1.4380189422775935e+01 4.2223572958105908e+00 9.1399321348841838e+00 -1 1 0 +20147 1260 1 2.6599999999999999e-02 1.4304259480768936e+01 3.0225224973374898e+00 7.0840404864415598e+00 -1 1 0 +20152 1260 2 1.4030000000000001e-01 1.5000038710755923e+01 4.4820227233013270e+00 9.9846869651675494e+00 -1 1 0 +20150 1260 2 1.2370000000000000e-01 1.5639941935305668e+01 2.5539512931406918e+00 8.7033169971457358e+00 -1 1 0 +20156 1260 2 1.4030000000000001e-01 1.2081029146239729e+01 5.5619230729709805e+00 7.0240622755420876e+00 -1 1 0 +150152 9385 2 1.4030000000000001e-01 1.0398677710841509e+01 2.6132174552595142e+00 7.1458602364708215e+00 1 2 -1 +107926 6746 2 1.2370000000000000e-01 5.0564645669299786e+00 9.8206736952581757e+00 1.2050756067767006e+01 1 0 0 +65549 4097 2 5.1600000000000000e-02 2.0092237695336150e+00 1.3647733560513613e+01 7.8060964087143585e+00 1 0 0 +41318 2583 2 1.2370000000000000e-01 3.2889581470504385e+00 1.5395406831499587e+01 8.1227148731915086e+00 0 0 1 +41320 2583 2 1.4030000000000001e-01 4.9623722046803023e+00 1.4094953957382288e+01 9.5590806118604554e+00 0 0 1 +107925 6746 1 -1.2900000000000000e-01 6.0634867066543432e+00 9.5484282841539585e+00 1.2296230810664806e+01 1 0 0 +107928 6746 2 1.4030000000000001e-01 6.6741988665111220e+00 9.2499811531291734e+00 1.0308875349648671e+01 1 0 0 +107927 6746 1 -1.7340000000000000e-01 6.9187781699197348e+00 9.1217664477662801e+00 1.1322711921884700e+01 1 0 0 +41352 2585 2 1.4030000000000001e-01 9.6017776350949440e+00 1.0818988642106115e+01 5.9796717383331348e+00 0 1 1 +107931 6746 1 -1.7340000000000000e-01 8.8159008450723420e+00 9.2215476294842276e+00 1.2939060135330434e+01 1 0 0 +107930 6746 2 1.2880000000000000e-01 9.1151905965455686e+00 8.8340925395314045e+00 1.0892578555618352e+01 1 0 0 +107929 6746 1 -1.1340000000000000e-01 8.3352274204594607e+00 8.9222475622725810e+00 1.1632822526543650e+01 1 0 0 +69386 4337 2 1.2880000000000000e-01 1.2475432366972534e+01 8.4535388534671192e+00 9.8010997231828423e+00 0 1 1 +69385 4337 1 -1.1340000000000000e-01 1.2183961606338126e+01 9.5133083783428809e+00 9.5150186186307018e+00 0 1 1 +69388 4337 2 1.4030000000000001e-01 1.1821311669543274e+01 1.0271543753950064e+01 1.1515153882968731e+01 0 1 1 +69387 4337 1 -1.7340000000000000e-01 1.1871110594374576e+01 1.0483008707917794e+01 1.0444919114342293e+01 0 1 1 +69379 4337 1 2.6599999999999999e-02 1.1857971549146844e+01 1.2184042292015063e+01 8.6614659076276297e+00 0 1 1 +69378 4337 2 1.2370000000000000e-01 1.1317141396250484e+01 1.2573319300708581e+01 1.0672328887070607e+01 0 1 1 +69377 4337 1 -1.2900000000000000e-01 1.1722235923015901e+01 1.1839046459537844e+01 1.0007231464783189e+01 0 1 1 +69383 4337 1 -1.7340000000000000e-01 1.2261182546118910e+01 9.8671789721187935e+00 8.1443688661455607e+00 0 1 1 +69381 4337 1 -1.2900000000000000e-01 1.2014141664603619e+01 1.1182218859954364e+01 7.7458662139445638e+00 0 1 1 +107932 6746 2 1.4030000000000001e-01 9.8995913535996376e+00 9.2237698067897202e+00 1.3177685392622811e+01 1 0 0 +65550 4097 4 -6.9599999999999995e-02 1.7458318049986850e+01 1.2626772124497204e+01 6.3525170639926802e+00 0 0 0 +65552 4097 2 3.5400000000000001e-02 1.6665164338293771e+01 1.1937651629402151e+01 6.0235296511383511e+00 0 0 0 +65540 4097 3 -1.8200000000000001e-02 1.7646955427571115e+01 1.3029929723406916e+01 7.5909570929344019e+00 0 0 0 +69389 4337 2 5.1600000000000000e-02 1.2265189992326546e+01 1.4290742881741917e+01 8.4069171939395204e+00 0 1 1 +69380 4337 3 -1.8200000000000001e-02 1.1555358586339914e+01 1.3518810236412984e+01 8.2012594227094588e+00 0 1 1 +65542 4097 2 1.2370000000000000e-01 1.5690440868314797e+01 1.1580697705070271e+01 8.7879736220365245e+00 0 0 0 +65539 4097 1 2.6599999999999999e-02 1.7811281801694086e+01 1.1774589953178271e+01 8.4290535902248998e+00 0 0 0 +65543 4097 1 -1.7340000000000000e-01 1.6690991873171978e+01 1.0038282867815722e+01 9.7296121527578130e+00 0 0 0 +65541 4097 1 -1.2900000000000000e-01 1.6665595158679011e+01 1.1138183814109587e+01 8.9474424737658609e+00 0 0 0 +65544 4097 2 1.4030000000000001e-01 1.5750449560114141e+01 9.7712770926962200e+00 1.0179218454081040e+01 0 0 0 +65545 4097 1 -1.1340000000000000e-01 1.7917505972636960e+01 9.5217739132725718e+00 1.0138662254181785e+01 0 0 0 +65547 4097 1 -1.7340000000000000e-01 2.4985890098324282e+00 1.0025642898562477e+01 9.4176492999025960e+00 1 0 0 +65537 4097 1 -1.2900000000000000e-01 2.5037460872226416e+00 1.1160633791856982e+01 8.6253692316834503e+00 1 0 0 +65538 4097 2 1.2370000000000000e-01 3.4886865157086326e+00 1.1651865642923802e+01 8.2660122736916346e+00 1 0 0 +41340 2584 2 1.4030000000000001e-01 1.6345251447958152e+01 1.0581077581118659e+01 1.2940303448103140e+01 -1 0 -1 +101772 6361 2 1.4030000000000001e-01 1.2061325019095884e+01 8.2414580626526899e+00 1.2746827572696125e+01 0 0 0 +41325 2583 2 5.1600000000000000e-02 3.2807546908780347e+00 1.7513301250682424e+01 6.1969284929278405e+00 0 0 1 +41319 2583 1 -1.7340000000000000e-01 5.1667966032079615e+00 1.4504958612304554e+01 8.4899418683521528e+00 0 0 1 +41317 2583 1 -1.2900000000000000e-01 4.2709331569515046e+00 1.5171166486203983e+01 7.7097533336229027e+00 0 0 1 +41315 2583 1 2.6599999999999999e-02 4.5302208176436256e+00 1.5822738162287587e+01 6.5065100708848096e+00 0 0 1 +195805 12238 2 5.1600000000000000e-02 3.4789342586146521e+00 1.6756199991066900e+01 1.0774146846249749e+01 2 1 1 +195796 12238 3 -1.8200000000000001e-02 2.9396670397560705e+00 1.7364763999896855e+01 1.0037973077323782e+01 2 1 1 +195794 12238 2 1.2370000000000000e-01 1.8172149588585661e+01 1.5879196184308281e+01 1.1942665785926817e+01 1 1 1 +195795 12238 1 2.6599999999999999e-02 1.8189960246829628e+01 1.6557402820682235e+01 9.8951910057012231e+00 1 1 1 +150146 9385 2 1.2370000000000000e-01 8.3229454006835439e+00 1.7106284894415296e+01 1.1175280806134634e+01 1 1 -1 +41321 2583 1 -1.1340000000000000e-01 6.4886610422833844e+00 1.4417282047103134e+01 8.0372824966757364e+00 0 0 1 +41324 2583 2 1.4030000000000001e-01 7.8692334894297309e+00 1.5217531732265087e+01 6.5759412635528571e+00 0 0 1 +41323 2583 1 -1.7340000000000000e-01 6.8035306315514008e+00 1.5119554474942500e+01 6.8678298859343405e+00 0 0 1 +41322 2583 2 1.2880000000000000e-01 7.2031050513797865e+00 1.3866464011687089e+01 8.6968935609528657e+00 0 0 1 +69392 4337 2 3.5400000000000001e-02 9.8208712510125142e+00 1.2837136804877213e+01 7.2879452773642148e+00 0 1 1 +69390 4337 4 -6.9599999999999995e-02 1.0594300370390499e+01 1.3660921113381333e+01 7.2955800346017856e+00 0 1 1 +150145 9385 1 -1.2900000000000000e-01 8.7817019328088897e+00 1.7596288757726505e+01 1.0343829436148329e+01 1 1 -1 +150148 9385 3 -1.8200000000000001e-02 1.0884985120753306e+01 1.7878920372459348e+01 1.1622690956049924e+01 1 1 -1 +150147 9385 1 2.6599999999999999e-02 1.0108201636057926e+01 1.7931699486130150e+01 1.0276792278149461e+01 1 1 -1 +150158 9385 4 -6.9599999999999995e-02 1.1231503999641122e+01 2.5211948038212908e+00 1.2157003840952251e+01 1 2 -1 +150157 9385 2 5.1600000000000000e-02 1.1450691871401704e+01 1.6961509499627816e+01 1.1846193381515082e+01 1 1 -1 +150149 9385 1 -1.2900000000000000e-01 1.0685137286262131e+01 2.1085945763903835e+00 9.2228119301870422e+00 1 2 -1 +150150 9385 2 1.2370000000000000e-01 1.1778864770299412e+01 2.2382910653089674e+00 9.2517160457463650e+00 1 2 -1 +69391 4337 2 3.5400000000000001e-02 1.0456151079379346e+01 1.4488060316916382e+01 6.5466258733581748e+00 0 1 1 +195793 12238 1 -1.2900000000000000e-01 1.7686648268709941e+01 1.5878855746393022e+01 1.0990461704653441e+01 1 1 1 +195803 12238 1 -1.7340000000000000e-01 1.6473035640090831e+01 1.5137365973601687e+01 1.0856129998973106e+01 1 1 1 +195802 12238 2 1.2880000000000000e-01 1.4746861929711587e+01 1.4655317568086621e+01 9.6616665472576706e+00 1 1 1 +195801 12238 1 -1.1340000000000000e-01 1.5796051233623190e+01 1.5136832380446570e+01 9.6813454294041570e+00 1 1 1 +195800 12238 2 1.4030000000000001e-01 1.5800095499624135e+01 1.5655928659699169e+01 7.5461924170663712e+00 1 1 1 +195797 12238 1 -1.2900000000000000e-01 1.7513784072987086e+01 1.6544830312871746e+01 8.6950467616507989e+00 1 1 1 +195799 12238 1 -1.7340000000000000e-01 1.6338499065166612e+01 1.5829599854108311e+01 8.5770220966138417e+00 1 1 1 +195798 12238 2 1.2370000000000000e-01 1.7934224097607796e+01 1.7144884480762489e+01 7.8707368838248923e+00 1 1 1 +195804 12238 2 1.4030000000000001e-01 1.6175858894436228e+01 1.4595879081941767e+01 1.1818036137280366e+01 1 1 1 +107226 6702 2 1.2880000000000000e-01 2.6931705146437825e+00 7.4528536578048046e+00 1.6401480417559661e+01 1 0 -1 +107225 6702 1 -1.1340000000000000e-01 2.5412082692488589e+00 7.6946064706658266e+00 1.7479029549052996e+01 1 0 -1 +43050 2691 2 1.2880000000000000e-01 6.3901733561307177e+00 3.8729885166252385e+00 1.6857663943247552e+01 0 1 0 +43049 2691 1 -1.1340000000000000e-01 6.8639644760880891e+00 3.9977844737634753e+00 1.5864759086802867e+01 0 1 0 +43051 2691 1 -1.7340000000000000e-01 5.8836925448396897e+00 4.2197213883127613e+00 1.4819642488545631e+01 0 1 0 +43052 2691 2 1.4030000000000001e-01 4.8445169787238385e+00 4.2666621101197810e+00 1.4993271083516717e+01 0 1 0 +160474 10030 2 1.2880000000000000e-01 4.9714511327777986e+00 1.5116752517331660e+01 1.2597642370797514e+01 1 0 0 +43048 2691 2 1.4030000000000001e-01 8.8893103329068470e+00 3.8888260173570122e+00 1.6459057949661215e+01 0 1 0 +188724 11796 3 -1.8200000000000001e-02 1.1688421678176432e+01 4.0960510248164450e+00 2.0909014529829917e+00 0 2 0 +188733 11796 2 5.1600000000000000e-02 1.1375250276290704e+01 4.8331916161112147e+00 1.7811967196437259e+01 0 2 -1 +188734 11796 4 -6.9599999999999995e-02 1.0736515393208268e+01 3.6250109566200721e+00 2.9002084374308392e+00 0 2 0 +188735 11796 2 3.5400000000000001e-02 9.7000686220121803e+00 3.9030555037638384e+00 2.8330595968939667e+00 0 2 0 +43047 2691 1 -1.7340000000000000e-01 8.2155679119992957e+00 3.9284586980885070e+00 1.5659681814868401e+01 0 1 0 +43045 2691 1 -1.2900000000000000e-01 8.5871632440144943e+00 4.1176139134649334e+00 1.4359425816463261e+01 0 1 0 +3053 191 2 5.1600000000000000e-02 1.4131209452224061e+01 3.7205834284925237e+00 1.2807104549015305e+01 -1 1 -1 +188722 11796 2 1.2370000000000000e-01 1.4402813832794054e+01 4.0507183151628627e+00 1.8177214408032896e+01 0 2 -1 +188721 11796 1 -1.2900000000000000e-01 1.4132746768243644e+01 4.7192568251348419e+00 2.5172268148938008e+00 0 2 0 +3055 191 2 3.5400000000000001e-02 1.2647552554478004e+01 4.1066728934311065e+00 1.4626327349760397e+01 -1 1 -1 +3048 191 2 1.4030000000000001e-01 2.1361911246942613e+00 2.0256462695747413e+00 1.3661683245937004e+01 0 1 -1 +188731 11796 1 -1.7340000000000000e-01 1.5082344798334990e+01 5.4339100483828533e+00 3.2040607534203400e+00 0 2 0 +3054 191 4 -6.9599999999999995e-02 1.3634640729991750e+01 3.8573291703607966e+00 1.4918577504339625e+01 -1 1 -1 +3056 191 2 3.5400000000000001e-02 1.3956384462179996e+01 3.9073965418023482e+00 1.5995687294821206e+01 -1 1 -1 +3046 191 2 1.2370000000000000e-01 1.7193526563745138e+01 3.7459889826236981e+00 1.3527506035297845e+01 -1 1 -1 +188732 11796 2 1.4030000000000001e-01 1.6083180459711862e+01 5.2111335470887523e+00 3.0021790482301487e+00 0 2 0 +3044 191 3 -1.8200000000000001e-02 1.4462398230952495e+01 3.7530010030969558e+00 1.3864072205754665e+01 -1 1 -1 +3047 191 1 -1.7340000000000000e-01 1.7647518143872116e+01 1.7688415837286873e+00 1.4069869500933256e+01 -1 1 -1 +3043 191 1 2.6599999999999999e-02 1.5358225536986536e+01 2.5383885112449232e+00 1.4011133084383125e+01 -1 1 -1 +3045 191 1 -1.2900000000000000e-01 1.6698963155322488e+01 2.7814029062226857e+00 1.3817663440342963e+01 -1 1 -1 +101766 6361 2 1.2370000000000000e-01 1.4486305311740852e+01 7.0492572322308868e+00 1.6861792785180214e+01 0 0 0 +101765 6361 1 -1.2900000000000000e-01 1.3952052360271175e+01 7.3593350772883674e+00 1.5958103513676853e+01 0 0 0 +101768 6361 2 1.4030000000000001e-01 1.5598211775798697e+01 6.8332180667355438e+00 1.4649592564383175e+01 0 0 0 +101770 6361 2 1.2880000000000000e-01 1.4413755542349351e+01 7.4347516650250540e+00 1.2552816796988212e+01 0 0 0 +101769 6361 1 -1.1340000000000000e-01 1.3891333488399404e+01 7.5059992680422489e+00 1.3502034253911555e+01 0 0 0 +101767 6361 1 -1.7340000000000000e-01 1.4605101636425838e+01 7.2573358819526579e+00 1.4741222690138107e+01 0 0 0 +107227 6702 1 -1.7340000000000000e-01 1.7883548418980652e+01 8.3514720862484815e+00 1.7898023886448911e+01 0 0 -1 +108387 6775 1 2.6599999999999999e-02 7.3105046605336623e+00 1.2002646672640418e+01 1.8180285553843476e+01 0 0 0 +108397 6775 2 5.1600000000000000e-02 6.4647144372088396e+00 1.0136771332249360e+01 1.7453949180576807e+01 0 0 0 +107217 6702 1 -1.2900000000000000e-01 1.7732828280737948e+01 8.5361463551748038e+00 2.8569355745343277e+00 0 0 0 +107935 6746 2 3.5400000000000001e-02 5.0561509861045302e+00 8.1734324546280099e+00 1.4745872444105991e+01 1 0 0 +107933 6746 2 5.1600000000000000e-02 5.1594105258377665e+00 1.1267260390577270e+01 1.4472801471667175e+01 1 0 0 +107934 6746 4 -6.9599999999999995e-02 4.6169720890872554e+00 9.1871032170689944e+00 1.4737566205819322e+01 1 0 0 +107924 6746 3 -1.8200000000000001e-02 5.4432003856112612e+00 1.0237922103124522e+01 1.4609929127699449e+01 1 0 0 +107923 6746 1 2.6599999999999999e-02 6.4820549290353195e+00 9.7078183298517988e+00 1.3613217549850990e+01 1 0 0 +107228 6702 2 1.4030000000000001e-01 1.7115417491762386e+01 8.7327362751247577e+00 1.7217705089608554e+01 0 0 -1 +107936 6746 2 3.5400000000000001e-02 3.5781383029214346e+00 8.9944694941570749e+00 1.4713627566978687e+01 1 0 0 +160479 10030 2 3.5400000000000001e-02 3.7326685747508552e+00 1.3427274929042056e+01 2.2216548785191739e+00 1 0 1 +107921 6746 1 -1.2900000000000000e-01 7.8562865065307435e+00 9.5957645375673035e+00 1.3851562295909520e+01 1 0 0 +107922 6746 2 1.2370000000000000e-01 8.0995841612996955e+00 9.7313098352338123e+00 1.4939733899172261e+01 1 0 0 +107218 6702 2 1.2370000000000000e-01 1.6835368082721224e+01 9.1131625105569878e+00 3.2255257646648907e+00 0 0 0 +108388 6775 3 -1.8200000000000001e-02 7.3532485484630739e+00 1.0786635947908049e+01 1.7355440619577308e+01 0 0 0 +108399 6775 2 3.5400000000000001e-02 8.6525462867452845e+00 9.1449007932328534e+00 1.7647695780957935e+01 0 0 0 +108398 6775 4 -6.9599999999999995e-02 8.5213713271356717e+00 1.0232558032132358e+01 1.7537403599029407e+01 0 0 0 +101776 6361 2 3.5400000000000001e-02 1.2049684967504803e+01 1.0165869848570868e+01 1.7105430507983492e+01 0 0 0 +101775 6361 2 3.5400000000000001e-02 1.2887489730527209e+01 9.4926640670100220e+00 2.0987313930387570e+00 0 0 1 +101774 6361 4 -6.9599999999999995e-02 1.2305590434143607e+01 9.2071744394622499e+00 1.7710749947057952e+01 0 0 0 +101764 6361 3 -1.8200000000000001e-02 1.1946469391161191e+01 7.9345918432054798e+00 1.7422016804743411e+01 0 0 0 +101773 6361 2 5.1600000000000000e-02 1.2259930148470499e+01 7.1324492364701051e+00 1.8139842490217099e+01 0 0 0 +101763 6361 1 2.6599999999999999e-02 1.2664387194381472e+01 7.8161236053804517e+00 1.6068998595047127e+01 0 0 0 +101762 6361 2 1.2370000000000000e-01 1.0978083818181998e+01 8.5416591738498990e+00 1.5007646020399198e+01 0 0 0 +179272 11205 2 1.4030000000000001e-01 8.8017355529519605e+00 1.2300324251887471e+01 1.1173326770491549e+01 1 0 -1 +179270 11205 2 1.2370000000000000e-01 1.0393817075879586e+01 1.1825769406851849e+01 1.2934369573096140e+01 1 0 -1 +179271 11205 1 -1.7340000000000000e-01 8.9139923428024765e+00 1.3024335850892795e+01 1.2003930331336008e+01 1 0 -1 +65546 4097 2 1.2880000000000000e-01 1.7899483895246036e+01 8.6480490306837368e+00 1.0836166866910942e+01 0 0 0 +65548 4097 2 1.4030000000000001e-01 3.4494286730252339e+00 9.6066332589219989e+00 9.6739630854217005e+00 1 0 0 +101761 6361 1 -1.2900000000000000e-01 1.2004770701672360e+01 8.1530844525238351e+00 1.4874154146718642e+01 0 0 0 +101771 6361 1 -1.7340000000000000e-01 1.2589725462806230e+01 7.9052944284843694e+00 1.3651903735235269e+01 0 0 0 +41339 2584 1 -1.7340000000000000e-01 1.6589792086060861e+01 1.1434284215631770e+01 1.3616315654462921e+01 -1 0 -1 +41329 2584 1 -1.2900000000000000e-01 1.5924934127057425e+01 1.1453825570103859e+01 1.4834566892269521e+01 -1 0 -1 +41343 2584 2 3.5400000000000001e-02 1.5346036789775042e+01 1.0577438179777253e+01 1.7744257789483889e+01 -1 0 -1 +41342 2584 4 -6.9599999999999995e-02 1.5535759072649746e+01 1.1618009272633429e+01 1.8028456966425424e+01 -1 0 -1 +41344 2584 2 3.5400000000000001e-02 1.5605571674399014e+01 1.1845541378829052e+01 2.5753776309133376e+00 -1 0 0 +41330 2584 2 1.2370000000000000e-01 1.5155432327680716e+01 1.0728855828798077e+01 1.5116346047300009e+01 -1 0 -1 +41341 2584 2 5.1600000000000000e-02 1.5255845286212361e+01 1.3595578835369178e+01 1.7401974454512626e+01 -1 0 -1 +41331 2584 1 2.6599999999999999e-02 1.6218407517059681e+01 1.2433872672159525e+01 1.5835322031560247e+01 -1 0 -1 +41332 2584 3 -1.8200000000000001e-02 1.5342508920013911e+01 1.2566890327026831e+01 1.7065300433834039e+01 -1 0 -1 +179276 11205 2 1.4030000000000001e-01 7.7409900700875669e+00 1.6039772300823500e+01 1.2996164460662758e+01 1 0 -1 +108385 6775 1 -1.2900000000000000e-01 7.4233967221649939e+00 1.3208845277918304e+01 1.7576420059242437e+01 0 0 0 +160480 10030 2 3.5400000000000001e-02 2.5198362929249960e+00 1.3397217172244797e+01 1.7309546401633696e+01 1 0 0 +108386 6775 2 1.2370000000000000e-01 7.6418580353016772e+00 1.3201805789851932e+01 1.6463737231152205e+01 0 0 0 +160478 10030 4 -6.9599999999999995e-02 3.1803970397480916e+00 1.3965101712621689e+01 1.7930232961704462e+01 1 0 0 +160468 10030 3 -1.8200000000000001e-02 3.2747731245789664e+00 1.5232476684383739e+01 1.7659189220495477e+01 1 0 0 +160470 10030 2 1.2370000000000000e-01 4.5355816453608124e+00 1.3114455934447417e+01 1.6215718014273392e+01 1 0 0 +160472 10030 2 1.4030000000000001e-01 5.6139592118976136e+00 1.3131308544224675e+01 1.4080126826092714e+01 1 0 0 +160471 10030 1 -1.7340000000000000e-01 5.1811370917832766e+00 1.4080044327837159e+01 1.4456427972211051e+01 1 0 0 +160469 10030 1 -1.2900000000000000e-01 4.5804091192069301e+00 1.4037606684058916e+01 1.5713383640096469e+01 1 0 0 +160473 10030 1 -1.1340000000000000e-01 5.0037064822006068e+00 1.5195504770002120e+01 1.3654947051935174e+01 1 0 0 +160476 10030 2 1.4030000000000001e-01 4.3104997064483790e+00 1.7284794062856477e+01 1.3634720726802625e+01 1 0 0 +160475 10030 1 -1.7340000000000000e-01 4.4078150650840886e+00 1.6318615075841972e+01 1.4219645992621857e+01 1 0 0 +160465 10030 1 -1.2900000000000000e-01 4.0610468192223443e+00 1.6308730622530351e+01 1.5558870664605191e+01 1 0 0 +160466 10030 2 1.2370000000000000e-01 3.5686154938002295e+00 1.7222651804330930e+01 1.5900437427118566e+01 1 0 0 +160467 10030 1 2.6599999999999999e-02 3.9318617624607755e+00 1.5132619387648699e+01 1.6267790553153716e+01 1 0 0 +150159 9385 2 3.5400000000000001e-02 1.0651976528402525e+01 3.4357906631307165e+00 1.2089534483238621e+01 1 2 -1 +150160 9385 2 3.5400000000000001e-02 1.2104884307909124e+01 2.5931369889877622e+00 1.2799396410924045e+01 1 2 -1 +179274 11205 2 1.2880000000000000e-01 7.5635170359697375e+00 1.4547808023605786e+01 1.1108629291415742e+01 1 0 -1 +179278 11205 4 -6.9599999999999995e-02 1.1635322751866651e+01 1.2257154805758839e+01 1.5137151672689530e+01 1 0 -1 +179268 11205 3 -1.8200000000000001e-02 1.0997175481765529e+01 1.3405153367619416e+01 1.5130082764970151e+01 1 0 -1 +179266 11205 2 1.2370000000000000e-01 9.1942088684810823e+00 1.5422706022769127e+01 1.5035703786272791e+01 1 0 -1 +179280 11205 2 3.5400000000000001e-02 1.2290942256734050e+01 1.1826014649487290e+01 1.4392219038469303e+01 1 0 -1 +179267 11205 1 2.6599999999999999e-02 9.9496209304151666e+00 1.3629886003062269e+01 1.4124589952682891e+01 1 0 -1 +179275 11205 1 -1.7340000000000000e-01 8.2701895659697797e+00 1.5076504555751216e+01 1.3052072167601100e+01 1 0 -1 +179265 11205 1 -1.2900000000000000e-01 9.0564106265983355e+00 1.4783784316041231e+01 1.4154656487210538e+01 1 0 -1 +179269 11205 1 -1.2900000000000000e-01 9.8768793826486316e+00 1.2787181450430296e+01 1.3014283720178977e+01 1 0 -1 +179273 11205 1 -1.1340000000000000e-01 8.2674216650716907e+00 1.4253273160133595e+01 1.1948939368483259e+01 1 0 -1 +179277 11205 2 5.1600000000000000e-02 1.0610727421449907e+01 1.3739814257364230e+01 1.6100755441988152e+01 1 0 -1 +160477 10030 2 5.1600000000000000e-02 3.9412304815930104e+00 1.5838691529735270e+01 1.7734323116652897e+00 1 0 1 +3050 191 2 1.2880000000000000e-01 1.7898982762827522e+01 1.6150504000168105e+01 1.4416156164361380e+01 -1 0 -1 +3042 191 2 1.2370000000000000e-01 1.3942092690198225e+01 1.7683486329176745e+01 1.4820833614746432e+01 -1 0 -1 +3041 191 1 -1.2900000000000000e-01 1.4940290038031597e+01 1.7837094196722056e+01 1.4454329160863994e+01 -1 0 -1 +3049 191 1 -1.1340000000000000e-01 1.7196155424954874e+01 1.7017060638418130e+01 1.4373120643853616e+01 -1 0 -1 +3051 191 1 -1.7340000000000000e-01 1.5845051399300770e+01 1.6778167679823589e+01 1.4620076052624285e+01 -1 0 -1 +3052 191 2 1.4030000000000001e-01 1.5497654156270627e+01 1.5778851829853114e+01 1.4800370085812935e+01 -1 0 -1 +179279 11205 2 3.5400000000000001e-02 1.1619265961576444e+01 1.1687845995171676e+01 1.6085200175077574e+01 1 0 -1 +41338 2584 2 1.2880000000000000e-01 1.7568651246853193e+00 1.2192292914855560e+01 1.2474233482244635e+01 0 0 -1 +41336 2584 2 1.4030000000000001e-01 2.2324306685334516e+00 1.3971093942058394e+01 1.4193890180808504e+01 0 0 -1 +41337 2584 1 -1.1340000000000000e-01 1.7657386738972786e+01 1.2343250231643829e+01 1.3351358148640003e+01 -1 0 -1 +41335 2584 1 -1.7340000000000000e-01 1.7912104075252799e+01 1.3296238336433840e+01 1.4340140648841116e+01 -1 0 -1 +41333 2584 1 -1.2900000000000000e-01 1.7246150468532957e+01 1.3385489918572183e+01 1.5568140261294454e+01 -1 0 -1 +41334 2584 2 1.2370000000000000e-01 1.7455716623269652e+01 1.4043517017613519e+01 1.6398684799357447e+01 -1 0 -1 + +Velocities + +40602 -6.3985937286226606e-03 -1.1283920651758051e-02 1.9394773557760127e-02 +111366 7.1417889228307350e-03 2.3686345533524764e-03 1.5065506389023443e-02 +111365 4.2982514673758189e-03 -3.3283192982106525e-03 6.5036881647937477e-03 +111364 1.4447480828875161e-03 3.8092269892626334e-03 3.0609420633918654e-04 +111373 2.2700374864640424e-02 2.2290576591487434e-03 -6.7977785798176921e-03 +107224 1.7187267010873336e-02 -1.1555287862823971e-02 -1.0717215799613468e-02 +107223 -6.3226613301485979e-04 1.4795913931442428e-03 -6.5605731669071115e-03 +40599 -2.5724488567018611e-03 5.3740131515095432e-03 -1.1508458865342254e-04 +40600 3.0894309265885834e-03 7.0869892184123118e-03 -1.9531624930404824e-02 +41356 1.7160195689052138e-02 3.3571060089956223e-03 2.0463824167599072e-02 +107222 -1.2352364881033985e-02 -5.6793207223280774e-03 -1.1101201909159270e-02 +40597 5.5215942197628732e-03 3.2107591811954972e-04 3.0815583031388511e-03 +40598 2.4529408589842389e-02 1.5523133298995082e-02 -1.7101075554038388e-02 +111367 8.5756582830476269e-04 5.3997389483404334e-03 -6.4875926078625870e-03 +111368 1.3769852735293254e-02 -2.1680927934792451e-02 -1.8995998166840975e-02 +188723 3.3328235104561783e-04 8.5236950748101713e-04 4.2020891134151670e-03 +188726 -9.8003887498915986e-03 -2.1495045220230168e-02 8.3413373308345595e-04 +188736 -1.1100104140321627e-02 3.0529586466152923e-03 1.4662924054520724e-02 +41360 2.3048551361378499e-03 1.3548917365876484e-02 -1.0649868672622506e-02 +111375 -2.4422125149829027e-02 2.5695162102282055e-02 3.3922349033143284e-02 +41346 4.6625666522050130e-03 8.5743244035343079e-03 -4.9179988094868107e-03 +41359 -1.2726148133992348e-02 -1.2000997718029122e-02 1.6708496998307527e-03 +188725 1.1437177939645920e-03 -4.6323573846128430e-04 -2.5634649694155787e-03 +188729 -3.3988449745788792e-03 5.3757300898929299e-04 -2.2590775366986299e-03 +188727 3.1711558095981144e-03 7.3348712723420714e-03 7.4298368874665018e-03 +20158 -5.0109592460971424e-03 3.6872279392635809e-03 -5.5038251558829285e-03 +20160 -1.1821234057304992e-02 -2.5798190857128922e-03 -1.7953380281471747e-02 +20148 -1.0790472476793170e-03 -4.7025193507702606e-03 5.9217761171112299e-04 +188728 7.5473765845357884e-03 -1.5388969664485809e-02 9.8152795837572054e-03 +20157 -1.1944120436498213e-02 -1.9061416156011441e-02 -2.4914799662105972e-02 +188730 -1.4290269695998326e-02 2.9968229390958515e-02 7.7682551251084097e-03 +41355 -2.5991049762131772e-03 7.4297395598412874e-03 -1.6861102450866203e-03 +108389 -2.0384096805913287e-03 6.0388461522491261e-03 -1.8156856992433881e-03 +41327 -1.8190165050566413e-02 1.2902744096957476e-02 -6.8012225052866936e-03 +41326 2.4564138723369069e-03 8.0442641486566449e-03 3.3082730180927712e-03 +41328 -7.9543703561699274e-03 1.4610678983649835e-02 -5.8658854142750068e-04 +108390 -1.4636133796141480e-02 -1.1902813702312741e-02 -1.2565958306297892e-02 +108391 6.8277912089155703e-03 -6.6616757590615980e-03 1.3194254171091536e-02 +41353 6.1344487178109988e-04 2.3782327128607731e-03 -5.9839334739494598e-03 +41351 -5.5148848659499717e-03 3.3175240477984454e-03 -2.3477985375082062e-03 +107221 -6.1719557341304710e-05 6.6392922109710087e-03 -1.2604337429895050e-03 +107219 -2.5442440180131719e-03 6.8009639830674841e-04 3.7895831012066165e-03 +107232 9.9471624926068185e-04 2.9343026454605268e-03 1.4564418253620532e-02 +108392 -1.2205773323818782e-02 -1.2367095129675064e-02 -2.3620384811178449e-02 +41354 1.2633903485313827e-02 2.8894382064193129e-03 -7.5485661956211066e-03 +69384 3.7045438016150749e-03 1.4715210123816483e-02 -1.2504143987109963e-03 +41345 -1.2050690902703552e-03 -7.4223700967044797e-03 7.9557125889578358e-03 +41347 -5.2630112301396935e-03 1.0024695076983729e-03 4.0678108158525451e-03 +41357 -2.4235372130303228e-02 2.7194778844038932e-02 2.5954476578362314e-02 +41358 1.1547802455943292e-03 3.2054286419790192e-03 -5.7816107018840678e-03 +41348 2.8215799895673598e-03 -7.2301887887184424e-03 -5.9561539318358590e-03 +41349 1.8508257020319503e-03 -8.5310062398337300e-03 6.3502572698804077e-03 +41350 5.0424082461614922e-03 9.8759747315334129e-03 -3.7148985725838621e-02 +69382 1.0209488485216548e-02 8.7948629085824424e-03 6.0461055609758911e-03 +108400 3.2185453787997705e-02 4.4465668237807292e-04 3.2221034555599638e-02 +107220 -4.0146593456830170e-04 4.3976084131760714e-03 -1.4675205968496619e-03 +107229 -1.0433617007031043e-02 -1.3650333859161087e-02 -1.4213050498992373e-02 +65551 -4.9864380278714232e-03 -1.4856355031384712e-02 5.2803332223931424e-04 +107230 -1.0046475666219534e-03 -4.3746998646380488e-03 -5.0828115157881323e-03 +107231 1.3064987533431858e-02 -1.2616440589792253e-02 1.5496724125123052e-02 +148088 -5.7788264907382165e-03 -2.6933832447928175e-02 6.2446472207853465e-03 +148090 4.7648648958641283e-03 -3.1957718696620278e-02 -6.8971058281332674e-03 +148087 4.1315835848582082e-03 6.3290740064834297e-03 1.2949415393118048e-03 +148089 -7.1554872977898868e-03 -5.1666910859972581e-03 -2.0484014887854340e-03 +40604 -3.1744414925873135e-03 1.0568434359276006e-02 -2.1819988456264736e-02 +40603 2.8248689961349748e-03 1.2658982899592434e-03 -9.5764006115084746e-03 +40601 -4.7840031125935203e-04 9.4450791561692653e-03 -4.5528435199967349e-03 +41314 1.9149519323665907e-02 -6.0539194052006877e-03 5.2839448608981284e-03 +40594 1.8001534383656499e-02 2.9721693538009245e-03 2.3761970191448985e-02 +40593 -1.0908632903323596e-03 1.0495712304397933e-03 -1.2043838978949969e-03 +40595 2.7037492749230224e-03 4.4950383230027363e-03 2.8523867304455135e-04 +41316 1.0657791699052992e-03 -6.5096741060257099e-03 4.6172120682064308e-03 +108393 6.4195678479741008e-03 6.1890863167554807e-04 -3.4458122416580831e-04 +108394 1.7640001229085639e-03 -2.7098331768220227e-02 4.6754689677561925e-02 +41313 -2.1194538663887627e-03 8.9933456540167741e-04 -6.3884135988039525e-03 +108395 -6.7159387862448430e-03 -5.5000640306663339e-03 -4.9701797361138859e-03 +108396 -9.3569802272948782e-03 -1.1015116885264041e-02 -8.9017892105562844e-03 +148096 -4.2819336553939994e-03 -1.0050196677360956e-03 -2.1765415720189883e-02 +148095 4.9372342704395670e-03 1.0772605578946723e-02 -1.1721352868997137e-02 +148094 7.1248826100540322e-04 -3.2781016402931187e-03 2.8577594939631964e-04 +40608 -1.2370534160282482e-03 -8.2498460545062293e-03 2.5338864890924385e-02 +40607 1.3877315839298684e-02 1.3217823230226708e-02 2.8654612266083093e-02 +40605 8.2533235910335293e-03 -1.4363497942103563e-02 -5.8333651379382651e-03 +40606 -3.6177440555578344e-03 6.4037161614175055e-03 -7.2599838950661412e-03 +40596 -2.4546392581697943e-03 -4.9076179625028755e-03 5.9137087618071201e-03 +148093 1.7447620781739517e-02 2.2068002127499306e-02 -1.5040662930237567e-02 +148084 5.0933294765535949e-03 1.0234031055708500e-03 7.5015891928184334e-03 +148086 4.8420055786770281e-03 1.6812726112808648e-02 -1.3819560009771241e-04 +148085 -8.8289871556675153e-03 5.2193033688785698e-03 4.7266480208508202e-03 +148083 -7.1461232997133148e-03 -4.1887647415794725e-03 -7.8404449131831862e-04 +20159 -7.4629924575313053e-03 5.1113651021916437e-04 -3.2772971405742720e-03 +148081 4.1407665746122004e-03 -1.7828488447790513e-03 -7.5664489213328147e-03 +148091 6.8153129958091630e-03 -1.6847748121324249e-03 -7.3048091201541277e-03 +148092 9.7131175647673530e-03 -7.5600099887703272e-03 2.0349319254081608e-02 +148082 4.4908740015736160e-03 -5.8588195363773170e-03 1.7442587106140391e-02 +111363 -7.2666723745643045e-04 6.4453310449022526e-04 -9.2142146514411166e-04 +111369 2.3214338205662967e-03 -1.9300494656438171e-04 5.2064352844595631e-05 +111371 9.2498196774835114e-03 -7.6929365735117954e-03 -1.5145794805183515e-03 +111372 -2.3916823221637332e-03 -1.8730462875375706e-02 1.1809691836554021e-03 +111362 -6.7382249992153909e-04 5.2995704976425322e-03 -3.3360124539462105e-02 +111361 -8.6055288981815720e-03 -5.4071424783112623e-03 -1.2653640098973984e-02 +43056 3.2222153132921145e-03 1.9837761268420732e-02 9.2018302104190340e-03 +195807 -3.1382834937265937e-02 6.9332535127632029e-03 1.3160308515046322e-02 +195808 -3.2683081868087938e-02 -1.6396793809679167e-02 2.5209625669480457e-04 +195806 -9.8938695448897631e-03 1.3705293166065644e-03 7.8003187155232159e-03 +43041 8.9415567805161723e-03 8.7913160341705917e-04 5.6333712078787410e-03 +43042 1.0613219478942223e-02 2.3186041832578441e-02 -1.0115460586963982e-02 +43043 2.0978361718671187e-03 6.0263535813099497e-03 -1.3700435982461076e-03 +43055 -3.4386257188604344e-02 -1.5039464899947758e-03 8.7479446119385353e-04 +43044 -4.3121573494832970e-03 -8.0623094479985637e-03 8.0995104097343895e-03 +43054 2.4806635642581174e-03 1.3435133813313386e-02 4.9496913185229094e-03 +150156 1.0204657798397571e-02 7.8520007773605592e-03 -1.9929390618242882e-02 +150155 -1.6742680788560771e-03 4.2949845657895766e-03 -4.0950556847738689e-03 +111374 2.8056883266325912e-04 -6.1512930242348853e-05 3.1968810263665582e-03 +111376 2.7185148974756327e-02 2.4258034996224734e-03 -4.4755557435753827e-03 +150154 -9.8043514557737150e-03 9.4303679048280270e-03 -7.7080592127516511e-03 +150153 -4.8187204163573456e-03 2.3740896109405102e-03 4.8634437258542442e-03 +150151 -6.3991780492525102e-03 1.1588777932327687e-02 -3.0347131918465452e-03 +43046 -8.8311146243204004e-04 3.0986511119250699e-03 -1.2407892016880967e-02 +43053 9.5611734483879354e-03 -3.1426599490962055e-02 5.8803835591003236e-03 +20146 -1.7681237741758948e-02 -1.2212042848023569e-02 -1.1833442613132347e-02 +111370 -1.0710837326206812e-02 2.6089672819193891e-03 -5.4317254687181677e-03 +20155 -2.7215865188963246e-03 1.4560172171770279e-03 -4.2670739431862311e-03 +20145 -7.4364708932625513e-03 6.7007663084826818e-04 -7.7802544634573857e-03 +20149 3.1175637372676617e-03 -4.0109309363089663e-03 -1.0041320465318460e-02 +20153 -1.4993060554304328e-03 -1.4897146798975238e-03 1.0061799265953016e-03 +20154 -4.5667092906773635e-02 -3.9442205782248569e-03 8.3317673247143066e-04 +20151 -2.4277432789537640e-04 -1.4230354846986382e-03 -1.3830486874839140e-03 +20147 1.7882378095336886e-03 -1.5801307395524379e-03 5.2438073877780360e-05 +20152 -4.0777615249197371e-03 3.1119760731858820e-02 -1.5759361074254526e-02 +20150 9.0304079532301865e-03 1.0875943342613147e-02 -1.0895971464493320e-02 +20156 -5.6282725264859799e-03 -1.1672424195060220e-02 -7.2540747831290687e-03 +150152 5.9014548429507903e-03 -2.5097412250563358e-03 2.4514394229295321e-02 +107926 -2.5360130619403527e-02 1.7027498464666991e-02 1.4089021440180751e-02 +65549 2.2437863237016947e-02 1.5376768642133005e-02 -3.0023558944022315e-03 +41318 1.8042221289882098e-02 -2.7690176363431174e-03 1.7781355400005368e-02 +41320 9.9006239878205310e-03 -2.5462778699343425e-02 -2.9213483015257335e-02 +107925 2.9075289343929583e-03 4.6134671356644531e-04 1.1769542406121603e-02 +107928 -1.0263708016336921e-02 2.3707724952912439e-02 1.1482359218154482e-03 +107927 3.4365248976792003e-03 -6.2525848992054855e-03 -5.9247937754846221e-03 +41352 -1.2800226678188423e-03 -2.8048563798401534e-03 2.0152855354049065e-02 +107931 -4.3356949892896972e-03 6.5928579486349784e-03 -1.8621873901022122e-03 +107930 2.3237710511205181e-03 -1.2538253427723276e-02 -4.7839319344868776e-03 +107929 -8.0478126756462266e-04 -2.7560021303245719e-03 7.5571229201517529e-03 +69386 1.0473405390103647e-02 -6.6814121040076752e-03 9.5814420685443498e-03 +69385 4.9440082509376836e-03 -2.5126914407222916e-03 -3.5949598322722104e-03 +69388 1.8208857117612783e-03 -1.1322803427677355e-05 -1.4333219921259978e-02 +69387 3.1850369745748921e-04 6.5069660914624204e-03 -2.6386771913439965e-03 +69379 2.6314325531485937e-03 1.5715621609313378e-03 1.1821470965878366e-03 +69378 3.7026928777500151e-03 -2.7614897646064784e-02 1.8259771516738618e-02 +69377 2.6687771533153914e-03 -5.7218381841054600e-03 -7.5893780564083237e-04 +69383 -3.3691968886554952e-03 7.1360246962528422e-03 -9.8211852411923817e-04 +69381 4.7565972492020952e-03 9.0419073906814387e-03 -2.2763053585622473e-03 +107932 3.8414353147230764e-03 -8.0733742293150335e-03 1.8586066754227297e-02 +65550 8.3801343387129440e-03 -3.6416927830206571e-04 -1.8048768464312942e-03 +65552 1.5638442308199697e-02 -2.0834570456500827e-02 1.0981929724627556e-02 +65540 -1.0857776192705190e-02 -3.0700087407187775e-03 2.8788388836712897e-03 +69389 -6.1755692750579995e-03 -4.4194428240845861e-03 -1.1011904673336976e-02 +69380 5.2112328945180079e-03 -2.0458437106421236e-03 -3.9919201383127826e-03 +65542 1.0161363284650162e-02 -1.7453919007551381e-02 1.5366623626875970e-03 +65539 -3.2306768646671322e-03 9.2182272960381984e-04 2.6015855213855988e-03 +65543 5.1858203386749152e-03 2.7852728941709375e-03 3.5441667809768297e-03 +65541 1.7878919381596906e-03 4.1390806335909131e-03 1.9778464485735573e-03 +65544 2.4551706016464687e-02 9.1023838230138918e-03 2.6294443083941983e-02 +65545 -8.2129497046984305e-03 7.4780642489738185e-03 -3.1716849956166665e-03 +65547 -6.8346051031379187e-04 1.4269967526595148e-03 -5.1908655600957226e-03 +65537 -8.6233453210128629e-04 6.5238125861394160e-03 -3.7603748025841180e-03 +65538 -2.0035485175081927e-02 6.1098481347540918e-03 1.7638834216090409e-02 +41340 -4.6576371710238193e-03 -1.1654104516993939e-02 -1.3773539799737619e-02 +101772 1.0911313320299220e-02 6.3510120728270860e-03 4.9522483493955431e-03 +41325 -2.6734468427113651e-02 9.1841923890378010e-03 -1.5328834252099265e-02 +41319 -9.1885019050582458e-04 -2.3029331976552095e-03 -2.7045144890137820e-03 +41317 -7.7654576230394307e-04 -5.5073614356975220e-03 -1.9202412214231046e-04 +41315 -1.7385686807141081e-03 1.5446300205458365e-03 1.9952832947580691e-03 +195805 -7.6598832481870769e-03 -5.1231059839508437e-03 -1.9890091940218860e-02 +195796 -1.1732064842694759e-03 -5.7497907053340896e-04 7.3157052031676490e-03 +195794 -8.6088113370853675e-03 -6.5484403401288764e-03 -1.2799674075156021e-02 +195795 -1.4996948131837684e-03 -2.7153802298280631e-03 -3.3985451066914211e-03 +150146 8.5964742262872283e-03 -1.1565212543638292e-02 6.2814871480959935e-03 +41321 6.9280720042544843e-03 -4.3686337166906584e-03 7.3581863700124467e-04 +41324 -2.8389899116042323e-03 1.3909468247823161e-02 4.3114594454619071e-03 +41323 -9.0125774083012790e-03 -5.0493438449767574e-03 -2.1434692510532635e-03 +41322 -1.5812355932370424e-02 1.0710941844899499e-02 6.2428080224479106e-03 +69392 -2.2546399596842053e-02 -1.8075810155354460e-02 5.0186567866324847e-03 +69390 1.1749781995426265e-03 -1.2749343383937184e-02 -2.5956074184824659e-03 +150145 2.9746343212151099e-03 2.9112464133544827e-03 -1.0105992832620007e-03 +150148 -2.7954531733395370e-03 -2.3070997870378741e-03 5.5980707473674289e-04 +150147 2.9436340567068199e-03 6.6274995352233522e-04 -1.7502135011225556e-03 +150158 -1.0014277667394864e-04 1.3345167443974380e-02 -1.2140518537356060e-02 +150157 -9.1176651172342471e-03 1.9161783922648184e-03 -1.7139066698174422e-02 +150149 8.4287523879888852e-03 -4.7408530887962617e-03 -7.0065798885690644e-04 +150150 5.9355600264354323e-03 -1.1442321105025752e-02 2.3098532485127263e-02 +69391 -9.2567222081355507e-03 2.5762644773261217e-02 1.4488482901383315e-03 +195793 -3.1158880581649206e-03 -7.0200266776289924e-03 7.8927832477760987e-03 +195803 3.9818115630686178e-03 -6.1024578419483135e-03 -4.8112538337763359e-03 +195802 -3.0570223177208761e-04 -2.9386036278753597e-02 7.0349341449799417e-03 +195801 5.2394953658191001e-03 9.1732533954368249e-03 3.1141270890654572e-04 +195800 1.7461569943837544e-03 4.0749677240683416e-02 1.0013003501743011e-02 +195797 1.7271750759534229e-03 2.3563819438706256e-03 7.5571688880444535e-03 +195799 1.6429099368351701e-03 4.5996046044822895e-04 -5.0654846345272089e-03 +195798 1.1001462298366805e-02 8.3858904779092313e-03 -3.3785909017681262e-03 +195804 -1.7296703116988605e-03 -1.7697327664914005e-02 8.5202162561649492e-03 +107226 -1.7331359261464195e-02 -3.0656969501809961e-03 -2.0157585732793516e-02 +107225 -3.5089078950579526e-03 7.9908038122458825e-05 -2.0549368746707371e-03 +43050 1.3308282236893442e-02 -1.9700033358625919e-02 1.0063042575124281e-02 +43049 -7.6186047983919196e-03 -2.8674634899580310e-03 4.5672905010358013e-03 +43051 1.6816862530873065e-03 -6.3271333424715836e-03 3.1966940544481534e-03 +43052 1.1101246737904471e-02 -2.7500007475214173e-02 1.2946853284945686e-02 +160474 1.0191231333280013e-02 1.6542569362786894e-02 -4.8086367671814206e-03 +43048 4.1304191245269536e-03 -9.6664493035188166e-03 1.7935667373089936e-02 +188724 -5.1975814552116884e-04 1.4631396054558342e-02 4.7299610442206614e-03 +188733 -2.7873452889993384e-02 1.2473853177297456e-02 1.4566554091484172e-02 +188734 -2.3911430844619536e-03 4.1678601894228583e-03 1.0523340557520730e-02 +188735 -7.0801718316105614e-03 4.4860133083137023e-03 -1.3973977234744157e-02 +43047 -1.4795679520736254e-03 -3.3265508294681905e-03 -8.3734303841242422e-03 +43045 -4.0265248091229796e-03 8.0349934652097204e-03 -1.7599504163315438e-03 +3053 1.7224357096979497e-02 3.5458829635939999e-02 3.6002747086972837e-03 +188722 -9.8212554448490110e-03 -9.0722203116146601e-03 1.3272184510909137e-02 +188721 1.9412771888515235e-03 -4.4699900251273508e-03 3.8658118576122263e-03 +3055 -1.0481165616355119e-02 -2.2885224468318546e-02 3.4105973508173040e-03 +3048 -3.8544097846844529e-03 -1.3138759658280713e-02 -3.9042582782915585e-03 +188731 2.8494075759158554e-03 1.1866122837661180e-02 9.1245321002059903e-04 +3054 -2.1216653303811474e-03 2.3713097765709016e-03 7.5315521509730461e-03 +3056 2.3069793629581111e-02 -1.4968995116384637e-02 1.0648281155553595e-02 +3046 -2.0460770227470892e-02 3.0144778758524836e-04 2.1317712207427685e-02 +188732 -1.8281144438483871e-03 -1.1261657685967043e-02 1.1561377925901985e-02 +3044 -5.9884526016642653e-03 3.3295170562367797e-03 -5.7072534228267519e-04 +3047 -4.5626331700614377e-04 3.0971491279442806e-03 -2.4029872771577656e-03 +3043 -4.4454572400557365e-03 -7.6632255493806955e-03 5.5714893931939251e-03 +3045 6.1822444895057284e-03 6.6714925326779974e-03 1.5853041589859675e-03 +101766 -2.1458444025968314e-02 -2.5444654112521999e-03 5.8443943342134635e-03 +101765 -5.0238024773627083e-03 5.6425955495419578e-04 1.5607573277286874e-03 +101768 1.3464094865409271e-02 2.4281015477592219e-02 5.3310699991396355e-03 +101770 -4.4451927612641729e-03 -2.7815717596421690e-02 -1.6333131847475500e-02 +101769 9.5556056066472259e-04 1.0579336291235283e-03 3.2876877431821908e-03 +101767 -1.3195206140247649e-03 2.8620575981464927e-03 6.9494145796683664e-03 +107227 -7.9393117929594109e-03 -2.6951728063767852e-03 -3.5504552957331117e-03 +108387 6.5062699201118646e-03 4.8334061939892101e-04 4.8677336839467985e-03 +108397 -7.8045605958057653e-03 1.2779059039902910e-02 1.0199245897299205e-02 +107217 1.0055130403876900e-02 -1.0465065338913601e-02 6.4885472073673246e-03 +107935 1.1211029199945733e-02 1.3279344243719089e-02 -8.1421545624445653e-03 +107933 -2.5074645215093297e-03 -3.3608116180463853e-02 -8.7759598361912446e-03 +107934 4.3630785569980599e-03 -7.3262449730214516e-03 -4.9702928323268390e-04 +107924 1.5858335103752397e-03 -6.4236616011150325e-03 -6.3145478319536832e-03 +107923 -1.1691114243010869e-02 -2.6132526052943480e-03 5.8259792906919282e-03 +107228 2.5723102304711070e-03 1.8969683778003933e-02 -4.1866716393140447e-03 +107936 -5.4678218513997355e-04 5.5669869175223568e-04 -4.3101055117239481e-02 +160479 3.4501662683352828e-02 2.9913518177340927e-04 -4.3250681509590140e-02 +107921 6.2983034191229420e-03 3.4484229430888137e-03 2.3049203849430143e-03 +107922 -3.3769140568511904e-03 1.8794033081416542e-02 -1.6496813943305891e-02 +107218 -3.0889032207105705e-03 2.3663544289661396e-04 -1.8121891586601914e-03 +108388 6.6752875665062488e-04 7.1838180565699144e-03 -3.3892317399802948e-03 +108399 1.3381268534931896e-02 -2.9088903387031562e-02 1.5490840830516450e-02 +108398 5.3504427431495241e-03 -8.4373535441966123e-04 1.7407361182703821e-03 +101776 -4.4229912609814771e-02 -1.2601183038357919e-02 1.0454766560285456e-03 +101775 -6.7661508494878475e-03 -2.0128944968707908e-02 1.3392250819698175e-03 +101774 8.8460616756493686e-03 -4.1840236079397560e-04 -4.5869622510927481e-03 +101764 -2.4616713101414359e-03 -1.8370176375787708e-03 2.4221242856289236e-03 +101773 1.9068324416344356e-02 -2.2416525675832060e-02 2.3631320938171878e-02 +101763 -4.6841884146008334e-03 -5.1533769491571239e-03 3.0773962394947921e-03 +101762 -4.6244612567492736e-03 -4.8907730218283561e-03 -2.4065994260735329e-03 +179272 -5.5640577174611121e-03 -8.0026913196123862e-03 9.1238863542354894e-03 +179270 -3.4663284666564950e-03 3.7327894844247110e-04 -1.8090164399996302e-02 +179271 -9.2512252325061984e-03 5.0292798915460612e-03 2.2087977951300956e-03 +65546 2.1022467060548392e-02 2.6012539191398815e-02 -4.0199199904540503e-02 +65548 -9.6925158665221688e-03 -7.6373757136848621e-03 -1.4022141632720348e-02 +101761 -2.4320225549836435e-03 1.7250815303594810e-03 9.0081186862997703e-04 +101771 -1.9996688975715249e-03 -5.6054082987894022e-03 4.5581765470880699e-03 +41339 3.1266677423361358e-03 5.9205052600478040e-03 -4.3339978463310851e-03 +41329 -9.8874045639901049e-04 -4.4750448363508602e-03 -3.4869981536843303e-03 +41343 -2.4016025797634774e-02 1.3175639791008605e-02 -4.6023020275273420e-02 +41342 -1.6716684647333912e-03 1.2459605567751943e-03 1.6068248832533532e-03 +41344 2.0325206636661194e-03 -3.0576895440245786e-03 1.1529498097307186e-02 +41330 2.5654903283602731e-02 2.3132228675317019e-02 1.1575874948668132e-02 +41341 -1.6553222660923881e-02 -1.1798485936730465e-02 -7.1873185555086112e-03 +41331 3.5346668585989967e-03 -2.0027759583546895e-03 -3.2889000031485196e-03 +41332 -2.5959229467918217e-03 -6.0602511790796782e-03 -9.3197710616591545e-03 +179276 1.1081427178681628e-02 1.6827323566739161e-02 -1.0299144743739620e-02 +108385 3.6564384223645233e-03 -4.9013600239771631e-04 1.3295156103955909e-03 +160480 -1.3803088794372316e-02 1.2219159767395200e-02 -1.3669800258940099e-03 +108386 4.1801973472378271e-03 -1.4647913911541162e-02 -1.6678122787186375e-02 +160478 3.8996210243085277e-03 6.7271423575770151e-03 -3.6784375058656509e-04 +160468 7.7419765741400326e-03 4.9138244434877576e-03 1.4031431499399972e-03 +160470 -6.2985622565362442e-03 7.4451997711637531e-03 2.8430316550356185e-02 +160472 -5.8383103703068037e-03 6.1929502851055824e-03 2.6819505985616384e-02 +160471 6.4540703717117969e-03 -8.0301907905106495e-03 3.8441043125357851e-03 +160469 -3.2190187970246821e-03 1.1026423392606606e-03 -6.4552121634166284e-03 +160473 -8.9124820567448894e-03 1.8453491165932152e-03 -5.5339629598225243e-03 +160476 4.3077321271397942e-03 -1.0514055910875600e-02 1.1874230774763071e-02 +160475 2.0892466118949786e-03 -4.5629240557269512e-03 2.9807140626559279e-03 +160465 -3.3040123862153868e-03 -6.4718982960261595e-03 1.5540054129147744e-03 +160466 -1.0482164269847657e-02 -4.2613706143882239e-03 -2.0407827062661702e-02 +160467 -2.0886745076283074e-03 7.3566125280433870e-03 -8.1361111572777461e-03 +150159 -9.3474335633482227e-03 6.8552724395616188e-03 3.0172635792791409e-02 +150160 -1.2395823331379360e-02 -1.8814096766422796e-02 -2.2588032834368797e-02 +179274 2.7142693103844345e-02 2.0981214151002650e-03 1.7741159681900803e-02 +179278 -4.7312726933158031e-03 -5.3735482175190251e-03 5.0258788007287686e-04 +179268 1.0476052676472475e-03 3.8663965130026762e-03 -5.2311881655905329e-03 +179266 1.5328249586214907e-03 -2.4374978186068715e-02 -1.2316372207153982e-02 +179280 2.0962579240811956e-02 -1.7552180709176319e-02 3.1310438513877256e-02 +179267 -2.9815916434868302e-03 3.3669678375885131e-03 -4.5604241127206076e-03 +179275 -3.4616159250607549e-03 -4.9052370217731742e-03 -5.9504393252170652e-03 +179265 -3.2638688398942024e-03 -2.8294419416218710e-03 9.7598020577956447e-03 +179269 -6.3820035949712006e-03 7.6268830685192008e-03 3.5859597533587175e-03 +179273 5.2814394103648347e-03 -2.6248694818828103e-03 -4.5226597201537379e-03 +179277 -1.2041210428484460e-03 -2.8617212529418956e-02 -6.1633779650706868e-03 +160477 1.0644756920882860e-02 1.1349322679914857e-03 8.4219222047503886e-03 +3050 -9.1677754946678826e-03 4.2780587837938129e-04 7.7954711472101390e-03 +3042 -9.5136449774802789e-03 -7.8088403318419732e-03 1.6481979622031205e-03 +3041 -4.2224554129104853e-03 -1.0046580459806016e-03 -1.2299765014357915e-02 +3049 3.3392704605801570e-03 3.2803849005614411e-04 -3.7962761566625422e-03 +3051 -1.4534919223640852e-03 1.6840179829874765e-03 -5.2689712045377035e-03 +3052 1.3121899362414865e-02 -6.1819078882882419e-03 -3.8070979101547178e-03 +179279 2.1031999741751132e-02 5.5208009434861991e-03 -4.0676368831269122e-03 +41338 1.4140591805763124e-02 -5.2322347712404904e-03 -1.2597608959408814e-02 +41336 2.9970177174658653e-02 -1.2564552612506892e-02 1.8546500897758786e-03 +41337 -1.0927245121297971e-03 -5.5983348471985855e-03 -2.6702824643818425e-04 +41335 3.8391554220007697e-03 4.9415840280308326e-03 3.8850792189150537e-04 +41333 -7.9995524811572705e-04 1.2714683204333441e-03 2.6878865364424981e-03 +41334 -8.1923367811546216e-04 3.8003884561477940e-03 -1.3493487265120480e-02 + +Bonds + +1 1 111365 111366 +2 2 111365 111367 +3 5 111364 111374 +4 4 111373 111364 +5 1 107223 107224 +6 2 107223 107225 +7 1 40599 40600 +8 2 40599 40601 +9 1 40597 40598 +10 2 40597 40599 +11 1 111367 111368 +12 2 111367 111369 +13 3 188723 188724 +14 2 188723 188725 +15 6 188736 188734 +16 6 41360 41358 +17 6 111375 111374 +18 6 41359 41358 +19 1 188725 188726 +20 2 188725 188727 +21 1 188729 188730 +22 2 188729 188731 +23 1 188727 188728 +24 2 188727 188729 +25 6 20160 20158 +26 5 20148 20158 +27 4 20157 20148 +28 1 41355 41356 +29 1 108389 108390 +30 2 108389 108391 +31 6 41327 41326 +32 6 41328 41326 +33 1 108391 108392 +34 2 108391 108393 +35 1 41353 41354 +36 2 41353 41355 +37 1 41351 41352 +38 2 41351 41353 +39 1 107221 107222 +40 2 107221 107223 +41 3 107219 107220 +42 2 107219 107221 +43 6 107232 107230 +44 1 41345 41346 +45 2 41345 41347 +46 2 41345 41355 +47 3 41347 41348 +48 2 41347 41349 +49 4 41357 41348 +50 5 41348 41358 +51 1 41349 41350 +52 2 41349 41351 +53 6 108400 108398 +54 5 107220 107230 +55 4 107229 107220 +56 6 65551 65550 +57 6 107231 107230 +58 1 148087 148088 +59 2 148087 148089 +60 1 148089 148090 +61 2 148089 148091 +62 1 40603 40604 +63 1 40601 40602 +64 2 40601 40603 +65 1 40593 40594 +66 2 40593 40595 +67 2 40593 40603 +68 3 40595 40596 +69 2 40595 40597 +70 5 41316 41326 +71 1 108393 108394 +72 2 108393 108395 +73 1 41313 41314 +74 2 41313 41315 +75 2 41313 41323 +76 1 108395 108396 +77 6 148096 148094 +78 6 148095 148094 +79 6 40608 40606 +80 6 40607 40606 +81 4 40605 40596 +82 5 40596 40606 +83 4 148093 148084 +84 5 148084 148094 +85 1 148085 148086 +86 2 148085 148087 +87 3 148083 148084 +88 2 148083 148085 +89 6 20159 20158 +90 1 148081 148082 +91 2 148081 148083 +92 2 148081 148091 +93 1 148091 148092 +94 3 111363 111364 +95 2 111363 111365 +96 1 111369 111370 +97 2 111369 111371 +98 1 111371 111372 +99 1 111361 111362 +100 2 111361 111363 +101 2 111361 111371 +102 6 43056 43054 +103 6 195807 195806 +104 6 195808 195806 +105 1 43041 43042 +106 2 43041 43043 +107 2 43041 43051 +108 3 43043 43044 +109 2 43043 43045 +110 6 43055 43054 +111 5 43044 43054 +112 1 150155 150156 +113 6 111376 111374 +114 1 150153 150154 +115 2 150153 150155 +116 1 150151 150152 +117 2 150151 150153 +118 4 43053 43044 +119 1 20155 20156 +120 1 20145 20146 +121 2 20145 20147 +122 2 20145 20155 +123 1 20149 20150 +124 2 20149 20151 +125 1 20153 20154 +126 2 20153 20155 +127 1 20151 20152 +128 2 20151 20153 +129 3 20147 20148 +130 2 20147 20149 +131 4 65549 65540 +132 1 107925 107926 +133 2 107925 107927 +134 1 107927 107928 +135 2 107927 107929 +136 1 107931 107932 +137 1 107929 107930 +138 2 107929 107931 +139 1 69385 69386 +140 2 69385 69387 +141 1 69387 69388 +142 3 69379 69380 +143 2 69379 69381 +144 1 69377 69378 +145 2 69377 69379 +146 2 69377 69387 +147 1 69383 69384 +148 2 69383 69385 +149 1 69381 69382 +150 2 69381 69383 +151 6 65552 65550 +152 5 65540 65550 +153 4 69389 69380 +154 5 69380 69390 +155 3 65539 65540 +156 2 65539 65541 +157 1 65543 65544 +158 2 65543 65545 +159 1 65541 65542 +160 2 65541 65543 +161 1 65545 65546 +162 2 65545 65547 +163 1 65547 65548 +164 1 65537 65538 +165 2 65537 65539 +166 2 65537 65547 +167 4 41325 41316 +168 1 41319 41320 +169 2 41319 41321 +170 1 41317 41318 +171 2 41317 41319 +172 3 41315 41316 +173 2 41315 41317 +174 4 195805 195796 +175 5 195796 195806 +176 3 195795 195796 +177 2 195795 195797 +178 1 41321 41322 +179 2 41321 41323 +180 1 41323 41324 +181 6 69392 69390 +182 1 150145 150146 +183 2 150145 150147 +184 2 150145 150155 +185 5 150148 150158 +186 3 150147 150148 +187 2 150147 150149 +188 4 150157 150148 +189 1 150149 150150 +190 2 150149 150151 +191 6 69391 69390 +192 1 195793 195794 +193 2 195793 195795 +194 2 195793 195803 +195 1 195803 195804 +196 1 195801 195802 +197 2 195801 195803 +198 1 195797 195798 +199 2 195797 195799 +200 1 195799 195800 +201 2 195799 195801 +202 1 107225 107226 +203 2 107225 107227 +204 1 43049 43050 +205 2 43049 43051 +206 1 43051 43052 +207 5 188724 188734 +208 4 188733 188724 +209 6 188735 188734 +210 1 43047 43048 +211 2 43047 43049 +212 1 43045 43046 +213 2 43045 43047 +214 4 3053 3044 +215 1 188721 188722 +216 2 188721 188723 +217 2 188721 188731 +218 6 3055 3054 +219 1 188731 188732 +220 6 3056 3054 +221 5 3044 3054 +222 1 3047 3048 +223 2 3047 3049 +224 3 3043 3044 +225 2 3043 3045 +226 1 3045 3046 +227 2 3045 3047 +228 1 101765 101766 +229 2 101765 101767 +230 1 101769 101770 +231 2 101769 101771 +232 1 101767 101768 +233 2 101767 101769 +234 1 107227 107228 +235 3 108387 108388 +236 2 108387 108389 +237 4 108397 108388 +238 1 107217 107218 +239 2 107217 107219 +240 2 107217 107227 +241 6 107935 107934 +242 4 107933 107924 +243 5 107924 107934 +244 3 107923 107924 +245 2 107923 107925 +246 6 107936 107934 +247 6 160479 160478 +248 1 107921 107922 +249 2 107921 107923 +250 2 107921 107931 +251 5 108388 108398 +252 6 108399 108398 +253 6 101776 101774 +254 6 101775 101774 +255 5 101764 101774 +256 4 101773 101764 +257 3 101763 101764 +258 2 101763 101765 +259 1 179271 179272 +260 2 179271 179273 +261 1 101761 101762 +262 2 101761 101763 +263 2 101761 101771 +264 1 101771 101772 +265 1 41339 41340 +266 1 41329 41330 +267 2 41329 41331 +268 2 41329 41339 +269 6 41343 41342 +270 6 41344 41342 +271 4 41341 41332 +272 3 41331 41332 +273 2 41331 41333 +274 5 41332 41342 +275 1 108385 108386 +276 2 108385 108387 +277 2 108385 108395 +278 6 160480 160478 +279 5 160468 160478 +280 1 160471 160472 +281 2 160471 160473 +282 1 160469 160470 +283 2 160469 160471 +284 1 160473 160474 +285 2 160473 160475 +286 1 160475 160476 +287 1 160465 160466 +288 2 160465 160467 +289 2 160465 160475 +290 3 160467 160468 +291 2 160467 160469 +292 6 150159 150158 +293 6 150160 150158 +294 5 179268 179278 +295 6 179280 179278 +296 3 179267 179268 +297 2 179267 179269 +298 1 179275 179276 +299 1 179265 179266 +300 2 179265 179267 +301 2 179265 179275 +302 1 179269 179270 +303 2 179269 179271 +304 1 179273 179274 +305 2 179273 179275 +306 4 179277 179268 +307 4 160477 160468 +308 1 3041 3042 +309 2 3041 3043 +310 2 3041 3051 +311 1 3049 3050 +312 2 3049 3051 +313 1 3051 3052 +314 6 179279 179278 +315 1 41337 41338 +316 2 41337 41339 +317 1 41335 41336 +318 2 41335 41337 +319 1 41333 41334 +320 2 41333 41335 + +Angles + +1 1 111363 111365 111366 +2 2 111363 111365 111367 +3 1 111367 111365 111366 +4 4 111363 111364 111373 +5 5 111363 111364 111374 +6 6 111373 111364 111374 +7 1 107221 107223 107224 +8 2 107221 107223 107225 +9 1 107225 107223 107224 +10 1 40597 40599 40600 +11 2 40597 40599 40601 +12 1 40601 40599 40600 +13 1 40595 40597 40598 +14 2 40595 40597 40599 +15 1 40599 40597 40598 +16 1 111365 111367 111368 +17 2 111365 111367 111369 +18 1 111369 111367 111368 +19 3 188721 188723 188724 +20 2 188721 188723 188725 +21 3 188725 188723 188724 +22 1 188723 188725 188726 +23 2 188723 188725 188727 +24 1 188727 188725 188726 +25 1 188727 188729 188730 +26 2 188727 188729 188731 +27 1 188731 188729 188730 +28 1 188725 188727 188728 +29 2 188725 188727 188729 +30 1 188729 188727 188728 +31 7 20159 20158 20148 +32 7 20160 20158 20148 +33 8 20159 20158 20160 +34 4 20147 20148 20157 +35 5 20147 20148 20158 +36 6 20157 20148 20158 +37 2 41345 41355 41353 +38 1 41345 41355 41356 +39 1 41353 41355 41356 +40 1 108387 108389 108390 +41 2 108387 108389 108391 +42 1 108391 108389 108390 +43 7 41327 41326 41316 +44 7 41328 41326 41316 +45 8 41327 41326 41328 +46 1 108389 108391 108392 +47 2 108389 108391 108393 +48 1 108393 108391 108392 +49 1 41351 41353 41354 +50 2 41351 41353 41355 +51 1 41355 41353 41354 +52 1 41349 41351 41352 +53 2 41349 41351 41353 +54 1 41353 41351 41352 +55 1 107219 107221 107222 +56 2 107219 107221 107223 +57 1 107223 107221 107222 +58 3 107217 107219 107220 +59 2 107217 107219 107221 +60 3 107221 107219 107220 +61 1 41347 41345 41346 +62 1 41355 41345 41346 +63 2 41347 41345 41355 +64 3 41345 41347 41348 +65 2 41345 41347 41349 +66 3 41349 41347 41348 +67 7 41359 41358 41348 +68 7 41360 41358 41348 +69 8 41359 41358 41360 +70 4 41347 41348 41357 +71 5 41347 41348 41358 +72 6 41357 41348 41358 +73 1 41347 41349 41350 +74 2 41347 41349 41351 +75 1 41351 41349 41350 +76 4 107219 107220 107229 +77 5 107219 107220 107230 +78 6 107229 107220 107230 +79 7 107231 107230 107220 +80 7 107232 107230 107220 +81 8 107231 107230 107232 +82 1 148085 148087 148088 +83 2 148085 148087 148089 +84 1 148089 148087 148088 +85 1 148087 148089 148090 +86 2 148087 148089 148091 +87 1 148091 148089 148090 +88 2 40593 40603 40601 +89 1 40593 40603 40604 +90 1 40601 40603 40604 +91 1 40599 40601 40602 +92 2 40599 40601 40603 +93 1 40603 40601 40602 +94 1 40595 40593 40594 +95 1 40603 40593 40594 +96 2 40595 40593 40603 +97 3 40593 40595 40596 +98 2 40593 40595 40597 +99 3 40597 40595 40596 +100 4 41315 41316 41325 +101 5 41315 41316 41326 +102 6 41325 41316 41326 +103 1 108391 108393 108394 +104 2 108391 108393 108395 +105 1 108395 108393 108394 +106 1 41315 41313 41314 +107 1 41323 41313 41314 +108 2 41315 41313 41323 +109 2 108385 108395 108393 +110 1 108385 108395 108396 +111 1 108393 108395 108396 +112 7 148095 148094 148084 +113 7 148096 148094 148084 +114 8 148095 148094 148096 +115 7 40607 40606 40596 +116 7 40608 40606 40596 +117 8 40607 40606 40608 +118 4 40595 40596 40605 +119 5 40595 40596 40606 +120 6 40605 40596 40606 +121 4 148083 148084 148093 +122 5 148083 148084 148094 +123 6 148093 148084 148094 +124 1 148083 148085 148086 +125 2 148083 148085 148087 +126 1 148087 148085 148086 +127 3 148081 148083 148084 +128 2 148081 148083 148085 +129 3 148085 148083 148084 +130 1 148083 148081 148082 +131 1 148091 148081 148082 +132 2 148083 148081 148091 +133 2 148081 148091 148089 +134 1 148081 148091 148092 +135 1 148089 148091 148092 +136 3 111361 111363 111364 +137 2 111361 111363 111365 +138 3 111365 111363 111364 +139 1 111367 111369 111370 +140 2 111367 111369 111371 +141 1 111371 111369 111370 +142 2 111361 111371 111369 +143 1 111361 111371 111372 +144 1 111369 111371 111372 +145 1 111363 111361 111362 +146 1 111371 111361 111362 +147 2 111363 111361 111371 +148 7 195807 195806 195796 +149 7 195808 195806 195796 +150 8 195807 195806 195808 +151 1 43043 43041 43042 +152 1 43051 43041 43042 +153 2 43043 43041 43051 +154 3 43041 43043 43044 +155 2 43041 43043 43045 +156 3 43045 43043 43044 +157 4 43043 43044 43053 +158 5 43043 43044 43054 +159 6 43053 43044 43054 +160 7 43055 43054 43044 +161 7 43056 43054 43044 +162 8 43055 43054 43056 +163 2 150145 150155 150153 +164 1 150145 150155 150156 +165 1 150153 150155 150156 +166 7 111375 111374 111364 +167 7 111376 111374 111364 +168 8 111375 111374 111376 +169 1 150151 150153 150154 +170 2 150151 150153 150155 +171 1 150155 150153 150154 +172 1 150149 150151 150152 +173 2 150149 150151 150153 +174 1 150153 150151 150152 +175 2 20145 20155 20153 +176 1 20145 20155 20156 +177 1 20153 20155 20156 +178 1 20147 20145 20146 +179 1 20155 20145 20146 +180 2 20147 20145 20155 +181 1 20147 20149 20150 +182 2 20147 20149 20151 +183 1 20151 20149 20150 +184 1 20151 20153 20154 +185 2 20151 20153 20155 +186 1 20155 20153 20154 +187 1 20149 20151 20152 +188 2 20149 20151 20153 +189 1 20153 20151 20152 +190 3 20145 20147 20148 +191 2 20145 20147 20149 +192 3 20149 20147 20148 +193 1 107923 107925 107926 +194 2 107923 107925 107927 +195 1 107927 107925 107926 +196 1 107925 107927 107928 +197 2 107925 107927 107929 +198 1 107929 107927 107928 +199 2 107921 107931 107929 +200 1 107921 107931 107932 +201 1 107929 107931 107932 +202 1 107927 107929 107930 +203 2 107927 107929 107931 +204 1 107931 107929 107930 +205 1 69383 69385 69386 +206 2 69383 69385 69387 +207 1 69387 69385 69386 +208 2 69377 69387 69385 +209 1 69377 69387 69388 +210 1 69385 69387 69388 +211 3 69377 69379 69380 +212 2 69377 69379 69381 +213 3 69381 69379 69380 +214 1 69379 69377 69378 +215 1 69387 69377 69378 +216 2 69379 69377 69387 +217 1 69381 69383 69384 +218 2 69381 69383 69385 +219 1 69385 69383 69384 +220 1 69379 69381 69382 +221 2 69379 69381 69383 +222 1 69383 69381 69382 +223 7 65551 65550 65540 +224 7 65552 65550 65540 +225 8 65551 65550 65552 +226 4 65539 65540 65549 +227 5 65539 65540 65550 +228 6 65549 65540 65550 +229 4 69379 69380 69389 +230 5 69379 69380 69390 +231 6 69389 69380 69390 +232 3 65537 65539 65540 +233 2 65537 65539 65541 +234 3 65541 65539 65540 +235 1 65541 65543 65544 +236 2 65541 65543 65545 +237 1 65545 65543 65544 +238 1 65539 65541 65542 +239 2 65539 65541 65543 +240 1 65543 65541 65542 +241 1 65543 65545 65546 +242 2 65543 65545 65547 +243 1 65547 65545 65546 +244 2 65537 65547 65545 +245 1 65537 65547 65548 +246 1 65545 65547 65548 +247 1 65539 65537 65538 +248 1 65547 65537 65538 +249 2 65539 65537 65547 +250 1 41317 41319 41320 +251 2 41317 41319 41321 +252 1 41321 41319 41320 +253 1 41315 41317 41318 +254 2 41315 41317 41319 +255 1 41319 41317 41318 +256 3 41313 41315 41316 +257 2 41313 41315 41317 +258 3 41317 41315 41316 +259 4 195795 195796 195805 +260 5 195795 195796 195806 +261 6 195805 195796 195806 +262 3 195793 195795 195796 +263 2 195793 195795 195797 +264 3 195797 195795 195796 +265 1 41319 41321 41322 +266 2 41319 41321 41323 +267 1 41323 41321 41322 +268 2 41313 41323 41321 +269 1 41313 41323 41324 +270 1 41321 41323 41324 +271 7 69391 69390 69380 +272 7 69392 69390 69380 +273 8 69391 69390 69392 +274 1 150147 150145 150146 +275 1 150155 150145 150146 +276 2 150147 150145 150155 +277 4 150147 150148 150157 +278 5 150147 150148 150158 +279 6 150157 150148 150158 +280 3 150145 150147 150148 +281 2 150145 150147 150149 +282 3 150149 150147 150148 +283 7 150159 150158 150148 +284 7 150160 150158 150148 +285 8 150159 150158 150160 +286 1 150147 150149 150150 +287 2 150147 150149 150151 +288 1 150151 150149 150150 +289 1 195795 195793 195794 +290 1 195803 195793 195794 +291 2 195795 195793 195803 +292 2 195793 195803 195801 +293 1 195793 195803 195804 +294 1 195801 195803 195804 +295 1 195799 195801 195802 +296 2 195799 195801 195803 +297 1 195803 195801 195802 +298 1 195795 195797 195798 +299 2 195795 195797 195799 +300 1 195799 195797 195798 +301 1 195797 195799 195800 +302 2 195797 195799 195801 +303 1 195801 195799 195800 +304 1 107223 107225 107226 +305 2 107223 107225 107227 +306 1 107227 107225 107226 +307 1 43047 43049 43050 +308 2 43047 43049 43051 +309 1 43051 43049 43050 +310 2 43041 43051 43049 +311 1 43041 43051 43052 +312 1 43049 43051 43052 +313 4 188723 188724 188733 +314 5 188723 188724 188734 +315 6 188733 188724 188734 +316 7 188735 188734 188724 +317 7 188736 188734 188724 +318 8 188735 188734 188736 +319 1 43045 43047 43048 +320 2 43045 43047 43049 +321 1 43049 43047 43048 +322 1 43043 43045 43046 +323 2 43043 43045 43047 +324 1 43047 43045 43046 +325 1 188723 188721 188722 +326 1 188731 188721 188722 +327 2 188723 188721 188731 +328 2 188721 188731 188729 +329 1 188721 188731 188732 +330 1 188729 188731 188732 +331 7 3055 3054 3044 +332 7 3056 3054 3044 +333 8 3055 3054 3056 +334 4 3043 3044 3053 +335 5 3043 3044 3054 +336 6 3053 3044 3054 +337 1 3045 3047 3048 +338 2 3045 3047 3049 +339 1 3049 3047 3048 +340 3 3041 3043 3044 +341 2 3041 3043 3045 +342 3 3045 3043 3044 +343 1 3043 3045 3046 +344 2 3043 3045 3047 +345 1 3047 3045 3046 +346 1 101763 101765 101766 +347 2 101763 101765 101767 +348 1 101767 101765 101766 +349 1 101767 101769 101770 +350 2 101767 101769 101771 +351 1 101771 101769 101770 +352 1 101765 101767 101768 +353 2 101765 101767 101769 +354 1 101769 101767 101768 +355 2 107217 107227 107225 +356 1 107217 107227 107228 +357 1 107225 107227 107228 +358 3 108385 108387 108388 +359 2 108385 108387 108389 +360 3 108389 108387 108388 +361 1 107219 107217 107218 +362 1 107227 107217 107218 +363 2 107219 107217 107227 +364 7 107935 107934 107924 +365 7 107936 107934 107924 +366 8 107935 107934 107936 +367 4 107923 107924 107933 +368 5 107923 107924 107934 +369 6 107933 107924 107934 +370 3 107921 107923 107924 +371 2 107921 107923 107925 +372 3 107925 107923 107924 +373 1 107923 107921 107922 +374 1 107931 107921 107922 +375 2 107923 107921 107931 +376 4 108387 108388 108397 +377 5 108387 108388 108398 +378 6 108397 108388 108398 +379 7 108399 108398 108388 +380 7 108400 108398 108388 +381 8 108399 108398 108400 +382 7 101775 101774 101764 +383 7 101776 101774 101764 +384 8 101775 101774 101776 +385 4 101763 101764 101773 +386 5 101763 101764 101774 +387 6 101773 101764 101774 +388 3 101761 101763 101764 +389 2 101761 101763 101765 +390 3 101765 101763 101764 +391 1 179269 179271 179272 +392 2 179269 179271 179273 +393 1 179273 179271 179272 +394 1 101763 101761 101762 +395 1 101771 101761 101762 +396 2 101763 101761 101771 +397 2 101761 101771 101769 +398 1 101761 101771 101772 +399 1 101769 101771 101772 +400 2 41329 41339 41337 +401 1 41329 41339 41340 +402 1 41337 41339 41340 +403 1 41331 41329 41330 +404 1 41339 41329 41330 +405 2 41331 41329 41339 +406 7 41343 41342 41332 +407 7 41344 41342 41332 +408 8 41343 41342 41344 +409 3 41329 41331 41332 +410 2 41329 41331 41333 +411 3 41333 41331 41332 +412 4 41331 41332 41341 +413 5 41331 41332 41342 +414 6 41341 41332 41342 +415 1 108387 108385 108386 +416 1 108395 108385 108386 +417 2 108387 108385 108395 +418 7 160479 160478 160468 +419 7 160480 160478 160468 +420 8 160479 160478 160480 +421 4 160467 160468 160477 +422 5 160467 160468 160478 +423 6 160477 160468 160478 +424 1 160469 160471 160472 +425 2 160469 160471 160473 +426 1 160473 160471 160472 +427 1 160467 160469 160470 +428 2 160467 160469 160471 +429 1 160471 160469 160470 +430 1 160471 160473 160474 +431 2 160471 160473 160475 +432 1 160475 160473 160474 +433 2 160465 160475 160473 +434 1 160465 160475 160476 +435 1 160473 160475 160476 +436 1 160467 160465 160466 +437 1 160475 160465 160466 +438 2 160467 160465 160475 +439 3 160465 160467 160468 +440 2 160465 160467 160469 +441 3 160469 160467 160468 +442 7 179279 179278 179268 +443 7 179280 179278 179268 +444 8 179279 179278 179280 +445 4 179267 179268 179277 +446 5 179267 179268 179278 +447 6 179277 179268 179278 +448 3 179265 179267 179268 +449 2 179265 179267 179269 +450 3 179269 179267 179268 +451 2 179265 179275 179273 +452 1 179265 179275 179276 +453 1 179273 179275 179276 +454 1 179267 179265 179266 +455 1 179275 179265 179266 +456 2 179267 179265 179275 +457 1 179267 179269 179270 +458 2 179267 179269 179271 +459 1 179271 179269 179270 +460 1 179271 179273 179274 +461 2 179271 179273 179275 +462 1 179275 179273 179274 +463 1 3043 3041 3042 +464 1 3051 3041 3042 +465 2 3043 3041 3051 +466 1 3047 3049 3050 +467 2 3047 3049 3051 +468 1 3051 3049 3050 +469 2 3041 3051 3049 +470 1 3041 3051 3052 +471 1 3049 3051 3052 +472 1 41335 41337 41338 +473 2 41335 41337 41339 +474 1 41339 41337 41338 +475 1 41333 41335 41336 +476 2 41333 41335 41337 +477 1 41337 41335 41336 +478 1 41331 41333 41334 +479 2 41331 41333 41335 +480 1 41335 41333 41334 + +Dihedrals + +1 1 111366 111365 111363 111364 +2 3 111367 111365 111363 111364 +3 2 111363 111365 111367 111368 +4 4 111363 111365 111367 111369 +5 5 111366 111365 111367 111368 +6 8 111363 111364 111374 111375 +7 8 111363 111364 111374 111376 +8 9 111373 111364 111374 111375 +9 9 111373 111364 111374 111376 +10 2 107225 107223 107221 107222 +11 2 107221 107223 107225 107226 +12 4 107221 107223 107225 107227 +13 5 107224 107223 107225 107226 +14 2 40601 40599 40597 40598 +15 2 40597 40599 40601 40602 +16 4 40597 40599 40601 40603 +17 5 40600 40599 40601 40602 +18 1 40598 40597 40595 40596 +19 3 40599 40597 40595 40596 +20 2 40595 40597 40599 40600 +21 4 40595 40597 40599 40601 +22 5 40598 40597 40599 40600 +23 2 111369 111367 111365 111366 +24 2 111365 111367 111369 111370 +25 4 111365 111367 111369 111371 +26 5 111368 111367 111369 111370 +27 2 188725 188723 188721 188722 +28 6 188721 188723 188724 188733 +29 7 188721 188723 188724 188734 +30 6 188725 188723 188724 188733 +31 7 188725 188723 188724 188734 +32 2 188721 188723 188725 188726 +33 4 188721 188723 188725 188727 +34 1 188726 188725 188723 188724 +35 3 188727 188725 188723 188724 +36 2 188723 188725 188727 188728 +37 4 188723 188725 188727 188729 +38 5 188726 188725 188727 188728 +39 2 188731 188729 188727 188728 +40 4 188727 188729 188731 188721 +41 2 188727 188729 188731 188732 +42 5 188730 188729 188731 188732 +43 2 188729 188727 188725 188726 +44 2 188725 188727 188729 188730 +45 4 188725 188727 188729 188731 +46 5 188728 188727 188729 188730 +47 8 20147 20148 20158 20159 +48 8 20147 20148 20158 20160 +49 9 20157 20148 20158 20159 +50 9 20157 20148 20158 20160 +51 2 41353 41355 41345 41346 +52 2 41345 41355 41353 41354 +53 1 108390 108389 108387 108388 +54 3 108391 108389 108387 108388 +55 2 108387 108389 108391 108392 +56 4 108387 108389 108391 108393 +57 5 108390 108389 108391 108392 +58 2 108393 108391 108389 108390 +59 2 108389 108391 108393 108394 +60 4 108389 108391 108393 108395 +61 5 108392 108391 108393 108394 +62 2 41355 41353 41351 41352 +63 4 41351 41353 41355 41345 +64 2 41351 41353 41355 41356 +65 5 41354 41353 41355 41356 +66 2 41353 41351 41349 41350 +67 2 41349 41351 41353 41354 +68 4 41349 41351 41353 41355 +69 5 41352 41351 41353 41354 +70 1 107222 107221 107219 107220 +71 3 107223 107221 107219 107220 +72 2 107219 107221 107223 107224 +73 4 107219 107221 107223 107225 +74 5 107222 107221 107223 107224 +75 2 107221 107219 107217 107218 +76 6 107217 107219 107220 107229 +77 7 107217 107219 107220 107230 +78 6 107221 107219 107220 107229 +79 7 107221 107219 107220 107230 +80 2 107217 107219 107221 107222 +81 4 107217 107219 107221 107223 +82 1 41346 41345 41347 41348 +83 3 41355 41345 41347 41348 +84 4 41355 41345 41347 41349 +85 5 41346 41345 41355 41356 +86 4 41347 41345 41355 41353 +87 2 41347 41345 41355 41356 +88 2 41349 41347 41345 41346 +89 6 41345 41347 41348 41357 +90 7 41345 41347 41348 41358 +91 6 41349 41347 41348 41357 +92 7 41349 41347 41348 41358 +93 2 41345 41347 41349 41350 +94 4 41345 41347 41349 41351 +95 8 41347 41348 41358 41359 +96 8 41347 41348 41358 41360 +97 9 41357 41348 41358 41359 +98 9 41357 41348 41358 41360 +99 1 41350 41349 41347 41348 +100 3 41351 41349 41347 41348 +101 2 41347 41349 41351 41352 +102 4 41347 41349 41351 41353 +103 5 41350 41349 41351 41352 +104 8 107219 107220 107230 107231 +105 8 107219 107220 107230 107232 +106 9 107229 107220 107230 107231 +107 9 107229 107220 107230 107232 +108 2 148089 148087 148085 148086 +109 2 148085 148087 148089 148090 +110 4 148085 148087 148089 148091 +111 5 148088 148087 148089 148090 +112 2 148091 148089 148087 148088 +113 4 148087 148089 148091 148081 +114 2 148087 148089 148091 148092 +115 5 148090 148089 148091 148092 +116 2 40601 40603 40593 40594 +117 2 40593 40603 40601 40602 +118 2 40603 40601 40599 40600 +119 4 40599 40601 40603 40593 +120 2 40599 40601 40603 40604 +121 5 40602 40601 40603 40604 +122 1 40594 40593 40595 40596 +123 3 40603 40593 40595 40596 +124 4 40603 40593 40595 40597 +125 5 40594 40593 40603 40604 +126 4 40595 40593 40603 40601 +127 2 40595 40593 40603 40604 +128 2 40597 40595 40593 40594 +129 6 40593 40595 40596 40605 +130 7 40593 40595 40596 40606 +131 6 40597 40595 40596 40605 +132 7 40597 40595 40596 40606 +133 2 40593 40595 40597 40598 +134 4 40593 40595 40597 40599 +135 8 41315 41316 41326 41327 +136 8 41315 41316 41326 41328 +137 9 41325 41316 41326 41327 +138 9 41325 41316 41326 41328 +139 2 108395 108393 108391 108392 +140 4 108391 108393 108395 108385 +141 2 108391 108393 108395 108396 +142 5 108394 108393 108395 108396 +143 1 41314 41313 41315 41316 +144 3 41323 41313 41315 41316 +145 4 41323 41313 41315 41317 +146 5 41314 41313 41323 41324 +147 4 41315 41313 41323 41321 +148 2 41315 41313 41323 41324 +149 2 108393 108395 108385 108386 +150 2 108385 108395 108393 108394 +151 8 40595 40596 40606 40607 +152 8 40595 40596 40606 40608 +153 9 40605 40596 40606 40607 +154 9 40605 40596 40606 40608 +155 8 148083 148084 148094 148095 +156 8 148083 148084 148094 148096 +157 9 148093 148084 148094 148095 +158 9 148093 148084 148094 148096 +159 1 148086 148085 148083 148084 +160 3 148087 148085 148083 148084 +161 2 148083 148085 148087 148088 +162 4 148083 148085 148087 148089 +163 5 148086 148085 148087 148088 +164 2 148085 148083 148081 148082 +165 6 148081 148083 148084 148093 +166 7 148081 148083 148084 148094 +167 6 148085 148083 148084 148093 +168 7 148085 148083 148084 148094 +169 2 148081 148083 148085 148086 +170 4 148081 148083 148085 148087 +171 1 148082 148081 148083 148084 +172 3 148091 148081 148083 148084 +173 4 148091 148081 148083 148085 +174 5 148082 148081 148091 148092 +175 4 148083 148081 148091 148089 +176 2 148083 148081 148091 148092 +177 2 148089 148091 148081 148082 +178 2 148081 148091 148089 148090 +179 2 111365 111363 111361 111362 +180 6 111361 111363 111364 111373 +181 7 111361 111363 111364 111374 +182 6 111365 111363 111364 111373 +183 7 111365 111363 111364 111374 +184 2 111361 111363 111365 111366 +185 4 111361 111363 111365 111367 +186 2 111371 111369 111367 111368 +187 4 111367 111369 111371 111361 +188 2 111367 111369 111371 111372 +189 5 111370 111369 111371 111372 +190 2 111369 111371 111361 111362 +191 2 111361 111371 111369 111370 +192 1 111362 111361 111363 111364 +193 3 111371 111361 111363 111364 +194 4 111371 111361 111363 111365 +195 5 111362 111361 111371 111372 +196 4 111363 111361 111371 111369 +197 2 111363 111361 111371 111372 +198 1 43042 43041 43043 43044 +199 3 43051 43041 43043 43044 +200 4 43051 43041 43043 43045 +201 5 43042 43041 43051 43052 +202 4 43043 43041 43051 43049 +203 2 43043 43041 43051 43052 +204 2 43045 43043 43041 43042 +205 6 43041 43043 43044 43053 +206 7 43041 43043 43044 43054 +207 6 43045 43043 43044 43053 +208 7 43045 43043 43044 43054 +209 2 43041 43043 43045 43046 +210 4 43041 43043 43045 43047 +211 8 43043 43044 43054 43055 +212 8 43043 43044 43054 43056 +213 9 43053 43044 43054 43055 +214 9 43053 43044 43054 43056 +215 2 150153 150155 150145 150146 +216 2 150145 150155 150153 150154 +217 2 150155 150153 150151 150152 +218 4 150151 150153 150155 150145 +219 2 150151 150153 150155 150156 +220 5 150154 150153 150155 150156 +221 2 150153 150151 150149 150150 +222 2 150149 150151 150153 150154 +223 4 150149 150151 150153 150155 +224 5 150152 150151 150153 150154 +225 2 20153 20155 20145 20146 +226 2 20145 20155 20153 20154 +227 1 20146 20145 20147 20148 +228 3 20155 20145 20147 20148 +229 4 20155 20145 20147 20149 +230 5 20146 20145 20155 20156 +231 4 20147 20145 20155 20153 +232 2 20147 20145 20155 20156 +233 1 20150 20149 20147 20148 +234 3 20151 20149 20147 20148 +235 2 20147 20149 20151 20152 +236 4 20147 20149 20151 20153 +237 5 20150 20149 20151 20152 +238 2 20155 20153 20151 20152 +239 4 20151 20153 20155 20145 +240 2 20151 20153 20155 20156 +241 5 20154 20153 20155 20156 +242 2 20153 20151 20149 20150 +243 2 20149 20151 20153 20154 +244 4 20149 20151 20153 20155 +245 5 20152 20151 20153 20154 +246 2 20149 20147 20145 20146 +247 6 20145 20147 20148 20157 +248 7 20145 20147 20148 20158 +249 6 20149 20147 20148 20157 +250 7 20149 20147 20148 20158 +251 2 20145 20147 20149 20150 +252 4 20145 20147 20149 20151 +253 1 107926 107925 107923 107924 +254 3 107927 107925 107923 107924 +255 2 107923 107925 107927 107928 +256 4 107923 107925 107927 107929 +257 5 107926 107925 107927 107928 +258 2 107929 107927 107925 107926 +259 2 107925 107927 107929 107930 +260 4 107925 107927 107929 107931 +261 5 107928 107927 107929 107930 +262 2 107929 107931 107921 107922 +263 2 107921 107931 107929 107930 +264 2 107931 107929 107927 107928 +265 4 107927 107929 107931 107921 +266 2 107927 107929 107931 107932 +267 5 107930 107929 107931 107932 +268 2 69387 69385 69383 69384 +269 4 69383 69385 69387 69377 +270 2 69383 69385 69387 69388 +271 5 69386 69385 69387 69388 +272 2 69385 69387 69377 69378 +273 2 69377 69387 69385 69386 +274 2 69381 69379 69377 69378 +275 6 69377 69379 69380 69389 +276 7 69377 69379 69380 69390 +277 6 69381 69379 69380 69389 +278 7 69381 69379 69380 69390 +279 2 69377 69379 69381 69382 +280 4 69377 69379 69381 69383 +281 1 69378 69377 69379 69380 +282 3 69387 69377 69379 69380 +283 4 69387 69377 69379 69381 +284 5 69378 69377 69387 69388 +285 4 69379 69377 69387 69385 +286 2 69379 69377 69387 69388 +287 2 69385 69383 69381 69382 +288 2 69381 69383 69385 69386 +289 4 69381 69383 69385 69387 +290 5 69384 69383 69385 69386 +291 1 69382 69381 69379 69380 +292 3 69383 69381 69379 69380 +293 2 69379 69381 69383 69384 +294 4 69379 69381 69383 69385 +295 5 69382 69381 69383 69384 +296 8 65539 65540 65550 65551 +297 8 65539 65540 65550 65552 +298 9 65549 65540 65550 65551 +299 9 65549 65540 65550 65552 +300 8 69379 69380 69390 69391 +301 8 69379 69380 69390 69392 +302 9 69389 69380 69390 69391 +303 9 69389 69380 69390 69392 +304 2 65541 65539 65537 65538 +305 6 65537 65539 65540 65549 +306 7 65537 65539 65540 65550 +307 6 65541 65539 65540 65549 +308 7 65541 65539 65540 65550 +309 2 65537 65539 65541 65542 +310 4 65537 65539 65541 65543 +311 2 65545 65543 65541 65542 +312 2 65541 65543 65545 65546 +313 4 65541 65543 65545 65547 +314 5 65544 65543 65545 65546 +315 1 65542 65541 65539 65540 +316 3 65543 65541 65539 65540 +317 2 65539 65541 65543 65544 +318 4 65539 65541 65543 65545 +319 5 65542 65541 65543 65544 +320 2 65547 65545 65543 65544 +321 4 65543 65545 65547 65537 +322 2 65543 65545 65547 65548 +323 5 65546 65545 65547 65548 +324 2 65545 65547 65537 65538 +325 2 65537 65547 65545 65546 +326 1 65538 65537 65539 65540 +327 3 65547 65537 65539 65540 +328 4 65547 65537 65539 65541 +329 5 65538 65537 65547 65548 +330 4 65539 65537 65547 65545 +331 2 65539 65537 65547 65548 +332 2 41321 41319 41317 41318 +333 2 41317 41319 41321 41322 +334 4 41317 41319 41321 41323 +335 5 41320 41319 41321 41322 +336 1 41318 41317 41315 41316 +337 3 41319 41317 41315 41316 +338 2 41315 41317 41319 41320 +339 4 41315 41317 41319 41321 +340 5 41318 41317 41319 41320 +341 2 41317 41315 41313 41314 +342 6 41313 41315 41316 41325 +343 7 41313 41315 41316 41326 +344 6 41317 41315 41316 41325 +345 7 41317 41315 41316 41326 +346 2 41313 41315 41317 41318 +347 4 41313 41315 41317 41319 +348 8 195795 195796 195806 195807 +349 8 195795 195796 195806 195808 +350 9 195805 195796 195806 195807 +351 9 195805 195796 195806 195808 +352 2 195797 195795 195793 195794 +353 6 195793 195795 195796 195805 +354 7 195793 195795 195796 195806 +355 6 195797 195795 195796 195805 +356 7 195797 195795 195796 195806 +357 2 195793 195795 195797 195798 +358 4 195793 195795 195797 195799 +359 2 41323 41321 41319 41320 +360 4 41319 41321 41323 41313 +361 2 41319 41321 41323 41324 +362 5 41322 41321 41323 41324 +363 2 41321 41323 41313 41314 +364 2 41313 41323 41321 41322 +365 1 150146 150145 150147 150148 +366 3 150155 150145 150147 150148 +367 4 150155 150145 150147 150149 +368 5 150146 150145 150155 150156 +369 4 150147 150145 150155 150153 +370 2 150147 150145 150155 150156 +371 8 150147 150148 150158 150159 +372 8 150147 150148 150158 150160 +373 9 150157 150148 150158 150159 +374 9 150157 150148 150158 150160 +375 2 150149 150147 150145 150146 +376 6 150145 150147 150148 150157 +377 7 150145 150147 150148 150158 +378 6 150149 150147 150148 150157 +379 7 150149 150147 150148 150158 +380 2 150145 150147 150149 150150 +381 4 150145 150147 150149 150151 +382 1 150150 150149 150147 150148 +383 3 150151 150149 150147 150148 +384 2 150147 150149 150151 150152 +385 4 150147 150149 150151 150153 +386 5 150150 150149 150151 150152 +387 1 195794 195793 195795 195796 +388 3 195803 195793 195795 195796 +389 4 195803 195793 195795 195797 +390 5 195794 195793 195803 195804 +391 4 195795 195793 195803 195801 +392 2 195795 195793 195803 195804 +393 2 195801 195803 195793 195794 +394 2 195793 195803 195801 195802 +395 2 195803 195801 195799 195800 +396 4 195799 195801 195803 195793 +397 2 195799 195801 195803 195804 +398 5 195802 195801 195803 195804 +399 1 195798 195797 195795 195796 +400 3 195799 195797 195795 195796 +401 2 195795 195797 195799 195800 +402 4 195795 195797 195799 195801 +403 5 195798 195797 195799 195800 +404 2 195801 195799 195797 195798 +405 2 195797 195799 195801 195802 +406 4 195797 195799 195801 195803 +407 5 195800 195799 195801 195802 +408 2 107227 107225 107223 107224 +409 4 107223 107225 107227 107217 +410 2 107223 107225 107227 107228 +411 5 107226 107225 107227 107228 +412 2 43051 43049 43047 43048 +413 4 43047 43049 43051 43041 +414 2 43047 43049 43051 43052 +415 5 43050 43049 43051 43052 +416 2 43049 43051 43041 43042 +417 2 43041 43051 43049 43050 +418 8 188723 188724 188734 188735 +419 8 188723 188724 188734 188736 +420 9 188733 188724 188734 188735 +421 9 188733 188724 188734 188736 +422 2 43049 43047 43045 43046 +423 2 43045 43047 43049 43050 +424 4 43045 43047 43049 43051 +425 5 43048 43047 43049 43050 +426 1 43046 43045 43043 43044 +427 3 43047 43045 43043 43044 +428 2 43043 43045 43047 43048 +429 4 43043 43045 43047 43049 +430 5 43046 43045 43047 43048 +431 1 188722 188721 188723 188724 +432 3 188731 188721 188723 188724 +433 4 188731 188721 188723 188725 +434 5 188722 188721 188731 188732 +435 4 188723 188721 188731 188729 +436 2 188723 188721 188731 188732 +437 2 188729 188731 188721 188722 +438 2 188721 188731 188729 188730 +439 8 3043 3044 3054 3055 +440 8 3043 3044 3054 3056 +441 9 3053 3044 3054 3055 +442 9 3053 3044 3054 3056 +443 2 3049 3047 3045 3046 +444 2 3045 3047 3049 3050 +445 4 3045 3047 3049 3051 +446 5 3048 3047 3049 3050 +447 2 3045 3043 3041 3042 +448 6 3041 3043 3044 3053 +449 7 3041 3043 3044 3054 +450 6 3045 3043 3044 3053 +451 7 3045 3043 3044 3054 +452 2 3041 3043 3045 3046 +453 4 3041 3043 3045 3047 +454 1 3046 3045 3043 3044 +455 3 3047 3045 3043 3044 +456 2 3043 3045 3047 3048 +457 4 3043 3045 3047 3049 +458 5 3046 3045 3047 3048 +459 1 101766 101765 101763 101764 +460 3 101767 101765 101763 101764 +461 2 101763 101765 101767 101768 +462 4 101763 101765 101767 101769 +463 5 101766 101765 101767 101768 +464 2 101771 101769 101767 101768 +465 4 101767 101769 101771 101761 +466 2 101767 101769 101771 101772 +467 5 101770 101769 101771 101772 +468 2 101769 101767 101765 101766 +469 2 101765 101767 101769 101770 +470 4 101765 101767 101769 101771 +471 5 101768 101767 101769 101770 +472 2 107225 107227 107217 107218 +473 2 107217 107227 107225 107226 +474 2 108389 108387 108385 108386 +475 6 108385 108387 108388 108397 +476 7 108385 108387 108388 108398 +477 6 108389 108387 108388 108397 +478 7 108389 108387 108388 108398 +479 2 108385 108387 108389 108390 +480 4 108385 108387 108389 108391 +481 1 107218 107217 107219 107220 +482 3 107227 107217 107219 107220 +483 4 107227 107217 107219 107221 +484 5 107218 107217 107227 107228 +485 4 107219 107217 107227 107225 +486 2 107219 107217 107227 107228 +487 8 107923 107924 107934 107935 +488 8 107923 107924 107934 107936 +489 9 107933 107924 107934 107935 +490 9 107933 107924 107934 107936 +491 2 107925 107923 107921 107922 +492 6 107921 107923 107924 107933 +493 7 107921 107923 107924 107934 +494 6 107925 107923 107924 107933 +495 7 107925 107923 107924 107934 +496 2 107921 107923 107925 107926 +497 4 107921 107923 107925 107927 +498 1 107922 107921 107923 107924 +499 3 107931 107921 107923 107924 +500 4 107931 107921 107923 107925 +501 5 107922 107921 107931 107932 +502 4 107923 107921 107931 107929 +503 2 107923 107921 107931 107932 +504 8 108387 108388 108398 108399 +505 8 108387 108388 108398 108400 +506 9 108397 108388 108398 108399 +507 9 108397 108388 108398 108400 +508 8 101763 101764 101774 101775 +509 8 101763 101764 101774 101776 +510 9 101773 101764 101774 101775 +511 9 101773 101764 101774 101776 +512 2 101765 101763 101761 101762 +513 6 101761 101763 101764 101773 +514 7 101761 101763 101764 101774 +515 6 101765 101763 101764 101773 +516 7 101765 101763 101764 101774 +517 2 101761 101763 101765 101766 +518 4 101761 101763 101765 101767 +519 2 179273 179271 179269 179270 +520 2 179269 179271 179273 179274 +521 4 179269 179271 179273 179275 +522 5 179272 179271 179273 179274 +523 1 101762 101761 101763 101764 +524 3 101771 101761 101763 101764 +525 4 101771 101761 101763 101765 +526 5 101762 101761 101771 101772 +527 4 101763 101761 101771 101769 +528 2 101763 101761 101771 101772 +529 2 101769 101771 101761 101762 +530 2 101761 101771 101769 101770 +531 2 41337 41339 41329 41330 +532 2 41329 41339 41337 41338 +533 1 41330 41329 41331 41332 +534 3 41339 41329 41331 41332 +535 4 41339 41329 41331 41333 +536 5 41330 41329 41339 41340 +537 4 41331 41329 41339 41337 +538 2 41331 41329 41339 41340 +539 2 41333 41331 41329 41330 +540 6 41329 41331 41332 41341 +541 7 41329 41331 41332 41342 +542 6 41333 41331 41332 41341 +543 7 41333 41331 41332 41342 +544 2 41329 41331 41333 41334 +545 4 41329 41331 41333 41335 +546 8 41331 41332 41342 41343 +547 8 41331 41332 41342 41344 +548 9 41341 41332 41342 41343 +549 9 41341 41332 41342 41344 +550 1 108386 108385 108387 108388 +551 3 108395 108385 108387 108388 +552 4 108395 108385 108387 108389 +553 5 108386 108385 108395 108396 +554 4 108387 108385 108395 108393 +555 2 108387 108385 108395 108396 +556 8 160467 160468 160478 160479 +557 8 160467 160468 160478 160480 +558 9 160477 160468 160478 160479 +559 9 160477 160468 160478 160480 +560 2 160473 160471 160469 160470 +561 2 160469 160471 160473 160474 +562 4 160469 160471 160473 160475 +563 5 160472 160471 160473 160474 +564 1 160470 160469 160467 160468 +565 3 160471 160469 160467 160468 +566 2 160467 160469 160471 160472 +567 4 160467 160469 160471 160473 +568 5 160470 160469 160471 160472 +569 2 160475 160473 160471 160472 +570 4 160471 160473 160475 160465 +571 2 160471 160473 160475 160476 +572 5 160474 160473 160475 160476 +573 2 160473 160475 160465 160466 +574 2 160465 160475 160473 160474 +575 1 160466 160465 160467 160468 +576 3 160475 160465 160467 160468 +577 4 160475 160465 160467 160469 +578 5 160466 160465 160475 160476 +579 4 160467 160465 160475 160473 +580 2 160467 160465 160475 160476 +581 2 160469 160467 160465 160466 +582 6 160465 160467 160468 160477 +583 7 160465 160467 160468 160478 +584 6 160469 160467 160468 160477 +585 7 160469 160467 160468 160478 +586 2 160465 160467 160469 160470 +587 4 160465 160467 160469 160471 +588 8 179267 179268 179278 179279 +589 8 179267 179268 179278 179280 +590 9 179277 179268 179278 179279 +591 9 179277 179268 179278 179280 +592 2 179269 179267 179265 179266 +593 6 179265 179267 179268 179277 +594 7 179265 179267 179268 179278 +595 6 179269 179267 179268 179277 +596 7 179269 179267 179268 179278 +597 2 179265 179267 179269 179270 +598 4 179265 179267 179269 179271 +599 2 179273 179275 179265 179266 +600 2 179265 179275 179273 179274 +601 1 179266 179265 179267 179268 +602 3 179275 179265 179267 179268 +603 4 179275 179265 179267 179269 +604 5 179266 179265 179275 179276 +605 4 179267 179265 179275 179273 +606 2 179267 179265 179275 179276 +607 1 179270 179269 179267 179268 +608 3 179271 179269 179267 179268 +609 2 179267 179269 179271 179272 +610 4 179267 179269 179271 179273 +611 5 179270 179269 179271 179272 +612 2 179275 179273 179271 179272 +613 4 179271 179273 179275 179265 +614 2 179271 179273 179275 179276 +615 5 179274 179273 179275 179276 +616 1 3042 3041 3043 3044 +617 3 3051 3041 3043 3044 +618 4 3051 3041 3043 3045 +619 5 3042 3041 3051 3052 +620 4 3043 3041 3051 3049 +621 2 3043 3041 3051 3052 +622 2 3051 3049 3047 3048 +623 4 3047 3049 3051 3041 +624 2 3047 3049 3051 3052 +625 5 3050 3049 3051 3052 +626 2 3049 3051 3041 3042 +627 2 3041 3051 3049 3050 +628 2 41339 41337 41335 41336 +629 4 41335 41337 41339 41329 +630 2 41335 41337 41339 41340 +631 5 41338 41337 41339 41340 +632 2 41337 41335 41333 41334 +633 2 41333 41335 41337 41338 +634 4 41333 41335 41337 41339 +635 5 41336 41335 41337 41338 +636 1 41334 41333 41331 41332 +637 3 41335 41333 41331 41332 +638 2 41331 41333 41335 41336 +639 4 41331 41333 41335 41337 +640 5 41334 41333 41335 41336 + +Impropers + +1 1 111363 111365 111367 111366 +2 3 111363 111364 111373 111374 +3 1 107221 107223 107225 107224 +4 1 40597 40599 40601 40600 +5 1 40595 40597 40599 40598 +6 1 111365 111367 111369 111368 +7 2 188721 188723 188725 188724 +8 1 188723 188725 188727 188726 +9 1 188727 188729 188731 188730 +10 1 188725 188727 188729 188728 +11 4 20159 20158 20160 20148 +12 3 20147 20148 20157 20158 +13 1 41345 41355 41353 41356 +14 1 108387 108389 108391 108390 +15 4 41327 41326 41328 41316 +16 1 108389 108391 108393 108392 +17 1 41351 41353 41355 41354 +18 1 41349 41351 41353 41352 +19 1 107219 107221 107223 107222 +20 2 107217 107219 107221 107220 +21 1 41347 41345 41355 41346 +22 2 41345 41347 41349 41348 +23 4 41359 41358 41360 41348 +24 3 41347 41348 41357 41358 +25 1 41347 41349 41351 41350 +26 3 107219 107220 107229 107230 +27 4 107231 107230 107232 107220 +28 1 148085 148087 148089 148088 +29 1 148087 148089 148091 148090 +30 1 40593 40603 40601 40604 +31 1 40599 40601 40603 40602 +32 1 40595 40593 40603 40594 +33 2 40593 40595 40597 40596 +34 3 41315 41316 41325 41326 +35 1 108391 108393 108395 108394 +36 1 41315 41313 41323 41314 +37 1 108385 108395 108393 108396 +38 4 148095 148094 148096 148084 +39 4 40607 40606 40608 40596 +40 3 40595 40596 40605 40606 +41 3 148083 148084 148093 148094 +42 1 148083 148085 148087 148086 +43 2 148081 148083 148085 148084 +44 1 148083 148081 148091 148082 +45 1 148081 148091 148089 148092 +46 2 111361 111363 111365 111364 +47 1 111367 111369 111371 111370 +48 1 111361 111371 111369 111372 +49 1 111363 111361 111371 111362 +50 4 195807 195806 195808 195796 +51 1 43043 43041 43051 43042 +52 2 43041 43043 43045 43044 +53 3 43043 43044 43053 43054 +54 4 43055 43054 43056 43044 +55 1 150145 150155 150153 150156 +56 4 111375 111374 111376 111364 +57 1 150151 150153 150155 150154 +58 1 150149 150151 150153 150152 +59 1 20145 20155 20153 20156 +60 1 20147 20145 20155 20146 +61 1 20147 20149 20151 20150 +62 1 20151 20153 20155 20154 +63 1 20149 20151 20153 20152 +64 2 20145 20147 20149 20148 +65 1 107923 107925 107927 107926 +66 1 107925 107927 107929 107928 +67 1 107921 107931 107929 107932 +68 1 107927 107929 107931 107930 +69 1 69383 69385 69387 69386 +70 1 69377 69387 69385 69388 +71 2 69377 69379 69381 69380 +72 1 69379 69377 69387 69378 +73 1 69381 69383 69385 69384 +74 1 69379 69381 69383 69382 +75 4 65551 65550 65552 65540 +76 3 65539 65540 65549 65550 +77 3 69379 69380 69389 69390 +78 2 65537 65539 65541 65540 +79 1 65541 65543 65545 65544 +80 1 65539 65541 65543 65542 +81 1 65543 65545 65547 65546 +82 1 65537 65547 65545 65548 +83 1 65539 65537 65547 65538 +84 1 41317 41319 41321 41320 +85 1 41315 41317 41319 41318 +86 2 41313 41315 41317 41316 +87 3 195795 195796 195805 195806 +88 2 195793 195795 195797 195796 +89 1 41319 41321 41323 41322 +90 1 41313 41323 41321 41324 +91 4 69391 69390 69392 69380 +92 1 150147 150145 150155 150146 +93 3 150147 150148 150157 150158 +94 2 150145 150147 150149 150148 +95 4 150159 150158 150160 150148 +96 1 150147 150149 150151 150150 +97 1 195795 195793 195803 195794 +98 1 195793 195803 195801 195804 +99 1 195799 195801 195803 195802 +100 1 195795 195797 195799 195798 +101 1 195797 195799 195801 195800 +102 1 107223 107225 107227 107226 +103 1 43047 43049 43051 43050 +104 1 43041 43051 43049 43052 +105 3 188723 188724 188733 188734 +106 4 188735 188734 188736 188724 +107 1 43045 43047 43049 43048 +108 1 43043 43045 43047 43046 +109 1 188723 188721 188731 188722 +110 1 188721 188731 188729 188732 +111 4 3055 3054 3056 3044 +112 3 3043 3044 3053 3054 +113 1 3045 3047 3049 3048 +114 2 3041 3043 3045 3044 +115 1 3043 3045 3047 3046 +116 1 101763 101765 101767 101766 +117 1 101767 101769 101771 101770 +118 1 101765 101767 101769 101768 +119 1 107217 107227 107225 107228 +120 2 108385 108387 108389 108388 +121 1 107219 107217 107227 107218 +122 4 107935 107934 107936 107924 +123 3 107923 107924 107933 107934 +124 2 107921 107923 107925 107924 +125 1 107923 107921 107931 107922 +126 3 108387 108388 108397 108398 +127 4 108399 108398 108400 108388 +128 4 101775 101774 101776 101764 +129 3 101763 101764 101773 101774 +130 2 101761 101763 101765 101764 +131 1 179269 179271 179273 179272 +132 1 101763 101761 101771 101762 +133 1 101761 101771 101769 101772 +134 1 41329 41339 41337 41340 +135 1 41331 41329 41339 41330 +136 4 41343 41342 41344 41332 +137 2 41329 41331 41333 41332 +138 3 41331 41332 41341 41342 +139 1 108387 108385 108395 108386 +140 4 160479 160478 160480 160468 +141 3 160467 160468 160477 160478 +142 1 160469 160471 160473 160472 +143 1 160467 160469 160471 160470 +144 1 160471 160473 160475 160474 +145 1 160465 160475 160473 160476 +146 1 160467 160465 160475 160466 +147 2 160465 160467 160469 160468 +148 4 179279 179278 179280 179268 +149 3 179267 179268 179277 179278 +150 2 179265 179267 179269 179268 +151 1 179265 179275 179273 179276 +152 1 179267 179265 179275 179266 +153 1 179267 179269 179271 179270 +154 1 179271 179273 179275 179274 +155 1 3043 3041 3051 3042 +156 1 3047 3049 3051 3050 +157 1 3041 3051 3049 3052 +158 1 41335 41337 41339 41338 +159 1 41333 41335 41337 41336 +160 1 41331 41333 41335 41334 -- GitLab From 1dc8d4acaa2142db1aa93f44395c511c43e72d0b Mon Sep 17 00:00:00 2001 From: jrgissing Date: Wed, 1 Jan 2020 12:58:10 -0500 Subject: [PATCH 003/689] bond/react: repackage examples --- .../nylon,6-6_melt/large_nylon_melt.data.gz | Bin 3745227 -> 0 bytes .../nylon,6-6_melt/in.large_nylon_melt | 0 .../log.20Apr18.large_nylon_melt.g++.1 | 0 .../log.20Apr18.large_nylon_melt.g++.4 | 0 .../nylon,6-6_melt/rxn1_stp1_map | 0 .../rxn1_stp1_reacted.data_template | 0 .../rxn1_stp1_unreacted.data_template | 0 .../nylon,6-6_melt/rxn1_stp2_map | 0 .../rxn1_stp2_reacted.data_template | 0 .../rxn1_stp2_unreacted.data_template | 0 .../tiny_epoxy/in.tiny_epoxy.stabilized | 0 .../log.20Nov19.tiny_epoxy.stabilized.g++.1 | 0 .../log.20Nov19.tiny_epoxy.stabilized.g++.4 | 0 .../tiny_epoxy/rxn1_stp1.map | 0 .../tiny_epoxy/rxn1_stp1_post.data_template | 0 .../tiny_epoxy/rxn1_stp1_pre.data_template | 0 .../tiny_epoxy/rxn1_stp2.map | 0 .../tiny_epoxy/rxn1_stp2_post.data_template | 0 .../tiny_epoxy/rxn2_stp1.map | 0 .../tiny_epoxy/rxn2_stp1_post.data_template | 0 .../tiny_epoxy/rxn2_stp1_pre.data_template | 0 .../tiny_epoxy/rxn2_stp2.map | 0 .../tiny_epoxy/rxn2_stp2_post.data_template | 0 .../tiny_epoxy/tiny_epoxy.data | 0 .../tiny_nylon/in.tiny_nylon.stabilized | 0 .../tiny_nylon/in.tiny_nylon.unstabilized | 0 .../log.5Jun19.tiny_nylon.stabilized.g++.1 | 0 .../log.5Jun19.tiny_nylon.stabilized.g++.4 | 0 .../log.5Jun19.tiny_nylon.unstabilized.g++.1 | 0 .../log.5Jun19.tiny_nylon.unstabilized.g++.4 | 0 .../tiny_nylon/rxn1_stp1_map | 0 .../rxn1_stp1_reacted.data_template | 0 .../rxn1_stp1_unreacted.data_template | 0 .../tiny_nylon/rxn1_stp2_map | 0 .../rxn1_stp2_reacted.data_template | 0 .../rxn1_stp2_unreacted.data_template | 0 .../tiny_nylon/tiny_nylon.data | 0 .../tiny_polystyrene/2styrene_map | 0 .../2styrene_reacted.data_template | 0 .../2styrene_unreacted.data_template | 0 .../tiny_polystyrene/chain_chain_map | 0 .../chain_chain_reacted.data_template | 0 .../chain_chain_unreacted.data_template | 0 .../tiny_polystyrene/chain_plus_styrene_map | 0 .../chain_plus_styrene_reacted.data_template | 0 ...chain_plus_styrene_unreacted.data_template | 0 .../in.tiny_polystyrene.stabilized | 0 ....20Nov19.tiny_polystyrene.stabilized.g++.1 | 0 ....20Nov19.tiny_polystyrene.stabilized.g++.4 | 0 .../tiny_polystyrene/tiny_polystyrene.data | 0 50 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 examples/USER/misc/bond_react/nylon,6-6_melt/large_nylon_melt.data.gz rename examples/USER/{misc/bond_react => react}/nylon,6-6_melt/in.large_nylon_melt (100%) rename examples/USER/{misc/bond_react => react}/nylon,6-6_melt/log.20Apr18.large_nylon_melt.g++.1 (100%) rename examples/USER/{misc/bond_react => react}/nylon,6-6_melt/log.20Apr18.large_nylon_melt.g++.4 (100%) rename examples/USER/{misc/bond_react => react}/nylon,6-6_melt/rxn1_stp1_map (100%) rename examples/USER/{misc/bond_react => react}/nylon,6-6_melt/rxn1_stp1_reacted.data_template (100%) rename examples/USER/{misc/bond_react => react}/nylon,6-6_melt/rxn1_stp1_unreacted.data_template (100%) rename examples/USER/{misc/bond_react => react}/nylon,6-6_melt/rxn1_stp2_map (100%) rename examples/USER/{misc/bond_react => react}/nylon,6-6_melt/rxn1_stp2_reacted.data_template (100%) rename examples/USER/{misc/bond_react => react}/nylon,6-6_melt/rxn1_stp2_unreacted.data_template (100%) rename examples/USER/{misc/bond_react => react}/tiny_epoxy/in.tiny_epoxy.stabilized (100%) rename examples/USER/{misc/bond_react => react}/tiny_epoxy/log.20Nov19.tiny_epoxy.stabilized.g++.1 (100%) rename examples/USER/{misc/bond_react => react}/tiny_epoxy/log.20Nov19.tiny_epoxy.stabilized.g++.4 (100%) rename examples/USER/{misc/bond_react => react}/tiny_epoxy/rxn1_stp1.map (100%) rename examples/USER/{misc/bond_react => react}/tiny_epoxy/rxn1_stp1_post.data_template (100%) rename examples/USER/{misc/bond_react => react}/tiny_epoxy/rxn1_stp1_pre.data_template (100%) rename examples/USER/{misc/bond_react => react}/tiny_epoxy/rxn1_stp2.map (100%) rename examples/USER/{misc/bond_react => react}/tiny_epoxy/rxn1_stp2_post.data_template (100%) rename examples/USER/{misc/bond_react => react}/tiny_epoxy/rxn2_stp1.map (100%) rename examples/USER/{misc/bond_react => react}/tiny_epoxy/rxn2_stp1_post.data_template (100%) rename examples/USER/{misc/bond_react => react}/tiny_epoxy/rxn2_stp1_pre.data_template (100%) rename examples/USER/{misc/bond_react => react}/tiny_epoxy/rxn2_stp2.map (100%) rename examples/USER/{misc/bond_react => react}/tiny_epoxy/rxn2_stp2_post.data_template (100%) rename examples/USER/{misc/bond_react => react}/tiny_epoxy/tiny_epoxy.data (100%) rename examples/USER/{misc/bond_react => react}/tiny_nylon/in.tiny_nylon.stabilized (100%) rename examples/USER/{misc/bond_react => react}/tiny_nylon/in.tiny_nylon.unstabilized (100%) rename examples/USER/{misc/bond_react => react}/tiny_nylon/log.5Jun19.tiny_nylon.stabilized.g++.1 (100%) rename examples/USER/{misc/bond_react => react}/tiny_nylon/log.5Jun19.tiny_nylon.stabilized.g++.4 (100%) rename examples/USER/{misc/bond_react => react}/tiny_nylon/log.5Jun19.tiny_nylon.unstabilized.g++.1 (100%) rename examples/USER/{misc/bond_react => react}/tiny_nylon/log.5Jun19.tiny_nylon.unstabilized.g++.4 (100%) rename examples/USER/{misc/bond_react => react}/tiny_nylon/rxn1_stp1_map (100%) rename examples/USER/{misc/bond_react => react}/tiny_nylon/rxn1_stp1_reacted.data_template (100%) rename examples/USER/{misc/bond_react => react}/tiny_nylon/rxn1_stp1_unreacted.data_template (100%) rename examples/USER/{misc/bond_react => react}/tiny_nylon/rxn1_stp2_map (100%) rename examples/USER/{misc/bond_react => react}/tiny_nylon/rxn1_stp2_reacted.data_template (100%) rename examples/USER/{misc/bond_react => react}/tiny_nylon/rxn1_stp2_unreacted.data_template (100%) rename examples/USER/{misc/bond_react => react}/tiny_nylon/tiny_nylon.data (100%) rename examples/USER/{misc/bond_react => react}/tiny_polystyrene/2styrene_map (100%) rename examples/USER/{misc/bond_react => react}/tiny_polystyrene/2styrene_reacted.data_template (100%) rename examples/USER/{misc/bond_react => react}/tiny_polystyrene/2styrene_unreacted.data_template (100%) rename examples/USER/{misc/bond_react => react}/tiny_polystyrene/chain_chain_map (100%) rename examples/USER/{misc/bond_react => react}/tiny_polystyrene/chain_chain_reacted.data_template (100%) rename examples/USER/{misc/bond_react => react}/tiny_polystyrene/chain_chain_unreacted.data_template (100%) rename examples/USER/{misc/bond_react => react}/tiny_polystyrene/chain_plus_styrene_map (100%) rename examples/USER/{misc/bond_react => react}/tiny_polystyrene/chain_plus_styrene_reacted.data_template (100%) rename examples/USER/{misc/bond_react => react}/tiny_polystyrene/chain_plus_styrene_unreacted.data_template (100%) rename examples/USER/{misc/bond_react => react}/tiny_polystyrene/in.tiny_polystyrene.stabilized (100%) rename examples/USER/{misc/bond_react => react}/tiny_polystyrene/log.20Nov19.tiny_polystyrene.stabilized.g++.1 (100%) rename examples/USER/{misc/bond_react => react}/tiny_polystyrene/log.20Nov19.tiny_polystyrene.stabilized.g++.4 (100%) rename examples/USER/{misc/bond_react => react}/tiny_polystyrene/tiny_polystyrene.data (100%) diff --git a/examples/USER/misc/bond_react/nylon,6-6_melt/large_nylon_melt.data.gz b/examples/USER/misc/bond_react/nylon,6-6_melt/large_nylon_melt.data.gz deleted file mode 100644 index c620b879a883817b8eb7abe4495e585ecacfaf02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3745227 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 %XlO{Un{C;OKaoazpbeGx|H3_4c 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 jV4v9vkYu+6~9n3uuu4%Q+MxS#mXz& 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%0A;*YQVmA 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

  • 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%0An6 zqU7o5l+}~h8Z_?8bIYIpIs4m64i)X2=CwJoeykVG1wtLJcS)zN3Hb3ZJ;QJ19j={g zuRo1QEBGAB#C7}r{aEV`Z-w&$@v-&t{rf*lFrGK!lJVvkzwgQ$@85kHI&+fCj()PVtN0=k0WKS zi`bp~`u$peH>}_=a{D$#caGuJt&@|BbSsS49+@l7`#)>0@%PTaV;jGGpQRb`RWWs9 zDN~?w*~DMJ-%VK{SiF?!$^U(EqD!`W_<3&SsLyve{zNTs$(t{i1ekP}E{Th1b1P|| zu`9*?)06ql21cI0Ux!*c#UH%cb}D9T0#1TJNo8* zzhhlX(vK!OI6qrw7icCC%eP5GZgY)5pTyNeejXj#Hv*r2zFsH3`NXO)Q4Z!emUlNk zl3Tdca-u@sJ>IYIEnjPj&7R2DdfUmS7U$0ZFzn-JN7O< zS@h=Q-=k-G{P+KUA!GhQQ7Gk!I$yM-wmjR#?TeSa@X|h_ab-T|+<(nmj^+HA!(->N za#8uB47T^V${V+bO4P=D3y_XF^Q5qe<3QclD_U~|Kf2_VF)m$mLMLyL(#4h!6IY(n zTwgYS9)ncL>TPdz=je00*!w8$uK80v&=4L*H-qJ$GbHnfQ0(Jy(oB zFR5cqT6(Yc@Qs&?^uB#;ct2Zt@qGh<_yy_?hHJUr>IWaPbdzXpIQJ$+de;`&qiXs; z9Wr*O`geQ_lnPU6Sh=VAtf}nJibgJOae0TYsyxo@3Fom{=GS7R+_wD_)pWBM#bh3>DT>B&ogpu z)jYB0_Zu!prFo9l{?DyvG$}5adh7q$^U5g`pWU*HIA&oxC3+IuakDv3k}L8UeI6R9 zY-F1A=TO-8DyE{#!e^$GaM?$6gzU3RV+fUF=}(y;KeJkGaRRICZ=J2*&*zD3zEZR> zY*v8L>XirCr+KVivOMh5qT_=1XRcWE)8qM`&-e+^>UKQ7wBd?sBxLa;NI~Z24@pIFH878Jhe|eR2 zHqHtTU9VeFYV+{B?z~e9IWG?AN-y5@M%nhj#~*UmJ+ExMK5FqBDg4^B$oRDOw#7Ai zr?_TMU^hS5+M!*z?Gy9G4&4&>*GYkoERx=DEj@D1RQDXa%ap7*#s2v{KfKPo6tL0D z|84BJ{|YnL?c%f6$>M5u0o#i9P1Ii;Q}9_nX(hwDWsWPHU+S4BuJXUlWTln*zcjyw zm(lZRNc+NlJ_Xy9mj9@H;V-a5spzCc-p|xoRuP$V3_G^%F|O2GwT&U};l|3(D!)4? z%sTS7bHe)K^6JTZ4K{VDPU$_HIwwYEZd&uUJHL`sQs@5;{O@8T$Cx1@H0O8sv@|E@ zhiSQYUt~u!oMf68nzeAoGv&$Zb5egh?lpE2KNhppR&)7`zf;omCw%#JlOw`aG-#sK zm*qV=a@OB0!WQn>^kxxv(N(*gU3$T$wtV4bif2|$c#^U1{?ZjMruNUh-&izJGG|im z)$A6o;u+x!BiBk^Gi;c~zRrzz=dZ&P9i;6y|C_$Pr=`*Gj@Mg<=1k_!_8C2*tES|- z@yU6A@M1Xi$i4Q(R7rt3td$#_7~0#`&0M_w4d>iN5qerPYaI>i0r!B+f_B)D)HhAvc zKQVUVMCZk4H(pv`%u&a<^=4s=-jC>sZ{MC}e<Z%!^K1b;bAm zRF9Z_!~KN+{0}8gl`?fZj@3Jkt<>RMAJg~x#0GZ8k84c+CCw`jW{*4l z`NM5Ksc+1J5i*CRTyMnBEt#eErHo_U$<6bHypOwTRUI(9l3>HMg#Gh-#;5#>Tk_A_ zW+)#&@I^U~?UnbN#D+&V&sW#5JY@P{XC)ZmTgtP}qU3hg)RtvG%a7N$b^qP|r}^WO zU+TUKr{3AB6S>rIXyTcLV%MJDV0>s~oGZC`zutF#8UNqOrGIiy92Se*?-|Xo zFLL>bKfj;8xTkSTupqAb+R3u5#^wSLUoRQe3;5weMI@E_ZJ8*xOqBuYx9aPA4(USvbeMM^)7z->XPWvLM>fM@xSk*y!e(l zg-v_&c~4?_8QXKFj~AvG6%>7X78J}=`LIUxasS=4{Zfb2cZ;y+#)^N#B`C4?&Xd^lS7TI|qdZ8hH;Gs16H zsXa@oN9r7xt()FX3eR?Z{Oejr!CaM!WSeNs z>2__~X1{%2dPM8G4fCQ&H)QWG-d~q`q5aa6=YMrfn6J!e3YGn}WB!sLOEpbLwXLGu zd-YzLUKOtX&rl%e%=YW2@q=PZ#Td4%6FLhXFV@Vw{Xf$n=d{6cKevT9LgyA7P!v?) zeVVeTDI#S07R}B%Q`cMUeWxm3>2v(SGA_RGi%tvAot5#Jb@bp&renJrjwE;Jnnw0!qDwWAcY=Zui=WnOH=2#mh z#I$Vs{@1+=_KGqX&DnaqyUF6!{%ib+8w0E#B>C@ZjnkgI_0kE2?X5;{H>o&V>jeG$ z)_%Y5Px!j8E9GWrWSHn|nSaXsos+qWz{jO#FQfK&G;L&dI8qp!R2#Rt{+{@+@Mxn6 zk`Jw-Zq`cPtXUYi_?7bimK0X!@MnkjDTr;fS#QdBeUit*h5WfU`eafrUr@U7lHtqi zZRRK2+4QDvbYA)W_n~u#w(i^2qVioZvrjmCX7l>o)=3kK8D<{ZfA^T#{B^0`v*udP zzdmbux$*_!fRx~GBBxsF(hDScQy(t+cdCB(l(%b^cs`QbXMeck@4|Zf!$*>OIC^bX z*QPyQaC(#FjEwW9LK|i^1m_W6QaP%YUroT9njkX7i-*6JKYjTv+8DL( z#aH+7N=}Vvc>DBEi=WpAmtaq~qPU|QGc>v09u7A6{rT^UUD$CTj#P?&yA9{kCIye$O8{ss9S~VXqFg+)69w3UzA;w3p`7TW=F|;P~6Z z_~g2E!Cjw~Uhr(>S;f0Od~s^ym6dyJ^nY3IyJ>Z{W3uFr&rv(&_#_yOlf(meT-{oB z!}Gv8$4||<_qOfdad=AEJC&6)G%I@EU)Wy6QL8LgRn}2+spt2Wdt5?C>?|(65skiG z(!eIAXZhFX@72#UA8xsIS=TjjRp^~aafyc;Ed+CKT>H>c?B4vep}N;)*RPD{WiKq} zuV3^?Rk&7J=31iRwvVEn%$x}Zf45Eh<(@1h#eQJr<0(RSG8RGbR;f(d2GwkF05hS-`1gbTghhLeM_yKyKE}`V)Tpm`kTb4 z&Tm{H@Mh=kXZ#vZJRiGxZ=I%XviQlAhnpKzKkkdU_|)!ZL2IQ)+Rx`9AFD6V{Kv1k zZNu!oC({qR@*i0~t?YC0kEf>|7EKLpd?}TB=1^#$Qkmw}2){!gPEY*P=*YKk_IBO( z{F~>;LgsU}H-i!#^Shp`UX+bOBbJNIY99k1!F3{Pj zvU1AYE&R`TbbnuR%{4DrI_dbIpw5kd=KNaYq8kzE-Ml=1Tn0 za=E`%QeJ3M*8krRCpT*+pPm=clX%cUYioFFwyWK=$@{0yZR*&^f2J#7et`Yzwfy^| zLKSTHJG&KxOfz(IQkL;!h+4IN@(IbW1?&wwe*C+dWwmee0f7UL6@0wC4Sn>dn>jA9 zmE7}5ar>H^Gq-;H)%)?fchKX9MP*&{!o-9v7Irjlt#W+IQhGjfLHd5{TjEEvGJRHl zUb^z>jM^{u-cbqS65c-(+E?N7hAthsQKY)De=>y2A%CwD-0J^MD3UP zc{FftuG{x|{j+ZicJ|a1crp3Z*B<>{@XO=HPHQ`l`};e!jy*V+m!khUK4pL9k3GhF z#F*lh-~PW}zyDw2BKP?Uo);{-uRB&e7iJOI{ZuUe?TO^}4Xe1adbV5IujyJI-Z&?B zwwt{Cbx)JcA(zFxl(zM@f4p4w{BU#5lmMPrOsT1{R{1pn`~H5~vqam6+MFg0oj+onXD6=rOpxgIzG z>!K^1Qv_8a?4l;^?|<;+>`f`B&83^R7KB74B}N-IJzAJ^Kl)@PYf@?2!4~Ej@{jJ` zzuSBHuI47Lgf()nj68+jXK+iid~+*!`s=O5{#yr+pXwGmeEVEu;iE6IAJh$48}=GZ zlINJv87p~Zhx*|lJwMNi6Z3!`_XqRl3jDq8=HRcn{*RJa;DS0Ab>sW*_SN{xrYf7TR5u^;X13~AXVMC; znmFP9qom+|`%|KBX@|TeWzHIf>`YE;Ntki_^SzwEtA0k`KT_A@aq(L8ZCzWPwqEt5 zz~vS{Hb!zC@$@p$-ltG>_xiKf&-z}iZP+k5p4s93hxH1#7P1`_mgw5_boZBr3|F-^Y83C z{6Fir-_*@Xky1WtcPjIiSe#G~xaZS&`c~#!@97-;GmmK(&1HVi>D8WXlFfH`l3-0) zaH36N%;7J_Vb{xBy4~eP8?8T|4w=~ZxFqMb$L$EYI?e6Ztt45mCU`r)+&gQdLC*^- z2EkjpHhWbbEbjlLdr4#VhsC`L)%>&F+8YgW9_|0`o9C9B@4&FZZ~5;j=kwmJ*zFMK zvNlU}&f1x0r(Upe{N3abyX3~V4{8(VGNcHH1=jNBzk1lt?7oOocyG(g7%s_Af{zxo z$0dZ6$wYIh7++tk(=Xr0^5y+9qjV>R2|q4ml`b)=O{-bfvG&lfN4OvlN zR!2N&*J)aC^LOOo_0L%kn+Gy@l?cjh=9B=QFUf5K4faTzei`E)jJoe>A=I8v1 z<;|INH%NW<%CiCU?r)cU{7SuwvsFIF;l+mU_Y}WuF+6f7pF1n*bxP<;hjZyi?|qE( z@zcqP;!xCD!F}+9nPH%q=jF31tA1Y3Red9{f#XJ9y}sJ>jO=Rp(!34#CFCyU=`%0g zpe@K0RkNviYd=rSp_y5A7gNqlF#P)L<#?83wOP@QlLted?up(Lw|mx`Jf9b7A2!|$ zGHff1*>$79=$;3ksj1a0rGhK`GV@oMU(-AAa<(&j-a3=l%4=u5dsY85dO_!%DOV4D zOD`+feu%+s$s*MvRkrt+WryVex-D%`<}h2&Xik$g_Rw3tC}YWUFu);GLL~GY0ErU z*Uog#57(am{n(2YPMdmeNXx!kDzRQMX19(@VdJtK&h9fsxzckLzkb{mb!l%c@2ZCX zL4jotxoY-1u0DODEjLwhQkRg`g+@Qk&g`1_wZ&W4-#qZ(y!S78nTLM^zd4-{T*szR zcCKu;)b9nq7kHg|?;go-FT*X6DfuEbsQ47`g194GF7p4GGS(+fHLFq*XpH{${AvJ; zd|L8{eHJ@6XrEs@^Z6T(uuR8?w_`(uSPep+$Ua&6(Jn~#WDsM?YPFdeEwbnQwomxP zsG1*jcJ>-&qYdT-FLSs0n(6)Bq2r&W@nh|q80|9||0E}yNZCy46sq(sO;|YT7`M#) zwGT?SCU4EzUv=23_2z=NKUm)~eiLL-WGFvnde~no&f|Dm*ZS46-Fi%&sa}UT_OID| zN-TBd@v4AJB{_NxBGEwsy^KpM<^9fU+&;Bu_ERy7+aG)celE58lN%&4ZML*tl(?UZ z-1Sepwi{Q>6E4ws;WC5iU4d(mMq_Vk>csV>k~efJ4z{g&I8pD&)nh-)nT-WiU^X|LnR%-4lC3J`PVveH&$ecKVU+CT`xv*=>tD>Y z#0{64d4$$}FV#sge_NEPdZ;_RPiZ#8R>>PBhx|WRN9w&TF#We_?!wN$|5pfqzjt@W zrV>~7_rjv9w3?U}zSUWH|L=rio3aCCEyCw`7UY$){^R{!)qP9#E^9bTdjrG7Et_q1 z|EqM!cUB0n3y(K@v9nZ7teK7C#8cC3+7I`lkwGhZjg?A-Hsb3wU7MM z_G~b||00cf-uru7C*Ei5`|Ps%vh%OiVIIq;Pr9i6SY+S(OL<1ZT|#@LZ%*b2ID7l^ zyi+x77k*tYlkyMmmgr=t&%g4RiXu&^t4RBF|qRP zqr3Tia@uza6aD0z?WIi8=k8-Wcp_ZCx!E|7@pD1IGndHv4>6`05y6RW2Tq*emozI` z@>$YvpWm^d2veI)th~|Nqz|iKJ(VSWC?!|4*-m+N)%4i`Eb=PPdZQxMIj!2we`c~> zbhsVKd-*}Ea|d&9;|t~K&-V(RuZ;8K$Y&5gVHOvbnG>%+!P+{(#pQ>0Z1*u`FDENe z)jzLh&S9=Fx>@pI#^gQet0%8DZfi<@^Iz)mB~IQ-3G0t7Ive@t3f#Jr?98#caq6z- z$N%~S_E{92+PjJO%I_~fygLtSyE@NJzh5xtvPJIn&AWJ~b4+-=#bS-{jckW*-*wfm z_ivx{VSS9{2~h{lx0PFq6Xb6`YiSG((qG=Lr@YF^z-`7~{i}Z8kEN{BW?y>k-@fg| zEd0GTEeU1U)G}*x(umQ=%)u5|GB`SyyQf$ z%=b01D;rjXu07-RaO3M6?iT#os@}V7^_PW8*dOj=7vWg(SmF4C`r5qS7=bO@q+YiC zdvR&H)Xp2>zqc}Tu5nU+wr%ox%ey!H+?ECQmhM&Vt!H%>7T!|bFfW#8(xdvH(i4yB zGd$YJvg}!==OhP75gFgf$yZ!&t~ekTq5AMxaX|f=NxTl%GUn^2?Dq)l5G&_MXr0Nl zbG}0MZ$szU(_-3LA**cCAAYLoQ!U(j{$^L`l@jN|N7JurZ|k3t@p)a?lay!q;odQ4 z{Z_|*56j5fw_c1tJb6XOj@6SY1NLfvR5#`i?)KDO@YFDgrB8lK(0APfQ{&gR9_G%x z%{5z9H>M~3+(S7Z%UM3PP0!=DPrKNe)))O`(z*SsCRM5hHZ=1+n%??o0`Kpvmyd4t z-8_E2a*4k54EN2(GJ9`{+>^Upyk>pv0bI7)%Zte`NoP~r zK6~x?c_Oa%aWfY@xN$$o>14`n+2`wpemyo_SYgMxS#sfRrxQ0h&3-j)-s&@FZ!NQA z&q1vZ30I>Ndy98`Wo<9*cCftFtsu_8)SCQoN`_8d=))6x1lRE`GUs%jvG`H$u7A73 z>>}%&Tx1WJtm%Jac;W@yjLCskx9=zGPL$lXTT5By&(l=*746xLW}Bum-E>qH9r7qIw4QsU_}=ZF7iQX(ue`VO+wyi_h{jt>_%pfUhb`r!@8>~#FZC{ zPFX9<+wxrSLaoYyd3$co@GhO&_v`6_`5CjnJyWS^j#8th9AAqg~(`n5YQ{NZgyEI!s=A_sw&z#jiG+fqPo8!KhLEUUkT<80gKVgp? z13Us>u%vH!cPL<$w$NOOo72h;Z~6OYLc8*8tEVjOn|dZF#G5B58?N#4n07cKJ$Luh zh^5WX#brO}l2iZoY>0Tq{4dqtOkzvgg!A%~;&`P06vaEY zyLrf&u2u=|PFH>#=dgjNcinG}{mosfb}Uipl^nJff92|TE}Y2xbk!Z_qp?Q4+iKeP z%ns99V4JwagQX)t_WQ?GuV2|*wF|ZCZmGYr?Rh+R=D$QsG2036#C(3dZg)Q4QtEor zV)4Fh7s^(>=CD?oE6A@_H|6atR^y!QX9^bl=sI(s%ePZz`C40hroKP_m*zhc|B<97 z9{cf*_hPmfPN%$MXG$3VEtQ&mqSPdCW2v4E`?75Z<(7nQC@h$M>m7&fhBtqHxc#25 zVp+59bZpZ7?!OC65*wdRy?(w-OX>F1PwqL7OXgSoZI0fmDY*GD=e+&#Yg2gpD{L#0 z=eIN#iO8S4e%#CQ0L!685$zgvXO+~Ir=BV(-s)2p)*0|{+P7to|2cQ7aNWq+-K(&8 z-V^RDk+s3c-tY4J*79IcHlyO~cfGqm)bGh&K2@8YSK^9_+r+n-sh;s>jfW;I43kbY zU|b-6J8AaIsd9%6TFO6pS1T?*rVzfcE%c&5+QPjI_`M|k`k{OG z_@p1L-o$L!)~c-Z_0Hmz3*H=V3z*XLYU!61G9n%Pj=UdxTA$uK_Oe`%a$jEl}%F_|;ake8RDUb?AM1e(Wpnf{TZ_mhO2bc6g#!K01`G**;rgS1XG`cuwQ~T%N-L z66+q9g|AbIek1bdQSH{siYemj)++Akv#oyMdFjF1Ajii{QL+JR1XndiL>)d1&=eIM3Y%5)2;i=97oCVk2B$Q%DM|E)jweyO(58x6)RKfC#= z5(TH?`*ifyl$_Mqt9#8p?P@t=&>#Egz5f;0dd?HsXefASM`G*Fc;>+6i@)#M9wcgd zCTHvMZ+D76h|hcI?(zG|+=R^cdDSQOtY8eaeQ~;Ur$)K?%g}AS=YQ4C|7)v8R4((6y|`fK^JV8bB+Cl?X*KO6Ub_@!=eba|UY zwPEm0cI^`~A?jOL<#HwWxcz-{X3O%cALe^Z5DQy>e@x9+klF@Gj&i&TakQOQ{O z@a>rth9Z^+sZY}vPF}OrYPyrG@rI4l4JxbNteo4Ha=9(XOs=toC3hZ|?GGN;Il)d7 z%X(($W(&OhaC_@RLykQwj|e`TvgNG$->;Wl>vpZ5=_R{k)N}K3Hv5-R*vkNe2JPJ9A`RwlDsuwEfb(Ut0yA_*E6|IQ=8?7Lj;RGpXRGwW@~LQZF&*R}_5E_qqGYUz8oc^}FxlV7M`U1pQ>baUOOAdQ)Y z5#0rI7!)e!9#^Q>I5vHX)chGjOiUsRv&25nn0+%ebRt12HZwd~IMC}Y3p z!=_mqid0r5$j8OrD`PsiL00@paZ~F$-mB|mb|kv$hUrhw&EDM1^)4ms&9_&d<~bPn z%$;~+;j0yAPlxA}e3J=0eNv&m{x|o_W!pYX`MJQwS<`kV$HyfXB7LXZ7s|HHzN>z5 z!z=cmw-Z@kAI&+JaCZI~v)gz3mh=6bztWMTfiv~uHsinBT)1Z%MsnPX$mUWx9qZZo zbL-4!bzkd3ojS-Nys!qAu4zG<^E|{#TvL2YZ(tXFWZ2W_U(- zu|ta2q`8X|{6Cbo98lvqv*Y5enq4{?&-_nwr0IW{!}D=^lGr8oDRnGX4YqFgr!sZ) zwArbzQ{O)+B-@Is>BZ0F)+L5g*Est$g#_!mdZ&D@ip}McJ$uZ%f7$-i3pO9vrrjml zZZS`H{`sh>hb52id)ug9u~%c3vvy*uUQk8sJCRSx@s2Az9aPQci0*Ltc;d!}lP28} zXX8b*?JUv@zr?P-^LDR|_dkX><0EgL%&A~Ml~vZ@GxzKDZBIg<6j~f$=F(cWM)~pE zBKPNdwz|JhKiZJCXRd5=Qa$%0_5|7dpgC)Q^Aw&~oVG+Ne!e5;)W-+XPn#dn4rOvn z&6>A+LZOCJn#z?^wUc-%jM{|`aJ?*)N!aj}-)6&)=IJ-*PriKZ&E_K$QkvH6S*H@@ zn&TWa-$d(q&CU9A+B2>mW-jqcQP{m!cFDejEW&TE7W+%*>(`qW&35bfevyG~WdYNL z30-c&i#Q+1#yZE(v^mIj^!ko%C2c=+G0%9gpBifV zPMQ%?um6#w{M-f)x!ZH>szt5}oP1xSu(-awJZ3>-bkaX1zC@SnuN3CC#kwR#y~$H! zbP4#X_PJ}?zkPRZa-7O)VRqlBR(OBzT7hky+H6UCKeSGo&K$06tN(S!@8qk+3Eld3;?th9 zY1}`b++Aod_35$p^7W=5Pr^RDh{)%%EU~yLzD^K}0;{<-^2timETR$TB=sTPFFhYwGL6?Vb--J(SHhd05Uqp~STQ|RpY*f4uc|2F|U6cQ}QRRU6|5V%YRyN-Q>o--$mYing22O`13~7|I8QIjq)z+R9|m0 z>0kRgRu-Sze-=DnyL<8VJpFu~DNXsW1t*_;{IuiVLb3S;BD<7pH-w+iOy|C8+PshB z)wlE9e>2QT`<{xVEM;@n4@DR7&H*=3h8Mnjg<6o-$J&dvh_dS20+9ejUS}nw{ zrF~7?YT3)Z20=Fjxmi-2j_g@?%&~vdxeB(6EL=8almOn0i~J?RdiD~o2G zvHId5K0VI*OT0$&yWahw>P72C*xBAxTYq|Zwd817uwMU}b-I$a8YeH>mBnAbpnWj^ zq4WBWe^t(ZXFIV_*erE^;8(A($P+$R6W)G#m>c{_%|a}AZ;N~Vl+|-Iy$fY=456EFWxJMxR)rQL4@SMP!OMqh3PJr-e{zIFF6&ThXn z=K~HBDYf}47tXIUU#J^sFgba;ET40NW$RLrXQy*=zq4fsJd%EX`%4PP#oCtkKQ~oX z&q7|cJV?Q%fHN8ZM)$9 z{8jt73?|-dm~wW*OuL>BANE~0dH!Pkwx>52cN+1fn&sCNxXs(Nr`aghu~}Vy_xB4H z-)^73Ui9Yu%sE#p?`Iunh?)FMA?m`%)pC~1iUKW%PGufQzkDHcp^t%%gyz}hF6&#E zoj5MaeA}{U%ezg^PCuC5gw8FHZZ?;2I4W=@;D}_cS{CyY%eIp@=1&uiYnyoV;o16v zBO+35DKBHbTJD$GR@|oCv#hen|8~lX|3d0+;v%t%k8RZ_sAr}m^4)sd!fL}`6`a}O z{xo%;-go`Vq|#O$Bip~BT_<=K{oo4SX_i>Yowz(@uV&dhE#rOb%jHfhYF#KPS@7a~ z^y&3;gdRL!yGuReK5xKw%wn%J-NjhqZwy^bitb4$?Ie$ z>bdqz`?y~I{f%47;sTFV_RicG;MAg=edN9gzvuqK!oSTmON^%a&+1-wy}e=P(+6@K z44hhid1@)M&#;@WYj#}y`uC~&UH7ziT@an`TRnU6`CgYK`9-^y$kZ=BEv;><_l8^6 z_t*Pp4lNvUT){cd_TM{`Jhku3uB&x31(Kq)(-eL*Zr0cI`YOIZRezbpsSVO6+iIj9 z|9E+B-Sx7CjaM$`#zkf^ut`W}o@#x%FHP}>W55I989z))0+p{`7FjKl;4S0yDkjmX zQ^9z5YCzFMy;nhoH`o*Ydop}(3;H3*rS;&8<2$Fz4dFgF16I$U7a@I`^_Ti5y&ZR2 zRW#LZ%~g4|TuN5rcI6rqbv;8Fhp|9eXzV~&@&5Sqa z>{Xq5v-ZP2pN9uo7O_lZx+eNP&&%b_m$2W#is$amz3u$RC2HM^Y(%be{O#`;r%ZEV4P)#;MBi8>67_u zQf<{4Fa9(TV0`}MlfymXv`3PXvG4W2CD`oO{OI*-j=^8Y66;!l7~jPk-Kz`Es;Sx7u2EJC0pn^ta0Y(?eUy6ro9+<()1~>dj5dw>%X;b)MsOR@V2Mwv&Yt*PoAH zbhRYt$)$IaQX(fcpYP+*imbf#L@@GbRmvBaEjr!Fr}AC%PPhB>Df$OkaIF8fF0kR+ zf-d)V`KI@*E4ChBx@5enK7Ostx??jGyr1RmztuH!xxCcL?+mk>F0J{sSM-s-le|Fa z{CUFvwk{THJtjM4^^qHEmV^pET_q_x**9%{_Es5_qciZ*4lhxSnOU-!ap;KYP+cPvi;i<1n3SuGgmL zHA!Wn+xfpmAM|Gg*B?6g@uK;sA64Hvc65B1SbT4Sq2AU9dh3b*x3HIOXtfbgEuVuxxY3#IZUixrMEDu^y&1+D+=Y)(~1>;PiI&e zC|=(3XV}sF#0j{PFPn zBL-{V%rtBhUb%*|$N#aXkJbE8&AP_z&25=i&xbqBIVI*Yqx|+<7o(m7la;;d%Y-UD zZ@pAq7+?Ev$;Ue04f^_tm<|TP|%1 zn=0(L;V2_=3AmmKxBcACIhn}u{X}bT;24lH98)OYllj1s> zE>53x;)BBh%fg+j?|(|z?zqgU?A7Nim9IvsKXg7mndp!umpk)}_Wz{`svhBA%u$Jh5fn#U|78S_UY<$Ly_hB=nDz3>10dr)N| z|4mRJ$?nt*v)Z{nJEm~S-`?@(RCqh@4hbIqTMz1IT2$N2Emki<_NF%%6EhE2?z8hbb$o(CRNINKZ~gNt1toHN zSDt#kUH0>RPXZ&%>{WWN1Wr0ex&pnXdaW{xVuK{ z+wSh9H-??=XJ7X%)2aXSs$|Or+oWPwwZHDa7dE9oXRXPfIX~uKe6_BoN%h#% zT5D~OxB5I9{8tkt?z!YoDpRcIocE4PzI~(Ci31C=_szZa^2rr9&q)T!w|5I|?@K>$ z>6wSKzM`3b^VI%14QhR{>(e8Xo@C9>iC7}W;&$WH{+sU>>0H>kY~_qi>F0x%v%Wq2 zq4(JDtcL~pEq8BQvoVITEG{+u9rIIa=Ih%h?{SOpt?80^bJXzG@2oO8yO`d)vyR-? z`afUW8IKdgIyKt-iJZ9$!YKQ-2Sv!^Wb8mTj&-MN0(k;`z zzYpUJ_x9S({p*x-;naEilB;#!8ZR;3)s+75C2Lm6o19b|dyCb{pBB2P|929~O1piu zSw8T2);wqT9bdM-y|GTKgBYSIm zm6#f5`S?0MUb;3=NxW|wSKO&rz6R5DKF(Rk_e=WN}c21nO*1$jE=l1NX*mZUP3YyGJ{k*J%w%?O=JN?jIlKo&}z?aPnE!|ecUy%5x z#M^uL>VX@*S|;0S@7#RftHeDmPdx7Q<~tjM1Xf$NJnDJBy7e%>`!TKqmXl_`Q2gcD z=ggVx`{e3&mer2iTn@Q(d;P7=^HJ{-O6Tm9y4YJe!)eAX2?ue9*l%yEnUc<>R-(P&S{5i#*Wp6eq&bldcEwg<4&HM5d_O{*v1(M|quXeub z7GLZAMe@>xqYs-yUbRm#e6cL@(Cf&)f>(1V>}(6ty><_ce zmOI(u^s@c=9p)vuvCBTZe{`{T$KK07^ey${Z~gloxcvNKZ_XPnu}icU7W@kGY*rCm z++(G&{^;qjyj=$>Cx~AAU85iO^uxi4(yj|TGT9{#n{hU7JUIDa%l+4SZfm#XSnHj? z9+dh2HCSHCWxb5dp4gHz6ZJ(X?98hu)E;epFEO^^4=+i@n zqv?zDv%g=vUzzaj@X^a`b|bbu4h*4Uv^m3r6)(^ zD1UnUCxcdXO>w?1hdVwJTG8j8Z0V8ZWV>y>O4RhuEvMH4Yo(dX*Wa1DSNe4#^Z62O zLxF%-ruu(4b@@LFnf{BoE#+>Y$Xs@?)8g14p@)lNeuxEx-|Q-Mcbnw2EsSGcoU7QS z%U`}3|6jv6?|I~zk9M!W9FA-+$p4@aTHRS+=pnyx=iwKQdau1zZ38*hU6^xdvgPqV z@2+&W-u4raDSUZv)BpL$T=By4VA{3t786Bzc4-BR%D(Li&kntN z&UwZ$Uhd}&-jjLet{X}Mmz*x1Jo~B66BR4}3mguWnRCzPSbI;M#s1ABew*{TQw&Gm zY}`2I`Hwq?ZrkrTS+M;nUe|Mai?{zGsPHg&}UzIu+J={{C*b3<6Pn1iq+h?F+ty`U=|1Q3$Yx9RI?}Huf zB4R9RAHPhUA#|;0@=pFqg})^{#NV%*7ErzUQHYCx!0F&#yZ;9dhG}eA_N$#Exb~pR zQN5F;O@B*8H9d?a=3jjD^69)SCsUs3_$B>dtuwoMNP60BaarC)GjEktA6~tc@13T0 zkoK4Ky!_eeDeNZh0bgf+IL%sol*!4`u<&f)^69EPkJ-67@2)?_^8Lc*O0|p+;?Hfm zmT!Bu>A|X;Es_Cw0X#+jMY9>d>CLi?n>KagHZcQj0sH4G_o$R?w!FNc+T@k1Nb zzoc>P7G3YmzBRk9{mZ9)o$>se=3jm_BO=Y^($cqkp0e2yAIz@nMI}+_PDyd8!mr!*3S}?LDyInNk4vj*!>uS5K|)%=F~g#dcxh z9-|X8gxFb5zxZBIxn{nuXNbYaw$See@#5CW{x^)){$Y5+RbD$)(IL}AtIIQS!fV;i zuF@^?m;MPJz4SKeTg6)!oBjR06MhJZ$UNCQ&&?;!U~Sct+@IwYu6!4kxiwr6@UDrv z`*yy9^~?K3bzXm1N<~&K)Sq-fE9h#&UOnE{7iMJ%+po&${oVXQ$>QG+J0X9K(_xBz z7P<^uotEbucNVz%{8EJ>)7eWkYBMw*O5UzJrXf0IhUby66wu~ek$gf{~3>MBdBlA2YU4{H}Mk>{NFWVK2ltF!EvIQ=KpheQ7S z+@0$BZNoFqvzw}-WlE;}5YJ5hFZ6%a-jLo820>A`{n`IJ9GmyM{ee?sA5)D-3p1#vANQOoU>o{#Qo{``&J(Y*>_5jHQht=cA3oLSzCN?K^OzjBseqCcOWeHQ(^=>FugVkO81KFLUwGn& zZH`~Jo6L7q2{^g&!*uP2>X{p-`Y}vrTNvYadSS-wz#xe!wp*p<&p!7v;7*2ky2IT? zj%yDcDa&9`tx?*m=FaUby=@bdgf9ES_AN%i0d}k(aC)C^KPwPepZSjE^1BnOS{aw zpIUx2X@Zy%JdF=JBlO4@b!zJ6F#=2v^`?)t1Z zsz+M7(%v_Aw+XELG=G8i(%%oN`42b+ow@LM%a=dL&ey5zT=r(^v58v@=AX1kMzrel8%R!kSU^W%-g9tG;`9nVn_uvppOxGQpPjV}6ga z-R~DNKlqN`V`$RM3O=s&^5wQuMy$v5)S}``*s8b%Dgy5vSMOlif8lx6rHN)q^A;UA zX!5>QCoZH`GPvN*{iARG9yM~QV$XiPI7#DwLyGeLBYpSh>^Z6RNl?M6L^blD)T-5< z+S85Zz2uppWLqNo zzyJFZ+24y#y_P+7kdb{u**vC2Ji45MYxb_`N?b61!+N>L7bPACp5AmozW0ymB+>4c zom;2o+y8qIICs%A!5)!6(gEj~W`y4;-@D&hefb*JBR@m$bhw0kD5(oPzFL3o0sf;W z_da~s-rHTw`}5B4<-gl4nx>elw0^#^y^~>+HRDnV&xraM?@nLaa#>f;=}Yx`&CB-wRO8ZYk8dqYZvIX?e#L~pn!&)K<2^3@rnpv zsaHLRA5IhrGFY_Y$ZfXUmOn1) zkNLwqZ#%Nz+AHyET4;&r`h@o#%PMVMcZdAk@{qB@ecsXRZRfr$F!q#uzAx>crh`Cf z^07_PTQ})n`4}QLUD^JPc$U)%xmEim_d1{4Gx_U;DT|C&n;WT3G*tT8Zhi4})lc^a zPye&cQTp}z%F{mruQ}Y?S2}$Sy%zD+X2wm+BM?PlDQ|0X4*Ku>G0>5k3R6qEj%fNNnls|OQBkw4iz0+jUZnY5#Pdp5lrKeYKjA>V1`zLajODkXa z*#*BB%Ric7T$ph{|Hh^4hLUIB6suML2zg4qDt}+e`D3NVri(F4Pt6MtYTwSQvfbvV z%v+vsuYzO?xaNrb*VAZt;6F=j+s~;>on%7_4KDO-<$pR=>v;Tw0tL34a~nEb8N%Q7 zu~elm=dae!sn)!{BWil{#kNCdSD8-gx|hD=pyWH_KMNGrKWAVMyKuf>=cPxhA4Pq6 zBFNLozd+l%_}=2?t9EPVetRgMmzT9DBfi}A*{kM|qhHgK{7lWh=C?gF*Ss51bBp=V zx$2@PMMW!`F0(fZY@B-jj^QE2c?&*A{i!+in?+^vnU~*MYzjKG=eJu}mI=M`atjFC zvDS|F)slIFn{Uc(RJqza(k>-VDTHm`prnkwfhv8MCp%h%$wW@_35H_3;0d=}^9T-JXgCr{3l{g$kZ#uI$N9$TynBmo56xOH=#$bdfb8kFsZ3_P1+3J#TzuUV`N-p+Bxg z(-#^P3H9oSaY0ccCmAXfY%bkDHR8!~UOS9^4U;LKXHAU){h6-~_sp$a|2II{6 z3F;N0C)20*r3k!WFY&$ZmRvP=i)Y7$({=ePu2f&kzge`)|KW{0=Ts646Mi!|9$t9y ze$6ZP8Y>B>(_Y3}DpAGdbK@S>6c)T;`4C#P(9|=qc<}<6@_6})(_g-jKl**|);4W! z&b@sR@y};};@=S1^NRTd-?RNwH>vO%JFW~<3cRyp=1soXt*e4h^9j5XKFD^haGHN^ z%iJk$?^yNy;=iuGWYH-xed3O1d$eq#Q(v?-*<@YNeittt?%lrn<}pKy>8n0&Q58Qj zBV^gL7p}J>K8yA#SFF-BnVYbC{WR|I-$AD$dmCq5=VNNPd+oQvhKDPpUbeh^VUr;9 z?VYez=INNZ{Zm<5-xyBvtg^E!YPnG8nuFb9b582sQb*8Q~-Th>9zF*O$ zNEMTobJ9N|7q4!7Q-0Vuijntg#P!WfQsvt+wg=tWuNQvqXV@Q(8KoI4Pq%f+=JatK zx@lZ^Z|zr>?UuQ}oRr^8ouS3|kn^}@x6+a~|8}XTgzw1lJZ8T^Q~dLvq-UG%UNGHw z_+s+qKwgtynF8tYQ}(`REcOCU5_1v)?UQB=&1S$;Ary zY3yY^d6PFMiN+l)xXTx2sW#u_(rpfbS_Y*(+|P4ux01|n|Ne=b zGkKx%m7^dvC^fd|>V|;Z>t~)6n0@#AF0IffQ%im<5?)gO;^!t!<0DUEH}9%%{KTaG zd(DIpHr;y-lWq#|HLlfq`F^+d^AaPSV2RZaBL4hRKm0G3MP#WayRwDAa--Kd9iL`S zX!-T;!ugX$t`~l-oc8pS^^H#_K1knpJ#_loABzQl^A7zx6gKhRbnDmU3$6s(dDPzu zE3|o-F=0KM*ZWmx>-NWn{qQ)vak5;ytl#O61uu?Y^}XrveD#&u7w#YJ0(mY*{xqB{ zZ7yD*d)QA)*N*@1ir4$6O<@sYc)$Gb#>EwJwk#)C&8u1<9&_EU=kxh6lPwB=1vA#_ z|B>PF_>;3>_OadKpKrZ+5zcI~t@p~eF5Q)l>-e{?JS>o@-@5m0;&RE2c9y?PrXD_4 zkSFx$Tc?is*Q3RviOh>M4~ENfeES=|`M9;EQJtOFHNBKs2}YA|?^0sdm?WLz$YZ^& zf19OZb2mAc3*56!j-Fl=WFX}nVBBEBr^Fw={ZdxhwwofBPWOFc z9kXT`Pc$<+vVFgP&CeGCp&^gDK0VzKc;^BWql81VNa9n^k|(8?Ro-RuZ0h6NBY1#|weKm0D8k&0412=P%&@kmi}=DBwbpncn|aWp%M8KIkB(b&SF3JJKDh9Fj=a{l zCmdZh*RFOh&6rryQ+(EI`ZHd(IrG;w`qypcw=|r;Je0-G{LHnlPD=l0`L-}FSh8)? z)9V_0cBIV_l!`N&vGw!MxM`JcS;m{V-Y}V*{nL{Ae`{UlX9LBmvnTnEAG1Ete)agg z;5Yv__Wzz-5X)?%uc5c{>)DOlx%4|V3}sezTTHcC<)G{*|L^U&0~c>D-KQpR^3?Ll zq>GbYe+wwfm{P{hV)o?aBwGpZj@6R?mL5OeEBkuI$6S}E7p`+9Fw`2fZJg_OeNVz| z?{34zO|C1o58Bve@A>byGH>eqP~n>r*UyUz?0>Ys#bX1PGesukzcO%?-!9i(VD$%sUqna7V#v_KXUzdfor8B&q5pY*XfRJ12g2%8?1d??r32O{jkI zZfCDuiLXrV#s>-l-#j<1INoH@ly~5*=d%y|vKrP?9w~*fWyN^D{D1gi)yDHP_Ng(n z*k`hQ4)S^Cxiw`6|BaRN`w~~~;bOI$XS?a@+1d3jUl*kNCiackEOtWhhQ{N5WTTby~M)@~EG$w9d+@1$Zl`?+Sfd)ErdU$efk;L zoObHg9FcI#dv(i=*OwOD$)6N{wnjKcbYpMEnKP+AmtIOIv+=IVQmwAOf49seS&kId{Bxwi_yQZv1-tH0y(4 zUg7S)>N~f7iCS=8PK7Tm?EQ_**)MmwcPW`a>o_=}KBT--F>|^45zjSk|L*bsQ&j1X zTzboJ#ughTo=svsn;P5|-l$q_;NGMVk~6_y;aq)tP11~OF8L-x`@`K|1X+a6cu`?8 z`8A)3NrRDX;PL(a%a6}goA%=ZJ73hlLwBn`Prj_Soi+KU=;a%W9hbItU;SC9eqJQE zVc!zhgvPgWslEb?m*UeNt$bTNRn+muQA-trfa-j<;|%RfE@!Ibi+XKTmfP??WyZmR zm}S?USuEqWPLfJlpLlv>nu784!z?m^V5bq#61iI=3mZD`#o z?et24rM_^xMLT=f0l%7?e~Z=_J^vH;%xdw&wt$MyMlKpZSTCu!AKR_8L$vXj%fzhn ztG_N!)Z`2w8hCm#za_hYDi zQsa7W_nMP)db3Z@%-$T(CBF?k)#@(e0a*((|7r{r~7^rLVo=#1&Veg%-%H#R6>!$r_w&hQmzUkiL=q22-fv$E5 zQdN$boOd4<#mm~Z3g2GL*s*0spXAI1v!46BcG>X3oK-|ne$`Z`pG&2-#(yo)d9gw7 z?ey+bp3yQahTXRg{AdU+N!@Z`0`t6PrPbO$zvwF#Ti0^gSrnmKSC) z$vrE#R8jc$Xo}a1n5t~cw|oEmd-*1NnR;Ksj3biE0}ftDn4BHEcf&Kq@)Pr!)-Fl= zU$N(W#NU#gfeRQuc_jAkdLX{BW$qrfe-?Zb_OFgS$aJn#vq;u>U;VCcKNoeV^~lW8 z@!u4Fx++j>W66S^j?VkvEPg-#xV_-EdDOk|)yr33T-%c~)j^~F_bUeZgxflAKQ%4Q zzbnnS(WjcN_R6nU?vD0Www`M~GWQuADc`;%YXX;Ar^oGC*Zhv}?wZ{9F);h>*RY^p z|H7Y{SIu?g&5;i>4-dHZC;9xeeG$neQ;VWst7cyBOr4YP;=;Q_t6kQfzq;?4VBiKv zQ&)kY-M_m2xAx3roSwfUbIuC(PmkA5IIFu?FN{z8aRpb4LDPeoc7GiFeXE_gM7nN1elugVZlgb}Vo?zAt2c)U%3+Y3!O0w%8cn6TjZ| zcc;zbZ>JLKIR32`^+{791^*`KF&2oe`Ej+rxX0j^FP&r;gU{xF-}O z;5<=zRo^cy-SbSLCpPiuZ049+y0yJ4?LOD1Ntg2{dhWi}Wwq?uhnBw%3x36Ud%WKw z-czo#?Wp@N`G!Xl`u7$blX+dNeMC|FgVcx27w=_F=SRiAIrmKA8ByODA2>g-%5a{lI$_V&>~pc}IpSqimJ8Tu*Bm(a%w+4r zhPE5eN?z9`xbU+|sk&E|>zr@UwGO*&>(j7lVNS%%tLvDLDRPGvER!vK#~_?j$Y%8= z4GY_x`EMTzF+{vHRI;-BsIlr`jEO7&Y+=dkce1dDHiqmXj6CXNsISD5+O= z?GW=7kCj`R&(3{#NT6WOLZ^x63~Lv3aUN&a6A+kSb7*JY#mhIW%$S$0JC$6YDV}DT zA-;r3s_|2s`GuF2PfYlx30eu1eifBYnZ>3h6d6>{!DQ$lxBHC3hKnnjPD-o3vEVtj zve{TBs%cZcUQ)R8Op9Ne7qkDIbpP#ZhI^JjqE6bsWeC0#FC@Xnd|fRs<*clNoT5SA zRar;&* zS#;kZ*=hE&ofkGv6p($%?sH4pv20Jg_M5uw^z(LmJ${~5e}AjWv*Xj&+F2eC0>#89 zM0+djXPes?U75C(|jTX;)T&8TYtm(&uXq~k(74n=5X7tB?`}#VI`3yJXu|M;nO zN`KdXi?ZC3v~l~ip4k;n4EH}Oo(kp{*WL3jOy@P9#WN4xTk%#J)&Bj5`6V@PPQEz( zf7hj-?1rUWlR~fUTW#YOGg;F|<4}$5{+&fpd*AS7ENNtF?0VQ_>2&wV_STDUo$Cxf zd}~u^^4i?{@6MjBoHbirUq&S!WnR3aIewzJNa%`fuk<4-C!Y|!UAt*|hTf6``Ab=9 z+D#u_-mW88Iq9j!)h#U>cDxTbP;_`d$K>q##m3G~-cMxi-rv`M>ZzSEZ)MH4hYfl0 zwl{t~e^h)}<@i&R8uPV2UJHIltPIFIH2MD3TQ9SYTw?FDta(ryxF=v@1%M;DQrRRR^_`-ejQ(i7tmu&mT!8Ri|Gsn2S&r>69b=9QPyYlNhIid2R?>x^?~4@79sGUwTf{_U75Ht66l~ zZt?q`K3S3P&x!)0o`+>5rWOFH5}~ny+li1`@{}3bBc=y55j@YnlrHa*Zf%T6w)c2lS zbg|6mIO9GIhBtz7UY+y$H`jV;Z{gPo-CwKyf1$>)(o=TLHs@a3R0p2;a>Q8t{fjR7 zcOP2hw@6+6mUWXobKmbNtSaRbYSwmyZmhFz{gWi%82#;&>8A_-f4`ZnFiVf?M#8^2 zr>;HF;-7ZD+4K7^s~gQvp3Rf_b^NlW0KXb*OYFDw)P;|}dnPQppm1&4nzOrH`dZu{ zd~IHk@&EdCPsRH9Q+3+Abgf((wtUOjdZ7A(N9KmyZM*dQEBIRzrfo6sdL6W~*50A5 ze99@;gNx+?r;EBAn{dr<(ZaQRbvMkq`O4{1#=U~o_hXm7-+id{(9g!W#QVDUmRLl8 zSZeTV@_Pr)aOH>lW(0dz$Gu9>5Ns8kZ#D11hW!RL$~K3c%-ZymxkNP|_$$obCzo*Y zKL3VTofJ9Y^;4w1c9a}jd}!nS-RccSQ&%2Mu)XqOPsrbW+TXNy2>yv#qP(lzwd;*n z|LQeD46AniDpT%m%5x6N|`0kdhytVi!yBYG?%`7`{;1S zdimA0(M4Pz%hr7E<*5+gv#H93<&a3^<~6sQY7TO4QvM&Y>s;xPZBHNVK0j+}!77WO zR>`%>W@3FjOqxbFX58M&F~cl|)9PvC-X(8K5^@f`dBW?ambv_SuKVj3$Jk7LV`Ck> z^maw|ynXn>cHi0-*WWV=56)PZ`Fg?aDce1d&6~1IKJm^P*%t-P=Sn;_JlY&A$R9h= z$mC19*5SvWCd4RgSYi9dT>JM@_Iu6o^D|!VI5eTzI;HRKE*6WK#Z4uX^IWy3*Mxok zv{Aux&(1yD0)hpizwIwL@^C}rM60=-_m)kc{I|46CE%2DrK!EFUdPL>)S1q{m8*`v zP@A{wv2s?8;i0Q@zI_e16^yVgoATiyvj~HWqu2J%oi=q_C;98wUo~ztZPvSW{g;J@ z#DNz*Vwyir+n;prRG1XC?tJ#ssu!t-4}2rEwUn*+H!M^+@=V-w=6OA)^_x!L(2jh; zy!Clr!tg$8$Q%(b~!9vc05+WmgoH~j}XOb;hacv8X3aIiy0#YKQWS(APKVXf$jC5Bf_8ZPw7^fe#3s2_RYiFH~jp{Fg4!Oecj^D_1RiU(^myAv^cZn zZT|jWDU7ovqR+PzOT|1%YMH9zR~E?`s5ms1>NUzt3>zw&5lodr+e0(S^LSf%f+of zs#=2|Pc2`@w<`ZY|D@on>6sCHOCK)zB+bBav#r*iakt-^EoC!Xg`WvOlVrFo>rgY# zHAJp`w^Abe%B+_Ad&SkX=P#Fw%M0Onz13mDiH>N7Ex&4RUjCu8NX1)4r_-bA8te0A zSNk>};JUX?zR=cjVjh$3GM@!UF6Y=h%e=p6n~TVx_vvXEmY~NptBgyQ{ym5Wavya!WJYQpx z9rnx2^ws+|+e=R~ud#hBn)5*=Pv%75v3)bIUcUvsulObzWu8 z^?T2HxBaf?MYKL<_rzS9xykpvU1pk0xz;OrpQ*JRjjTC#yCc**<1(i5DKhD+C3$n4 z+qY`_8at~+?$@q9Xfr$3RA&2Rez?cc)_pEtZcfY$I&V|u941 zX9vBzX_dFOq;iwFXETl7=&i}0`=hz$|J^tDZG+pF zv0a|?=|IK$I<;qoU2FK%wwGLg_UMdzmH)oP-_nO~{Ce1ax@5}Bdz+hdRB|?MZ~x$V zr{5x^&Luof_|~;km*35E68Xcd@2<%z8&`VYU{lES34tFI_H2vVV}{B&SZ@t%n-6t=}x!q5rVtmO$*ZHP+DH@z|&(gX0p5L`L9pWAU2X zlX@0;r1$;0?qvDDv9>EXL^7dl$-Qs!TwV?{SNu-ClV+_GX|U;MtatUlqI74yO95&# zU4m}$zts)>QOonC?bFih+Ye64N%e8raOmQbsj2Bt4<%X#F3IO}IeJ0oZ>|-~La(0r zUnP5LuPk1CdtlG~AS;Om#P`HZpBtlvq@7Mg7;U zcf0e3HQQm-MQBPM$ zW#(E6gmK%;2wwSCzw1)x={-nw+H(BF5y1oC^o;m2=I{62pnVF05KA75?ks zl+T)ta}>f={~6u0(3`aOcDvCY_r2RMPSG#yI=LZeW*4`PTJ*W9zHQ&sQ&=69=7p7) zZBUtPad-p&Ur~dqJIoGQ=2F5Ue>AuEPTt6W&d(@hg7!|PD&Dm#8jm!txTt>rXx!w> zQB5(Lx8irCm`!*wS#OV-^HJx&AAi+xGFpVFt=yA)<=2c$GMf`MeU@?kZh2n#GS}i| zag8(6+5@`wp{^=Fduk;gvwyS+Tw_=XF*+v%^SG2 z&eP{1OS)}Or>8n`{c+r#l5e$sM(E#=i2eKX{x`SrCN43lU2CB(`@jB?>dv`y4@)^c ztrL>_?=a1?SWy%hgx%E!T zGt`=%2!t#6ym}uvee3Ke>@gNE6thnB zpFUdhWQOB*Hw}%aF&(!*oj7y7?(#`#`PxH{cfIbWwhOJkbh-G@9e+lJH{l2Djr5K^ z$QEB#c0)`yAmi(-z1!XHnu^W;KJih;?58W$ySmdADwm(NpL6Nt8|IM2)~^pb7H3XB zB+-4|_-cBG+0sLq_D>(EcA89mS0s8ye*GSgyJzKg)NP<0liDx5jbB_S_dTJ1@L^ z#9$T3^U0}&<+pLrUJ{@L2;cgdTESgWVolOBGW#wm1;YvKIFy1o3HTh8lnzD$>X&zx)* zGG)oR3CmW@`*Fg1DNEOBt>T&;TblDOE-)|`VdX#asCH{`xn$w4BNZIx;i@c$C9j#B z{IthakM-HFo!PyaJRu6cHo?Iiy;v&TE<&G~MTbn?b= z3n`;VKlV=hlKNs#l&*VB!MAq>kA7uT7G9j1{wUYtdTg1ck%Pzno#lopypFEoqk{XVd~m_u7=$JTQax1V;pSWVDvSK7RWkIC-m$vr!`6()Gs z=}$Y}x4vj%q)Ji3#}DGH4^33&ESUXKy!GHDkr0V(^XG)>h5tV&?Q!A0!h%`c>wDWn zdylYQ+Lm^Eoxsn67n>*4Mcw1ORD9SwRV1#lqvwEn@R?=oX9fE@i)S-)nzufkSax!c zUiq5D*7^nS?=3pzB7T+k_YO_DT>B)wyLl3UZz6qlmwYMN_x$lk=egpwYlG)Ze|aXQ zK-*Kmie+_Sv$>Jy^3Z2H#Wy<~%vx^Rx|8kgjG*-g62f(pM7d@y6KLFaY}*0xnf6Wc zy9)j5`9JSil3TB>stQv z8c{`|faQI^I2<3$w(g&>>rvAzA?Z(IUKbpi`TJZq>}K-hyS7GhlI^qQ4D*!_T3(#4 z$9sgKYIpJWa^Xv-m+-t5Iy%{NdQ5z+eZi#K*Q?jB%(a%|*f2X}=Wjvb^HW1kKH2B| zs?nyTaZmk%2R&S?7jS(sx%u~`?9SyOFE~yA2Hbu7+0aB^I$T{}yvAK)%_I*=x*f*Wozw$~#8ee+djt5s5Is0;o zH}3FoYu4nESs=fFw?n6Y?wjJ>A9`1P`Mh_|{nIluR`zNCRjv5IH}mKu`_wPzN`J&0 z&$Hg7rLvau{rz`4zD{`KC&oQ7DD`El#?}ixiz6SkYuVjAxPvj)QhAxo%fGkhI{PxO zN{`mOIQ`7FoRSCqtKQ8qSo~n^3YO37GxLvfec!jcV%b6UZYsVEii0x{J(Fva$wuekTCC=Ug>&!3@=3{&3f~DL-o4U`BgawXPXEd+;nEY zkl;C&!ivLF>vZ)0um3Z%e%*&l-(G(`_QZLQhJbwa)rgcO(OH*v`b-p>d5_1?Y3c5T zQaR4kc~*RX@GyTNM`4bCRrRy{NcFER7q%F=M83;9{(bM)g0{I~3mi6ZN^3IAv0(mi z_G?O?AD9oEP5|bf5^<|$1K&t`MLeooO|2%#e9^tSpF+$$-N_S_j`GLFD>LO zc((Qb%i{8g4B&lOuDayPi~N=elfEC|R^Z?_*A>J`;D> zZNHk!8T_u+`{pFKCN0-sQ9E(!g=R(n6!uoxMcIC#b7dMm*;~0!oez*JpLY19IKv9f zOFc<`Q)H+5>4vqwOyPTxuflHi>+IYu=Pcu6k6d1^yYtS1WBDBW?!G-dN9Tg~@%^u& zUS8DtTqh%!kbQc#q$&SV+)Y{FmSe>(%U>5QnYg?6>y&8a-wNIw{gz{O zj?nXc%aqFW`rnxRn0D;;SwsK2`8+JsmTq8t_0dD-VfHSUci-NljTeQ7)xJlvbzWO`Ca|_t+`!}05@UmAx%oS`81a1%o$0O=xopN7KWo<8 zjutvPyEh1lyp(%&G3m1-*Vj$+&R!00I~pQ7&*8HiuiqCbz7s2DW?t1?WUG?Jp~&`E z(I)*)rHU(K*!HQ)Ocnb31cX}-&YAz&C&I95lFSFg2SP7)PWvMxaK55ILfb2~!PN1} zN9+Ej_Al1FIIgX@{>VdFVZZMxoD1~c{tTV+{js9_D<;b)KiUJf{?BuIp;@-evu{JW zE90h%64DDe)1~#R;w>-!4!V>*|7Fppr8#SARb!SqPL7m(x<^Su`R(5hk6po4OBw$; zOH65sTy#a*`qxc9#mOw~3wliYmmah*%QZbJZWr}Co9`pP(?w4{MwNnnSMN5T^;Bjr zIlR{8{qza$N4rk8e^|5mz&UyE6vm$>tLJ|BI9*lSNZ)OJ{_k5k#lQU(W@*Mu^l17s z>*buz9dE92{7Bqzb>}(hj?#!@6Iuf7tL6K?nWsNnQL`i6I78+!|Ai;ZH8%^j-PyDJ zV#R@+!)gB}ZHni$lU3TFVfAXWBun2rgC6HwOpKE^&Cab~e&m7o!B&=;_Llv8g6no& zZ20=`)x7!6nO$`oG)&&j`}?xI;qvsr@SQtFEN1VTwW-POy6~D4$0sXA#j!YvtSDWx zI7Dy8Lxz$|kv|yEoT$#;=~coZ@Mh!IK&9`&jzy^^D;!o_eteJN^kOrYQ_|OsR8!Ix z`iLDdvQ1w5_O0A<&+5c!hj#K8H7oC{aJ4w6Y7^rv>U8kbTPMevs_XaP$~U!4`5m%Q zv2x;+qJ0axOX3w?GVjtW&31Xo8GfqJb-&$hqZfz&Nk5(av19x4&WrJzk0*y5Q8^*8 zvOoC4kp$gKjZ@crnfv)?acl%{RgJXiWp$QUk6d>C-Ldk`qdiBG_P$B_5vM*YE6V-z z(g~|SXEd+4k<0LeW%-2*+fHz8?z3>;lzpwC>PC_CkGCG$^Ut$x*jD$?dBTN;-3+@l z*R7gu##F6ycY=<@x_15Z4m&lkU2uD%W9DK1_Ra|di=;_a`_F6$%}m{NNR!8s&D7~8 z*V|(Prb_(!`oiLV?~JE#IoTN=m)TMsm#(p+f7|~P6CxL#|6{OO@Vm$6WA`3@JY{tz zMYhiB%9AYFCxzBbk=w$U@&2fLsuU(rn zkJ_$FTXM75)Z>PZL-wt5!Gi%U>8h4ij7Q`5{&e`I^>ac`R`K^NnJ*^Jwbo5*mUjAX zUl6*PxB23o&!P`~s&8cM>iNyElEp(x&oD7$a>3eQuH0uD(>NTSHD0(DUffc1>f-*% zqHiQlWpJI*=$n1}>5OOT7v0T`6?@g(_sHJL*kx-bRn6mmUU03Ql-NSe(^;Y_H7#2N zCaC+qk4tauo3O#TF01~&%<3oU&)EYO?~QYr@ku-PbMdq86I0gje4ECTB|Tw+W6wo% z(}i;x3lvYVp45)rvu*RF+kPuKkD0E}eSh@E`V4F1$MwxbQm^u6hgEtjUbTPvzY?`ZQ6 z&RkTO(@=S_c+Y!_vQyUQ4h1BKFMRX(+@(Lt$14`)D&^g{(<6A+iS6^Q>mRRAdvSRc z>++M+7WApw{WvbWR81g;U;SKF@X=Crpa5p=>06Tpgd6Wkkt-VApwh? zOK-Hi4b$iAM0!eaWv5@LI@w+Sp5ykR&V>72M(;g$uRW5q<}|D2{~CJz z?OXYv<*oCQchdX2kKSK9_ow%93qY{S`vi@&O&v$QPz0N%Q%e75O zcLmQ?xUq?4YKH|qD2&@bD{J>_$9bP0trh4HVsWqf&uxETVuM=VW4TxVbTY(vyVxak z?0pV=RrqahBGlCP(r2E@$>{HG=VgKvZ^!ApJ3mQH{HP}z7yJC?s&Bhyt)29AikPFl zklm35;u6!#%{`l&Cv)c?l?o7xemWyl;DuZKo8|1^=bFq>uU1GCxuV+BeA>pM^pN_q zIz{94@0sqJvzg6W@OC@rTK)t3&c1h@#3}tx>cx~3&+6^@XVj;4goJLBU3<;*Sd@mj zR`H#>x!ilC`|rN1R-BmJv_P+}V`*vEEj@;gi(i~p?lP$`2@-PKdWh%gz6l#@=4}jY zdCB4IB5$(pF0X&+WCh-%Vf$6x-EKxSv@E|rp?3X=bWUzvfn|?h>|4FP{9&)_k^C#m zmHp}u1Xn2C&eU$b{5C5=;os}~^UKoTv>HUUuFuc)^j@}Bt$CKAb-R>K>!+ZGeM_DT zRrW=TB{Zuu%UJ9xmu=Ec+poCb(EA8qwzbcUgnKruWqwNk*%l*T#1%e*wJlVk?FQ0v&aJ<{#1m7pN!*edh`7YfW z=k)5g-K>hg_QoGibnG(fdv@pFyTrk2~B4Ea?Pje0AmpEr@bTK2_r$0VovUCBlEdTI(Qg=8fq?(Uv8 zC#&G*w?p3le?Qo8LoH0s&s?YS^S&7mQtgjlG8R0#vT4e>^U^$`Z+5gS42;`enqO9H zvN6Mb<&CcmHPzP5nlJhrBf6H9hlRi5|8jBLyiiGzZM6~lsvY@mTlP=;wlB)k`%;QW zr_=*+{TR=s%EmYN6bsd?skd$IQQYNyuN?U-bI&0Fe9Q&UAh>S47lK<5~W02KS?nzpq{Dt^e%6i)RKZzZX5wkK2{^ z-(=R6j7Oh@BP;c%3ck7#RQcf8$Kr=ZD=zfL%rOYuy83lzcfMYD#>C3HE80e>clKM{ zo0NRr^#21@j}6&;|7y)Iy+5&@b?X${1leO+UlWoG-+sNi*CJ}t$78F+W=%T1=I!pJ z$9gGg#Y}Uq3cGqnF00w9J}bIXmZfjC=N552Po2oqYafweD1G`~AE0gyi#YbGP&tc)Xq3_3wC7 zzSwdVjsApSzU69>Pe0|}mCoA1@=v(%EAzVC`}|XEZ(BJlP_)?%0Yer*?SGy)yUDx%)itWi{v3^qxO| zHcv-BA)#mM#0M!iEbo;bito!_IsNxbiJyFCzSfoLbB?Z$UpvqERX}X`J&rH0&h0tF zvd1-5M6iC#Jr5!CO(*uwO5T^JJ14LAzjXnd&cWYjnT@(%N$;Pg8}#}LucTUngnEy_ zkN0sN3itXiZ@S9J75vF#+PnKwYdJ#%&-_ce?N>WbN8#&)>QD1tM=5_@Tq}4(`p7ju z_j6vo6ZYtLZsc2N^?Lnw?ZVaOlTKJj$9Qi0-o5nl(G5IFFDJ_?tgDrdRocuWW^{*R zbs!UKqk_yWi^sL;J{J4zO^Yn8A0-{D{{2+`!-Escy?f67H9eX&{mI^aF4pT;A3Z$X z?MYUkOv{h(?2qCbX3v!o`_FUtx!g8J#m~JKCdu`&I&F_9Xn55UG#pAQ||hp*FCcjF7Q?6_$j#|kzkfdSyXmVelYhQ1-f_L9Z~LQV42_x9+YYiYtYvtfZU0$( z(`Jt+ep^1CPF6e3xT8kC;cCxzCEnLEeAW53W=TIR_NEj$uD751s$o&LZs+8z&i-WS zN@bab{WZMX_BVv8r5Y~zJMD9Gp%Zt<$5^Q)5qw5J6fVZAXxK9pGuiF= zT)bDU^zb%jKgR9doQs0}64`&OX_%XI=zH5nCl!vZ?>Fld|NmjkurfVlPO#JA`^hm| z89i@&TyTv2QF`<&+YNVSzt61b54|U_b*5SW43Ehwztj?suMb@^Z{Fi0hTcBvn(y^Q zo?Y=3?7q6i<@%M2t*y7sR=l0?WdFC@L zs-$>oq3DP6;Y;R(B|G)IDXtM>K6@dAh>ibeF zrdTbBh zZyJq1&YM$`^=G4(t+L_V{%ixa+?o0x+&_4%dA82hpowv+vrXRXdSQ@WUe@06LzOlNZI ztXx#wKG;0A{e8jqe3M8*^&^8ciSWC#3~f#pb1RxO9(u^0us+gN)NS7p28Q@Ie(cjU zWj}ErRM==I<@-{8R>s_OD{aqT6nVGZjzQH_=tuY4;8IxpM4!7^&t~;?{adxO!JRp+vqD4*PC9=t_LX#RZ;bikW?-ZNhZz{8d zPsll^p3_TgdbqYv_VeN`JOA;_UhDL(vFQ1-#hX?s$vk^8)u^qlrq$p*|HR(j#kzk= zqqpz5qwG7^J#Tr+5##=udt+Y|=t`dZJfXJ8b$Qy&uOB=DEVxzFarX4TD|-?!Y9?ZujG*7ue7P5C~X zE?Bsy#QRN4me36z-RfR}+tr+w-&vItgimB%=}wj{sFb|;|3$&&Pj=3s8^6EJPnS>M zEOW2s;EgwCA6Oc-isGFwF}u7MX;N2a5Z_!r`CsB6-XnSX9(FOOy<&Af%Pe2% zw7NdEBO+tJ@#WXa?n%KW$$3mZfA(DSSuVcBL5|aB(UJ}E-(6j#n-^+M-(sAjT$kqzv2dZCw@|@kL(xm~ju`2^4dP!n!EMTnFAZ%@UK3)@KIbk9TXgZihLFL= zx7DA%&bd`6k*E0Un}}tq^vUY^b25ZuQf~eKEqA1E!HXYkyOPTOU!4&dtPp?PcmAA^ zi>E)@UsJukr<-}!xf}C8{Wz95DD#&! z+k7|5KIz)1;nF`t@^?wi2_Cj}7kl|!9Ql^_UTo&&*zrd0w(^X^Ek#qlxXRxA$$G$O zr;zRfcg8JEOR9fn=7>5n&GJxLHz&xsQsmK79`=o)Gn#Yu6tTz1FvPQc@!B0CfBKo* zeKpQkz1x=Bul{HJ(r@9JkZ;1SQ}+Kq+V`nr#ip?PM>lDHa4(VAKZ$Fec=mI~&AI!+ zB$_QxZeC+O*^jleUz91AmCLBXDLyN7*(Y}Sy)nz~9G5@)&HYAp#p8pS>#dn@FM4KP z`LuNF5lgj8+8f`N_Iwjqq$p_n);L&7u5G1c-0JIpJl;u7y0cRDR&tg{k@9`%s6&g{ zGsR~=XL-fZIBTbjq2a!jyo#2p`9=B#~RYQFwgjh>ywT7EXAYa^G=Ki((it(%WZExp0*#Ml0} z;L0(X*!ksUPtJNSzifEasC|vyF}W{_CNsB|A7!8NwPQjbTrLDGe|qAXcV@tA&JLHy*Xm;rMzI)g51%2^U6=o3 z!Cz}__M2N;UY@G_k}gl6G_rk87;y)Z|9ZNb+Z?lwgt?s+*)j%vBt<%<^S>} z-zI5(s|tE>{J@uu$Fv`wIWBSFjYX}|p3ME%g8nO?D4qWKrrk_~d8Za_)|}=kVAH%t zdEx%Q+x&%^xg8nYd<*;eGY_lmF55Qy_wumZ{sWCaBo}qC$ZnQ6b!nHZq6@G2G=pm0 z;?LVQmLyBsXt+%Hbm{E5!zqnCcO0C$1zz7?rc$Z*Ir+wx{Y~rsHO@b7A{my^yDuqL zwlMlf`d^(FNI=`g^-=L9tM6 z_sa`&FNgMNsO&76*8F+JTMyn7+&gN2x$fQBv63~q-~Rl9hF=E1FSYVVN8ehfa_WSw zh`aa%_0@Cu@2wW~+@SS%+NbYZxh||}*xrBS`U}aF%iAp9NWWMu?#$X?EBr?DvB2CP zx3}K7%D>hxHE3cYf8NU92?7VC-uFC;d(8VYo1J^Ltabg?3y1bzJ=wc7Kl|^|*o+JN zi=y5v=!lWtZOuE=Zu93GYD}d^Pv7>M;Jn-3<@f5Zm#4Kw3P;8+xco>dPp5*T(NX-c zbNpq6Z~G1=E@S9;^#Ml@|MI`zB`$mYD?Xk0_sFa`ji5}| z9dAx+c}{rz#a)1*;^c`F?M{t>XC$`T9@|y6KD}vCZnN`zevYj#jf*rqTG}2@@86%B z{-E%1H}6d8xEsmelK($V-rX?A?$PV!+`l0+n0a6W#Uzx~grjxQ`-r)RjFKK6ls z_BZB(Z#tH_eVJt#lgG?DNBP=5PhO)l>zXgiJd$+}*%fiM)vPIq<>`iO>G-{!%k+4T zCsl-hP87)9qcq<+c4g+9ZkdTEO0G*9l*?ZIr>wpE`j@hQj=4V9I$C5b_nE)?QoHsT zgVF>$-*2C1ZjPOX8rN>g#Y-lA&u`u-#klA0 zw@$YF*VEZ_rL(M!XSz!Ham}8;#ksgK#`68~%x7)xbC_Rf`R?58cGoUz(;)@kKa(p? zoa(DQs>j~Kury+)Z@;CqjETO-gAaWvQ+>7vwO1Hork-Rt>CO^t&npt?=xEvx@xPS%%@$mYTu~v zDegSZ_xr=1qDg=B&mG?7A2h?sFsuALLvi7abtX^UKF+kf-(=gw5xZrZ`$2z~?~-9w zDNM@T=eW*p*mnMqU_+YLu0=1G^YQt7dZ?7%!T)3_*VD%~ZEJfDDmgbln7heqzq7E{ z?*6wwmsR!rIWoa4+t>eqhwSq5ma6?i4=oP9cv`#BE3&hUH}+!J>C{DSg}3V-m_$`F zxxL~4xxU``)?v}_-JO|b^ZS_18NHHSmq>s8AHE{$*wk*O>b3ps)+gSrEzF-UCi^FE zjyC&@SGK=hvgP%vOKwf^Pn%L;@pk*+(yu#q9y$3ciphL={{zRk_MU|#jlo+Njx>zN`)1GnWb zD>&mW!oim~*SV6%>*|9Ud!Ciet}5P^85Sbl+`3JCb;GH&WDz&hsd-PD*rwZ?bT0Q< zvgbJeSB=)Y_Di}Zns)u-H`~phw#m-4ghP1AiB&=zb_d@^1$4!}w5&6YO!pJJlF{Fg zFX~$K<{)eCmIX_9Fr{xiaolJpJD+OGrLF%me7!H$|6<7qxTSqI%xbg0_k|~+t>PvO zw=VL2QF0U%I{q*E-gN8zQ-9qSKHSc8Og!z5LvQ5M0RPIbEE8WRW**Z%GV^ii&OiJP z^;3A9bAC_SuHpJ~?xONrj|{IdtT$vjv}O4uqwU}C%06wJx+E}X{Y2x-a-SwKoczIk z=j|MA-HC4l_AzZ-c4<#MU*SJTUy;odZXedNdE=NDslb1>%)&%C?Bja3Lra1dYN+e2 zu(>J!Nnp+umv4U-?^}B;?!n~Bpx2EvQr?`*^!4$m(^PQVr8WKIzlVLx%4|wKtMtC) zoK?RudEQz+f5xPnPSdm`PJGkKX4!k2E}9vv2AX8To6^j$FyQ z&>IqxS{R$!HZkRRL3Gx%009l#ZsWJ?VQoV4wudVCemboyUg~71`rW@FVD&`N0^PgY zj;l>L>%d)RcK-3r+kW<@(Z(0VkKF8N*n6`}h&?EA`Tbi#;U^#B8Yu4n6m&6ArK=AG}+cCh^W z(4sZ|fShvjh9{lJ8Y?I6`Ex=qPJDIytC|Z-lybR?uUgq&bk_^8P}6gXzB0|JO~(9E zqvX!7pI+pq%JGW-4tdY$$XdMe``-Ks0#EXTEG=Spe@GM9!MyK=o$F4HdE3SO&VOW* zyAjxK;{AQjq4Qbdvzi39Ufmmz)3euhj>wC`y?MU&x4!R`J}@Ste{b38vt>*;y0<~;*?XHm z=L8DfRnjGdm-&AVkl?+yRPt2vtm8*ty-fOMmVWH?4&hC=<0AhZx}wb$T(fW*^GU`V zCNrKL|5N4oLFw%K$o#~e316-{-2Ztrr*Zr5qnD+pcTJ8vzQRav;lsUI2Y=tT;4g1e zFZmF!dU}bK+d^Y;f6fyNrmmm&@{(0e9@{k)t>@plh5XCYSo7H~FlZK9NwEFi6`l|KE zXV|~*ao&(+a&by$M+t*_LS=ps|FMm7%F2N?xf72?djI?y`2F&2k00!6l{q(V_J8kM zbNb2M2jc5ayByfhW)!;dR`I^@M|Ho>KGA*X&QK!wH>o$GZ&_RZ4nbbUwCCCvCW$`# zI(zA5E~iyfzm%Mq6jSB!LZCIyt#h-EzfPX-mePQB!#`V(PkEfr#LI%mAE-a5@trtfB7=pLb9}|ZN;hv z6^VO?m+t>z6!GSz+!4C)4nhiH}x1Wzo2# zR?@05L+s@vk-z*F-1ko${4#NM#l67n!Y_w?Hcj7kLei&c((B~eS6^)NN_6bspZRO= z9s6Bs7q>=>-pb%U{?Jd>>cpFgCdFP~k9K`4TT;t!ZF1$0UCX?Fzm&ZXX0$dM)rK(5 z@q5DkLbtm-bGq{GiT7;xPS$pPRTyObU7Lfe?fL2_CoS_1F48}q=A-Ou?&zx+d^+;>O#U8bg~i*hMt6HX2uxuP>N{HdS^3+VcK(Kw^y|T2lHw0j-l!}qd7mvg z^H0o^cR}i3zg*w=K_z5k>QoQG5)K!oO8H7AG4b{Hw>`Um&MG0}bN>t*XZacr_W~<< zyB!*uw+~dc8J2w2nq+cb!_ImQhxvtu-gkQxukiG@$#!i#yj7@~Yh^DhXQ`!Zr(x3V zL$BtZuDiA5vvPXA*0qg$(;%xgIJx=4S8qIEzRU;6L?(P zX4LxOXI!6p-C~Uudt|w18^51%%ID0)0u$N&yhUp+2IXx#+!i61mw)fd`(!E8Sv_id zxu(VMVRv35@WHr-#diHM#`U~$-alLghSZO7&nUi(t-YQLNp3JPzE`MFwTFlur zc|W-vPFfvVKWEN{;Q6ye4*N|PH0PO^adhhH6VD7JnwCBZE(yj-O2`)aremXs}J{;pU`SMzM zK~uwBbtn6m9S>vsDeoyPmhfj{*`*nqm*z{PEMT4RwEK2d^Gwwrhn_S(y7<+cBR!{g za^l*fzmL9H_BVa&$Mh_=MCPO)8HZ!ClBa1IJr6jl<6|axvSr;(-`m`m+^RQ*Keo8g z9=PnleE}1zoolCd6nf@pgieopP`_#Sr@4pcGn&tPH$O^5`<=)vb|2l7o1Mkef{Q)x z2Z~SK)3P<4KVW<4$&Ed?FFP+yt#ADJbF*f=Y~rPm?%cK)F6yfF%TyYhkN3LqTD+K_ zAh3%6;Km7A%TqZ2Txk^4=X)T_; zO3zg9-yaV)t#$jK_x|^nh*-{&73_iU{+V8w@t?u(`4s`7$4ig?JIkOM*!Njdhrj#R zBVMgpyIx#!-ShrkhO+SAX)Hz7H;wu3z735&Cp1^!&+~bj{VctU4K{yZW!(|`PUFps z7yY@-EoA}A=QCWfRQ}?-QMZ!UWYU`49UZLJ@6R{7UBCEjwLVAUZlR8qLRVM*-54`> z#-Zi+ZQFz=>fU^HXQ%9p=a2U=nmqc=t?se&#((pi#FKtzGrImBkiAsV`GcJq^wSGC)3vhUKh3MXP7)X>+#9a z_73;SZ~qqCn_Q0Xdi8U{j2A5azn3P&KUmtyEo%0E!+WLA4acsnn{mxr@Y$SI=Sse3 zZA@zZV60iF=HoWC#pqF;qPF|CLw4O;-dFA{R#P}OS5Hr9L+6CQtvp7(X=R(YC5COV zd=teSDQEkpJ^uc-f5}gz+3kNen8&<0!-zg#dw;E$dlGi&W##nG_M59J zr6I&RH~I2Qqrgd%pGiEfiC_1Rd;a#U1&$6y<=b{NM4ixNm|>x_PicqSwTmm{KP~3T zO6cNKezu?`Vb;7BlV!D2l8j6QPxd@>|K}AG+J0C2?k8!snsb{jXH2-0l@_S?PjdRv z7SntGlq%;g)l$zFarjb_yykrQl3HQKm3^J5M$8UeVv4lf#dxe#pp6pIHLmPuLp6`S;H+>6U+8p=xv$W+?ZqM_5zw+*cHNS7T9apN|KVj+@i%E}mM15K%dQp(w zY#UpCcIp9F#U2-h@TwzMiu2R2Nm}!ic}8A7Bo^sxq1pBHjr6MdredpBWG!U3VX|On z-+p*`nd3gjlhGUB?)tIf$1$Ho@$z+IM%*f|=7`oztNVTPT+6zHr*qyf5q(zH^T9#G zDt+d(#=GvfINu-OE;!IEaWZ#bUa$G5&ne9J1gk!_JlwO+v{OC1;i2(C`9gcQW%VXc z8X1>;Un|QWbc$j50;P*3XV!-CGr6)`ow;mW@Kb3m$7AvAy!_p)78dTbU@x8Hq48Tc6pJ{%p7HGIaqA@U*Z1EmcPK1q3cvY!hKQQ_iODA` zHe5>lJK?F(ca>LX_k22#&#Cuw$^)g(EcwjoBKP-wP-{Nu(3c;7U8-A4Y7XD(w>y>X zq)(KkKmM?E;;ci{ubo`cj^tM|w z;w0-~MwMB$6Fuh1eNX-UbEb9JM)`$XpFRmPpD3$n`H<(^*GUJf4JIDyk9l2ti97K@#>yi(CL*6FR?NNqtsy$pbq(j9c~3kX-3(ib z%4_C6Oq6U&FGzdB7gg|0o#XPJxOPrQm5W=PSzpF7%luaQl;okqe?ne(Ma>L{#>)%` zuPi&4GB0vreD;R6#^qo8Izrp$Uei0&V0QcSRG;*B^O`y$4`vGI2m4+NZxwFoG4Iz* zeqsLd(n{W`@+bYj`ThNFDRPKAP21p&LYZrR`|ZZ;3s+Pwo98=kZjzb(;F0OEf151j z{I7+$e%tZk|B@+t(w8aQob=zu*%%({9d`7I=>`3X_o~~UTw3$9z1#8ja*r+RZ^o)K zM=Q>q$2b4xeSxsQ8SVx5T%WBdS2TUs_x^Z?VyBIu;OykPkECy?p1C$5@owJ%mS~Zq zf{&+Gd^sd2@X4x<`EkO3t#jr+FTW{{|^qr<}WZ`}vKJ#sa1{?rhus{;kbP z=jR7(7+s3)@M>8&&0=`gU?r)cww zggjer($wO3EAgn#)2}N1(X-nkcXBF-bh8TyFg2W?H;?CwdVcVPRVQRNUI?rHoA*#A zy7!Y#N6^8n_v?}ZFKc(bx;34lSC}pER@j@sqHR;+!mZ~$>GWRM?s?2uepmMP$bw4k z=86gbc3*s?KB>#dsQvlXOE>l0-`gz^<1c8~d)0pl$KM}}i%a-l9V~WzIyd=e<^R0r zoT_(MwfxUK;9uz9_V%%$uV$dU<~yy0VWlE!KPysgu01Jx$62&&?WNoatFf42!2pE%Q(QlU&Fk%LD)g_We+R6t`|DTFeJHx^E8*-U*!6bW zXGgn_wo$>aV;Jdcph4VW9Zp`2n*E}tz z^!sh_*9`gUrwN}fUf-{(UdW)utEeqGkzaB0-5WLquYPbJJp4lCac;Kwqeo6ln|>y- z<##Wb9&}DkZT7E8V!cI|3LW{5y3w9?265N_iNt zUG>)oO%uZhfgVaSnd_(TpR?4}V9~?HD%N%;`=#~;T9t1xoxM4Hr``-tf?zBh{;_V%!i-gW48(#I_sH)l`q zkbA71x9^?b6^k#YHdN*-WraCN{*SPE_a|zLmH6*V&x@?yGpJ7BT&tiGR#~0tk;ol% zr!s)STX@&2gFE+ceZIb|ZO)BV{kCo@6nTA8J&<+7>|BN;B5CKj zlAh{E+)!^6ySw>+!CKM6@1kL!Py9P(%9M z>pkC(DVDKiQNh}OYkv2;2ljlw)FGC5ecMt7EhcrwCl-2t7jD0)u*iio@!98d=MJuL zc^Pv-f7i^?;~c&%_DPej?!6dtE%%UfuAy%~@9gEj{3FxQJwPMOgY+<|90y9(lsvyd@i?#XIw0*IBe>v zw11L=!?!0@eO+aJO7b`QW#sH{S&{3YnFmF@@A{@HKhR(6R`$x-L$I`2EX>EzRjbL*4sl6_TELdgfI3gtJ~ha@fqha$n!#`FFT46|1+~Lw8@3If6**;T$d#ID=0@jo6j!kOl$c^ z3BQzY9TR48EtougW3AH*x0Z6zfNSSlO->76&bCo{FPv`^x+-$wT#aYH_RO5rA?ot) zQ1`vE`#lnEHA@v9e62}(F!OAE@T$|Id|CAj)m{9W#&Qd#TB_%lrgNvAomwn1?}6SD zHt~X8hBKsQCQHuqzrN2{=1B$P8|%9%K?hcz{FnC2>eybbG-EAx$3;d}8G9%1GLH>B z^T^w?|I6O5XKfmuHvC~+ljpC`^V;&d3VW}*WX3|X@-D*LR;p_Dmz$a~}jw9ghr~dvwN3+tnTYzBgnh=mqs&6}jZ+NHJi#ywx2crYumdXhv_cd*NhEJM%S233hw?~jOGTKdFQcmK3wvDfNFOtXIp zN@%5*)&5^4JUPPVsP4{OUY?@GS6TAd_k5mRe&?U{gAH#TC)(G1WscdHuG(qP&UN(L zgR4yHqQcV_)IV$#V~;B72sqgyy7D~7+H-%oSiTk+G=8{nJyGjcBXh#Pfp9Nv)=G@ z->JN0?vqlhbmNtquI3A;UYyYVAkS38?EK|vr;arSY!{1ta^TseqkmR#^KWunA2xfA z(izXmE5gHa?mD)W#2lO2;=JJ3`_LElEDgCv=!kuR>Ka`k%af`^6KMQj1+%-JDboU|Utok3nHY93I=5^@E+E-!f_iFCf6Fxjl z?l;{of8gK!DD{!wBh$4!8{5?nUhe3$h|!vR;ipfW##5i;8(8_(g?HT-*lyOnw|lbf zq-SsL7Rd4~b6L$8_2hC_;Hk<_vu>>B>|cFlzMN!1A;X7R2juSeeCB4!Q?*v?`dVjM zZFP6rzfYAqE{7x+2=+>uhfmOv$a&VI{95U?y6R&VRt58_zx+l9wtGJxnWJ*S;m-?+ zXlbVyQ}3-h@tNAQSDi}Q5p>qo^>^UB!&0Uz7ISi@r}V9TaJs2W;gVdf`)-dM9^3vp z{}u1!->qTau)I|{`pv>ed-MOf+^EknNd8~6&FYl16^HD6(>?Fs*(_ROer&^x&u*VY zif_botTDcN+|2XzvB-%(T+db3$G+>?;@U7FaK`4`cXwta%~yE;I)uL_p6{deR{pH( z&tI_Up5NHYaH`@(KkLDJ+ZXKeZg0J97Mid4;N$YM-mB+q`t(s!Ainm^(T=z7U#(7b z-m5)vb8Fi~{aa@BTpDRfMS9916?N?Y6@s^1y6U%+SHiUX@uJ8>v28`3&%SW-wM5)f z6W$Z*)$cX)*@2te-SmY1wJe&D`#j~qtS$L`(^V&xho5F)eRu2lj8k0dH_glC(wu$S z9x?DM|K1_GBsx%%_tM(8rMd@J$$XLcWwd&oxa#ZG)=#oh-#I%57r#6eaL%b;Ep_7K zH zx>jewuD(o+CswuLWVW?;g$t*ZdZBT?d|u-lw;6d$%KuK`-&QE+B3Qs7(yVe`ZWq7l z40ZvwnM;E|$1dL(=Pq+_f!w^a+(rhE&HY<@R1~L$p2^d2R8yTAdND6WnorFvtdp~- zvcyYi`J8WeH6G46c3{WLvvZ`Q%s0k3A5pJ5@}JAGN##Z!UFJKY6L*!#+twE-5XE4y=a6U$%q zn|8Y#T>NNq-Ksefvd;?lw|i*;7z zzh8H9>m&<~t(F?kPPs`f>^a~*W$C3FJ!K2^ebWRJbSyYiPBMqQU4HrCs;d$YF3-MM z#W-i4hv1j<@{kR#Qy!4Xby02#ICcG_8 zcQh#0E;)8B{DwBu5@)8@jvsE<#Olm@r}N24xXUFhvn;={_9>Uclzle^13EG+Kd{`p zKkxbPTAn@qAC1L$KZ=O3KRbE*E_Z=FS4>KM#f_gIX4DFLmz5juEV&c+HaSpFi)HIM z(fx1BR{Y|=o*?w((7}Z#n?q+DN$nGpTVB)Re0)6X zMV5KkP(&1Dtq&bzbzm+ax1+fw|Y<{gu}%0iZu0PUy$g5t`{d+HLn zCQLC@SGu&WBx3%o2IbmaC-~-tFE(HFW5vCD)2-RX9MaPs99SiB_f%WO#0Bml5sNKl zUF`g4CKtTAC&+*O>90uXeABj|+8GOaw)IB5Nqlj^YhB*|sZ1N(RaYq{R{Sq}DxY$G zV*LEaf_ro9V=jF6N$HrdGuswQ*zm%-27&r+mLFd)uUBX`&IANMQEoWdg5KJnXlW+5TWH zWXTGC;bD1wf8Fll`z?p1?@yCh87HOjdb?Jx{*KdzoRz0qB81OPk}E%MZ@X@$NruV) zl-YCi?x+@RR6fozq3iXHIa@Sb_nkXrxNq8v`he3eyZ$hjuiA7lw&=QK%MG{o>pSyq z+g1v`xj+={%QE4TWl@UAM4NkE8g4`BCIRpx6*gF(-JkdcPhI+7h2AcS{^LJ z9;15dq4v7!KuICjBv*!n?dI1{da4&X#V**#`)A87?W6B4*RJJHsAjKw&0CYO!bEia zY(>R4Vhq==o|IU)CgkY@`#TqRT--Egvd$hMtsTBDn>?lk#BtZ_GH&Ah!vAOYm+O(bLjP}Dd^jk6J5QzW%`-iJ;ygDlmR+$SMfZ%SowomG-Cy(5 ztQ;Jlu1RhtuAnVQQPqo2go%la#R z?b7FSADZX2Tgtc_w4%h+}^E;6|Fmc z?{Ut{l$IkYZ>}!b*nKs)cb>__RJJ=WF6Jz@Jz#U;%hBDAMKMi^o1CP~zN{|Kb3Oht z>6^RXO%sPW%M*V38S05s+z#-mu)3I3WNvtQ?tAi?<;PDLc&Tqz{CHO@N%-=d!j+9; z#ywwBuJm-4DZV}ZY1fQd5+5)B_f|WjAf&~|F1yI^(j7ss^1G6^zZ~KyK4g0N)^GFf z`Qpy{ZJX!JVRftAmuz%5XHG?<Q5@n-m zI}$F3{ok@Q_D%U8-sD)v>fh%MJ!GB9*k>xI&EhEcKiI^1`>y^|Dmzygc4>M!%PVHo z>{Y0oQ)m3FY{{JXQ%kovt2g`+o^fE~S?}v@=ML9-h^D`-wVAuzS~`Gx;<=(bcW%~N z)E9Q%es%K0J#9~IR!glk*QKr3=RUp6Eu{K%vgx`t6SNhta&CQg`dP^X%hiiB?r@0B zob&Vg+^dIo@&D?}=S;U3y#DVM{~G;3%c(mpr?yuFbooVFygXsYfA3r3pX;B^d29rD zI%hfUEB>DR(EBOx)=%vZvf`sASl+bX@VQ*$>-y8adf%_k(czF+PzX3xk;0T1!lCJy z_L*%L`@uN3e-WN%;wJlW^t7+O89HmzE#~yv=aNa&)kOKS%5RnK`g`?FvZHO!r9W2> zcRXG*IbDKfwX^KMX|iqSH>>VsoKo{SzOPK=z3)ZM+8@`CiGJ0QF8_Y@1(Vepoy-&K zXY0F!g{JL^@L>J2bn_(E{^N@tZL6%k^K?t+F~0L_pLnd_^CdPt^ymX4lO(CP^BH!A zHvAIWyZ@)u-mAtciW@A<4*3en@63K=prFjhJ!#e&cgd^nISuJ=YWHQU8LQm;d^P93 zf}Z0l_2ctz+@4_2s<^EoY=f9^M_LJYq-%V$T@J%Gt@_X?Pb0nRf~ii4rz0;YPWZ3A z|6|*wt~-}GHl%O(ZFA#>P*qr>!YTKF+rpdMR4bWgw_lZAa@MQ4LnTz3_F) z_8Pl0C}%zJXbekd;dgm?B69z?74B@={^h0F?DYM-*#dv> zXzbpb9(HNnhScdhqhGI+39fIseR{|J-^EA1^LOsP!DX4?^6KXkXY&gIC7d1kcjj!W z<6OM({wMh>&*#p~_5Q|}Hs@l%@#*Fq>VbkREf*@vt&2_8*w_W!l;Muce>~Gq-&-|3 z;FEp1z$uZCH49^!dG_3MtKO6IG3epCa`PXCB{f1U4SLOc_xN4jvMFX}{%N(#!b^;Q z>&RFZ`&_!6@yCY$i^WNP^&Ex&!di3YYHd9E{zU1FuL8{rJ9hrz>#TOE3*VMoHu==K z;+rn@!5J%>WRKaumYZQEerJ2)4|}zHdySH0N<`(mggolgV;Bo$KNZ{%-J7YiSL#S! z(bQ=RTIPuz&~WRIElhtu@7mAk#~w!tg{uSBMh8qPjheOP;_CioFVt^vrRy(UQTBf0 zVSATtYz0jcw=OomJ0b8Xad$=YiOl>*G8g7|#Jv&k|GaY7hNJ(hW4wOPFVW>`)ZJCo z!a48lIoaJFo^ib<6FU_)YPo-~EZf|wV-WafRc*^F5Ah@AKlEF4PM8I)VaQd<|8XcF zbr$y&4&O_kZ}+Lk8y^t-vue-f(z%N`yaRY-rqu;q`W@$Cbtviq+l%aZ)h_}K{lf!A zl}*n^aTj(UFm-b2uqs^blQH4)X{Jv$w_hivw>ccPpQ{orb6Hk~vt!BCGm^Jld!&_n zR4-4fw068X*QR_{Va~ti)0@iqa#dEz`KxQDWNr6&lzeMx$J@zU8m-QmMfb(uzV-3k zvTKe)i4mU5@^7eiHy+bibLWWF+{5-pUUJWz3lrzp+eE&6qtg3~&zaF;@?B9KuLoKi z?%vAVEheOFb?L;9Y3X89qT2&kz7?3#v5ob}yGOCFjdHJuL!NFC+YTB-ESGa>aiVXf#IiKJ<(enQw z`%cXUiI>@;ZSs$UU#yyS)T~_g(V^cS_I$?!ZcX3TDdZNN{@Ik}p1?T?mMMulM6ARU z4Vj-knGq-J?=yRO_2l23Gh{7a%{`KE)ogQRf|jCnRjZeeY}U@>^D^?*UGsO(xyAQJ z#>mv-^YOU1Obxxob99yO9X>2|Zd131{kP>RXY2m|fA(B(wwU2u?H>(tMW>CFK5kem z(wKj(+?2fQ7N4<>*!`74&(*w~=eDa)x2}%kiM%=Ur`j*ciA*!gFYFcyova(? zw2$Ha#z&edrOh>eg&da`FK`H{V>I>SFy|HU%?vsA>C4)Pm^{f>JLiPD)b5?b{!{+L zM3x3&_M_R4zB;P>n9?DsEq>ZcM(FpXfCCRtuw?%VIc2c;-+8}|_~&tt+7@&hmEFCp zmcloOxtZtnJxAtrw;J7v>A8{fuI;?OZ}H)y2NWCg7k>6XpU~Z~B=o3F*RtBR(K;uB zBjesSKHSr1sve>G_RFo33ipWT^;#nT70!kfUNTxYwPU_KkD^Hbr>eef9z~b_?J_Ow zI(fCbQu)|H%d#WV-&Qs6|Fl_jb_W#P-x=rFErQQTS&OfB*nGl4;Q4C96UB3E zj<0_w$(Q@h^oiz->9sEF3O?}MHqhO+w(051Ih{_?r<*g5#C!375}tob?3n!Qi?`o~ z&0U)?<4nQqzIW^zQ$)kIJ47zw|4{Qg_v){@-`vW&M-2_D%1f;pA6LA3V?V?0&y)~` zJ3jrt^rw8-6=A!lpH+upL!pyZQ!r!m3YKjLgv}=GIenYs`>ubke77D~ZoK2Kzklj& zMx|LdT=o3qzj+iUB(lA$UUg}Kr6|kHZwAjc3nq7aSlYPBw0@Z@sdKrsWV#Sv=oU_{ z%{P=xbIP^UUEb8i>ddd(>{G*KTWIk0V*C6TcA5bneoWuOzjs@Dv!0{AaC{@vw_us; z0=E*qqSLeAn19{8_kn=BZ9jO&f3cuojZ+^cWq-#?L2r@>>laP{duuOt+dEBAUX z_%wY>f~UfSBXaIN4@)RhCgoq9{eG;Lvy?u8AH z*KJvLw^Niwo^N_VVAJ1LBR#iYe|PR%YA3n!yt?^p{n;~|?WXQ)U+a6!?A8PUo;$g0 zVsmdCI<(muOqYb(jA)+q70+*1o+Ddh9>8{+!-6Yj&O4+y$4iD_))d zWcgd*r&Q4Vy#G%x%$e*WGwp~l!^X6tO*~7S_I-q_kIu8Kj;4XVy$i`;SSjo^NxACwyd3_spB!%{f>Zjg{`csdee73ceD5= z|LVp+9}C!1I^W%_5YtjZzSHAT71>Pw!r z;MNa?OuDnymYja|qO{6UX2ZN+E-aIlJFQj`3E0LiS zxKSvVZ~y+>%INF*d~%y(Ev$=wm%s7jz80kNZ@b!_t7|rBJUDl>yfdKBKDv?Tz}t(i z<)Rl8Ogz|K&b+DNW_PN;tST}4V`X-Fz5QdR$TOUuU&Qe^2sLe-oAI?NZzg@~^4?Isn|*G}NvE5F45BHa z*DRQy*H{0`O1G|ZHtark+3d%*qZ)HQ3%A_WPR%I)xL|YP8pjXv$6tT7-@fIIzpT>) zPv@u10ZbYKtNCue-L5D9UAc%h zQ+UPOi=T=W1q)WxEqfNR)uWzk{u~}fASp21F&YHYCTSEB%CeH1+!2196 z{I<{=u}h{ex>!^?Z`Lm33%YxZ3TlPe=5)*u$?5#scwuwy*Au*M$EW;!ss8S)?uFdB zmU6MImoCMKgjqG!+3{L`T(aLK(f#I>Gd+!49x;}bxo0=X%@hhdE*p1fz4!53ern(B zZ?C?lH&-I~h-W*mujaz9~np+B+k9y06~lY16f)W%?YyU4N{_f8AG? zSHE7r*86X;;h_BNuhY-{e$y#dGrxEejxo+N@!}dQ4XYRQ%`N-ju zp0}QUpLxd2@B50BawhAhxJ4o}-s!(Qy6@JiPHgWmhsMu5?-2xPNC!z4}tI^fPNx0>wWV{dD+uW5N-A@vHl8Np|N~i^_ve zViS|@?l)l%VSY4o?j#$J6MGJoWmVsgww4uMxO{pWuajqG=I_m%SA0L*TC=O`xBkK> zY;NC_r+nWlTP|})A+nG0srxR;i*oaAb%nO8wG`Xmz3k^=^JMwJ37s7ye_KJ+mezK z=@zkDGi%!%qevF#!1;T__Dw%8yZrCYj_Fq>8Ytbpc5+&PWKH0$cR!6?%z7g4n%&;E zK%j2p8tdOJo<@CgAGSN+Sm@v^s+-rqdHLMd3prJDi}y3+zAfEYu_Ho;r9XTMtIx&X zb_D@uMv)E?58u3WGMg7tE|YLy`{c~pNs7O2T#A;|*|Fc@;)9m8(>-UD-d~ygcT-iT z?zH&#|2GyY&e$FI>`-0kcG>=9GociLht*8Irfkd1?BnX+GaUauKfXbNTdjIaQ;b^P zR`c3BUN4cNz~4@2Rq*My?yl5Kgf2E>fw*`3Y`yZjJ+o^)9giFt=jc|m(x8Q zN-q6%`3~+gmlxW+n0JshT=Q|6&!gYATOZFf{PlhNS%*p2cO9PcB5$^{a9fktym_~O zHC?N^qMcrRFl+l2C55d&lCJsuQut-a5KwhlN9bteTkmCe_5`xrydxZu?K0`7=Cf%p z-Wq@8o5O9p%Y|p+^4;Zoltd<7IDKb{*ZawSwGVoI4EIK#e0#-9?E-7StrX3izsvq4 zwz}nCDLcWNo|_iFWY`Jx&MTkXu>62+z=F?f7tN}<6@T08$7jU~)rHPSCnsNAbaPX;&37?- z0|W1kq6dF_KehZLEA_8VZBM_NI$Kg{w85XHTlW9UUw7T9piV({dsB?O<<%;Ie~ecS zvp3A0CMj2NW7?cQ`P#y|UR67`?0xlZH;YiT@U*+%OnjA}SZ#A?y*SV03R}oF-}P^% zn|g8OEw2^SXV`i_k9+fh+u~pO4RcTZaJkVUm(JhSA-IO4@uGpK{kOxO>NmyxTxOl$ zB+7RDV?p6kqr&5Q`EhU8s{FA25jkJRlX&zy}UayAUMcqvg`kcY8(EY;t1B^kQaFH ze!=WHj@bv>-TallxOK=Nn8Dm%T`-&b?kFbMy}|9l9bZgyof)Z(QM8s z>)t)we0$N+g|k;Ly!xHJz~6&0^^RPLM5D|E#EYDWLXxlsbWzrUW_YZ`57^tRxa&BFIO zg|}~8CNpqyRr6H{s!7c^XXCw}JhDoP9a0=NCB+x5KJoqbx^VK!#kN{aFXewK@i(u5zc}OKSG^wHl6C>!w~ki`Pv8xyHYl~&dB42KCg*?c zuT<-gXXe~XG5zpdRI*F8qV<$+tefPENu1G@ie8UBCm)-{al8|+V^zVEcM0dz)j;{y>_nkEq`U+uQ>k1@TP9f)uoFW>SA@| z<(2n(=$?>#zW#TPM2&9@V~OmZ$QJnov6-AdJ?D#eKmO1Z!tu>&i-6U09Y5BD1x-&6 z-!jzO_SIuI+wq0=XU*^2e0lY_S99}@Zl-x=Q8%=%a@h!kZj+xJxOJi7Y6p$O*>|@u zudeDT$X}-;8!=Ju@{%_vBz_u;TzTfI%V&IvZ?;L*`r|kF`vd3Rb}?Ji#9|(P+syb^ zUT;V1+S}@fIQ)+&+_+Sp`tR`i$ilsPgf6Usvcj@9)rJ!$O|*J4b3km>Jyo&Q|_F*6Itd1yV{&*=zj25d~xug;Hm7i zs%<~6J2t!un7w&trSuwsv+6b7somZewk`hiwDQcJiHpPca{YLnQX+k5_0zU+n;$Eh zi_%%X9Z_-WIv?$kKkw4CBcGDWFTC-6Sg^@aPoPuWrSkDn#y#nJM|WM!KNl9=zVh3R zX?g4Sdl;3y`?pJCTD4eB*Up~DIOO=(J2b<=+43Yai`#`$Nq*Sl3eq?!PO=|8TwU*qo& zd?o!vzw3HQkcH%~Ime{3&irk=;S{C(cpgWv-PG%Izg|w3Sz%}VHuM@RyJKXl)a6nx zg?FiY`vkY@?uwF;d0V>C&R;$%v`Jyr|0?;j)0P~Gcoy8pbVf+W#d7DHmG@2kt{?sN z(m6RVv(+_g#;x}Ht8?-WG?brPxbaT)^FQ+pCb;dW&-ms%P54*9D~&^fi*IDunLOOx zyj5*}!)D!px#cH6z0JRNTzkq>o7)R+<=xPD+q^37E{g_#=PJEU&0WhopY&bV4o{jk z-Pf$X?1}U*0fQeQnF5u+(oUG%Iu-bM=H5{ApbUu;p+7%GD&4iKU+k^9THL&YWo2vb z&0UN!3VCd@6C=*-3G81W&^))P!O47G5BjuY+6tA0FQ`m`@ar2b5g{~Z>mZI2tIy}7hp z8_$*h-hX+*oGDd1drNMoHE~E+%!_+g_wsB1w$0~Q#CQ!JcfB~Hc1l<(?90LJdc1p7 zXERPO@mMEblKxR?183WYB?YSM?{utH@>7gC;Sj$>&~s9l`>s=6%4PQ(*B-mSui0z= zwKA=;S(9oS8aHtG%-H+xNZGGt$F|J8tQBza=a(hMRf!(II%~EqchqG&-s=3)i7m~KKrvNLWW|m4?((ZG4LjTRX!hH>x77AE_H(W zZx-uxKDha0d->)o4tLx`J0nw${Mi%nwta^8vPmyyT==bg=Y!;gwSPQyqS`p3cc_|6 z9ktN9J)M8qt8;e3#WT5rtlBtsUq70+WvkmQr{__ za-XL?m|$tN@u<>??(<)NScG~gEq{A^u4Ub&2uZltWys;PrY3zUuiwb+B9gP zQ-#ivl*{Wp)TO!px_?%fdo)DHx%GyV=9TT=8hv+j|7N{$*L{EB!+Xr>C+GMxuxKq= ze7Jq8sI`AH--B0Sk-s*aSlo7VU&(?v9V;2}u#ykg80MyCDwOX!v`MI@_PR!pwD_ki zX7Pg3&YmSp53*H>maUL~rO3$BCB(Qs?B8wiJ@IyIWt)W-`AllqZ{suf&1W$gZ5y8h zIujp%$=rPOLdu+^mg;==l@_~KygeeK78mnP<)fa#`wt4$H`z*ro)*Vk&e#;akxg@7 zZiube;sqZTKf83nZn|77+B z9kb+KXx{w2H~lo1qv}eVq74N_joX>HjU?vrG9OeLr&ytVe@-Ji>J4c#ZLGTdF< zTqpHni{9P~o3mI~*XT?-*|gwa`nMZqLQ67Ew`4jSdEaD8x^vsZW7n_F_uH4u|Lelz z%vR|e@#Xllg$qvw-Cv%cW~9}zh|}cx`>6ZVf3r*XFr8jkS$hBRkEW$p#MVbm`16~e z-BWA{HLWV9u0q13(d@;e9C z?h>Bc^7(JiPq(Z|IoHfog|659U9?w>b7Sh2zcG52XO122a$4rUU#Rcp^=q-s!F?Bn zSdP9q{7WNHZH|zTc0BvT#aAaEu(hs_N^M?pd#S|&bq1~8*Bt?7zB6LZc0JlLU`&kqF50g5N3+#Wqv6IhhS>_Cl<2jOj8~3j(6Ip7ww>RsQ$ewBcz7=vL zRJPsS^_9u>XTi40+b=I||6RMa-l2T;RQX*D-oNh&U6uK5YI#;~>HZ1pUi7`uw}}6! zZxPO?&&izDGy8G-jj#Nchc-CgaaO((tG(pYq)&%CUUc4hn)LHB@3KGB7tHXi$=z7p zY~^^}Zv&UpeQ8Dm_A`l#HBPPC11ehD`kFinuL*w1u;bv>c+|uuu{8Jf%!otVid-eK z9xn~G+&A&1S0tl~zTzfxR!i3GjHG(j{P3ugaw@NxWW(pFs@~l4e2Vu189_~zX(i>7 z;SB$IHG`#2ubrjp-X&CK_^PV&M($1Pqh~uJ-OcCiJu_3!_lxNjm!*f(Z(As^%1_*v zyZ^!J<5NFNHrWM;OkU*}ZJ!e-tmc19U)=EW`R>M*sxJgKbiQ2rOY&jDYKDg`vnH>% zK5tu{bjz$IC17j$d7A~c$&eqXN#OvR(Pc_N= zP28SVzB`vLkkNV}`L*4&g`1LHb}f4Pz|T4LMiNW)s>$Ic3AQuVm#SR#->=h|`{U=) z!0n~y_nUE9|31CwmT36_N4YOd2VQOLUphVBY<^bi5|;qphiunnSDQTDlGhdL9P-qe zf%VO{6WpS50k-ef)MQ6ZJe7Vzc+%FkU5Cvitb3K5Z5kcU@vFP3Xui_1k(P*AJ9pmV zxj83{G?F}y<%*w~{+W^U@v=|s3f^TL*-uWcEjw;k+V32*h0SdGq(qBqsun>p3z*uFN?YlXg_o`{`Tz_@YZ{X)eVYbJ0``2R^{ zY4Jm@IYOyV9a6sk@A;cK?Tf{vEuH`VhkeXbc$^^jZU4q=?q?Pn99qr!{`T^`@Q}0% zo`)A`X&t^(Icbh^#Ycl+zJI6A?EAQAx$4X5H?(>>X z#esJ@u6(n|;i|mR@@2!66#FHo%T=^hw4L1(T<@+7b-pM5Vdk#eVFxd7HCnmwuEO)* z4P2*L_ip~YJV58x%=YS+1&rm>)lZ}=z0&u&bt^}yQ1OaQ>4(3M_Amu{*Q{}g-8VU{ z;l_nXmP>~F+H}su7F=`*7Vn=Mc4(~)pAoA&pZ=0N`=^H$XN<~;i1Fwfk{v9q-?Vu9QDoR}Gmy_|1D zw=sonJ+GQq_+LIYv?Wo=g>Ws&xBn( zmYD8m-gD8fNJ@ySX-~4Q;I7Dz`scNG@A4 z9PxE)_Rbf3QDX95?1gNR%G&h_-2J*~OMLD~x_+oj{JA{xZroDgm+sROxqpa7xjwuy zrSqgo;pLYZlh<50{AkOL?x+Qo$?x*)OLJaw+iLb z#nL*g+iz=L+n6eGKG18|rm!~!UA|A1>Vm6ftbT;GXf4by;1gYYfG5Dk@XX1#Us7Le zH_3l$p>+E6A@`b1ZR$tVmA9OgT^ev;--NSntO~XIf&sU8n@juLUDv(ry8bK1W&2~a zZcL~y+flJ}it>*c{p`x^$xGterBhrVa-Ytev2C_2=Q)KrvY}I$O)4S;A6gpd>U?H= zQ#A3ObJK~-%3;U!q$;%ZMEH67Ua)bT;<~Lp=afiFvq?)$+>+e5Ii43T@=xX1ko5Wb z;|uXlyF#|izn{zdOr?eY)R~%^(?xT=MSm7g&^USXsSD$Yglz&7I1-uP+&6m6walbl zs6YQCXEFDVg>$yAUX^@mdiUwsu001brA7a!)w{i{6PjpcY;)}8oO@rBTAUPi&Gl31 zRSx^`#*$-C&p`>ZJo(5Oy)BW4tky42T#$RI&T_J4?pRD5evl);Nv#`D&P>91GQ zw*AY^v9dqT^H#SX(?%nK12+oy{MxCub8$tj>_(k(?(o!qmnI4sJX;vZA^xJIWpau8 z)*svojso?Qqi3;%v+L6D}Tb>AW-Jt8Cr99^I3NAH6=jBi-snl_FAL6Xx^UQiW8w~YvQ8i`rkLmwrHlkWH@nn z{h79%CUt46!t3hJeu|$UtMz1SOZ+Bg-;d8T|9&!I@e|%Tz31>HaYf4qhL#T|AKB*h zWSx)AvI99g)^`52(VeFK<^03N>%?|ndAe1t?7o7%)0&na&O0?uggE|HH?wM4T~qJ* z?zeygv z`D4rbnChM*Y~LJ=-`q!u|#)n4}qH6?}a2vf!TYwO4G_r)-=bw(7w1~)Qttj5V zJW@pRi20UI2ixEE5?3xBuh4JJcNJ1!R4G#JI{${q4oi`Dzg$u-H2>9pFPZS8N%4{5 z)wH~SsRu<`7n*%|;oluDmC^wW`*10p15~@^PKA#d0_6$dNIzg0qt%VrnuVdUl-JO zYxioi3l{^v=)YR>W`(I)fh<3V#*d@=c{!HNJe9{EigAb)x;7X+>gg%DWEc7MBwHN+ zfsYKg%2?0LpB@~y_}TVvbssG^9kKo8#n_eb@xuyf;htL7l2r!V3fn9mg_~EEGkIQ| z_N9H}p1%ce`3-ljh!^6DkJxE<;~dxYr3|m4*Y*lpwS^TbtAE`~Afm79LyHzv-*?dV31hdi zVN#3jJoi+%^V?*pd!;4wcWr&V*65z#&yxo~G@dIvtWcGzPQ{(7x%SJ3BO~u z^n6%3X`<5IX&wQqx?}Y?w+MY+Y~n$sLmx z)Nu03E;2fF{_r~Gm6~2QK6|r{PmuPRaF=(fS58ap?T>|1g^&DS+4}hGIzP82mG!UR)O&dU7RC?LbQ>7|9kA|Qa85v$ zVeXdRq6M=nZrj>Fp4)k>w6p8Lsj86Tb4FU5EL`489y+C@aU%I;R>zb!_S&4++9{1@ zDT@wH^SE{}Y*LQK#FIKqf-(HTA^F$tr`~_`qo@4q;=Q699TpaA z*mi4chr{7MrTHJTtghPcnewzMs$>7VBOxqH%#3UIN4k6|PW^i$|ANWka}#f0GF|Op zv+G!Ntli0{_HGJY8V$#Ge|jGNG@1MPx_Y022}@@x7atO~`w_j?dh=!0wSS|OW%``? z+*YiZcjd&y_viX9s9J4Y!ZX9|wn?|gz1Tm6p)skkA^#YnbdUXMcbyr#aJ}8h97&Z! zOMV`UD1V?*tGiwD$){%-Jazj8CUVc2ng9IJ|BD%Sdfh%YF}5B5_C))pMDL=jYCHNb z9ew^a&1IF5M`Qi2wAb-(6BpXn+`hT(l|h&4@l9>JgjcRK{cwOYAT@k0>r3Iy<=>=> zCks1!BygJXrFFxqv( zv!(u*r_ApBy#9jW@8#3^BU73`7M^)^`FWs4xwiFk#mJId(t;dYPR@`2nwWEI{bBtU zml?HR&O6RDKi>Dkx`0X5_A9F*%R9@R!QwOCJ`B9_RBy&hURgkVH)0ZonQ(0>Mm~}LLZJyoSvuV3alO?;E#g3Y_G83J)n7eRZO7nQCrT(J$ z`-fB~z9U^GRn2xUlizWi)II;T`qpmGVuKTwNA7=j}-2#iHNL80`^ZOUj1=zQ;(vd0?j=Vtt`N0nb$J^VQ!*KOvz8sd{Kk7BGcCl7sdZ|RZr{9~nAxFK ztzwQYh~A>Zj|2#HXQZdb#+5cthd+}E)#xb7S0e74HJ9daQ z2rqhL@@Iv}qK~$+U<5z)#1+Mn}Mf^qu6nG}VtrA)$@5r&h2~AspI+M znfPC20bhZW(1be^7J5EoxHfY}lKupPOOqG5KAAjyM!)p(W2Y~_*`pvMtj<)~S=q+! zcqis!nXpcK;H#4wd(Ey_-n>&^AGJe9RbtJdsM#!mF3(HDo#vkkI8qz;G9h7-%$(pS z`}W!H691ik?euvui#Z35S+dQtUZ5e!nWQw${^HKVdry1rQ$Da@`|qGH7Pa5x1KcAFs9@PcIkBF*58mjn4-kG^2JfNxB{Cm47VFtZ_knY&HPv8 zUPJrdUm6QLU$E@>WS!G$`5scC6~zJh_TDY0q@MZGYO^Ba-~$6nd9d~hy<=+s zqw>-P?m?m3kMHA~*mP3q{XVykV+_Ni|y5Sov~Zujq>)=M+u5067rEuSKLk<_Yb@L zw9nIuZa zX^$RUe{--s&UnJ|V@*zCMf+~%)_!>S(T_{&%$fU1Bb6(y7pGj_JJoBBcF!+C89g8K`a36XPI(eyzf00(;as`jZ_|bU^LVAG zgH~s4JlUh%ykP0RU)&KFy0YKAn0Pukw)5uA{eky1XM70F)SDvs>Sw-8@(xGCROypH z=fzySF)_TwOL_kDy8Ty+Ijs%$2n%le(KAyZ$l}^UO{Y7R!6$NA1Ov;LRv!8JSCRF^ zzmNs)7EzmX4Apf_l590zzDsW0prf5Ey75x*hltmA6Z4$*JyB_j+I;un>P>D|>oyl; z?Oina>AEHxNsjr}53VIl&T3NER%wX)R@kG>EG8Zy8vfp(AZE$;^9BZw6LmsPUwy;% zy2$tXvZigZr*p#jS8y|DM3vvqH~HKX@WJq3os`qnsP{GIGnTM=nJb>UEy&f#@+~J& zjOR7?V}0F?TbV?wE#$@XJnM8mc%)?hYgzH`iNo*nH{u=hBmOKkjqQ%CtF}D%{J=ch zfV{2z(>^n6vNU|@o4C}i-I}{%p7*asSr;XZgtHB0MPK(!Z@;{<|eRa-eu^5(<4Z8RH zmf64Fc=y~BhQ~8qexLJvzqO)Gg5gnT^WNXb4zN$C;nbIM7ZNUKsa5TFm?Y5t2 zFm0mjg6p4+B=^kusA0&rZTj(pe_lRydc8tLuk5FGvz}S_7YF9WjqQCC%HE&WY-n8& zTkv(}7uN-kv>VP`Gf_&=#nvBZgj8<`YJu^~$vFeKMuP(05 z8=1r=o|^UFsZS-2?VG>9f0(@4!vCjUyNE5A*l0UN$tLEGaPEWxX2IfXs#7+XJIgjy zURJqgeQYnY-JR{)mpdF(lZ$6*M&&7<# zbd5(t^XkG~@k}%3HNP=B(4XzlGP#aLuyx<%N6z04dCt^7-Ex3I<>C*yb5Z-ZoIbI) z8xPijiFpKB^*CR z{5t5CZJs3Te81Cb|As%?^x4Z;b_zP(o_u}FroT>mOgS34&U;ww-lfOioSDea!Yx_* z+_d4vp`P{f_gU^UXdeEsHA?$|>WulDde$w%_Ar z(n()0bo}#X?rrC*8#$(axjb{m!|)A-l5VwAt76nYmFN|zq{_%zp8elB<%+hXH~_{yTB4ZGWxoA~|B*#FY~Vr9ruafQ0VKa+R5X`H&h)S@iT zTz*HhT-mF2&DUkuAJJv0;99+WPxrZrI*zk6b{J<^FBk4xqIh0j(f!Qv(_4$ys(WtP ze5h^772O-hB7N4qd*FBWVRu`R-%eMHM|PoRe~QWtPpOBBT5b&ed%K(Qf@#v`qn_{E zjdWTUt(H?h_x#^B=~wr6FBiNQ=2Cs(TV3Rd;O`8NAHCkXb6HZN(uLL=cb^6Bc3QpX zio*}1tft88`IQ=CpK$eT!}mzmt&6nV0J(Oa(_%?B28%$6UX6FKDmexNYWt=TZV{&b;h?kL#eRtoEiqswe7<-UW&s4i}Pbb~$6z zy8Nfg(gVMa@7!{`E@$(+{@tH{8}u>nQ%+n_DI##DGKOKH%-P)I2Y8k${d#0G`(w@S zs_Xw2%}QU@t7h_khR7nPghLqzt+qB#+f;aQQ4LS~Wtp%|ig3*MMC zu0MYFsY{EEmIULzYaG$J{TG#v%3f{xC%MbM%Gl zip9YnzD)SG*Lj|W&)=2bjOGPREY$ui^uqj1)E~pD4~#BHlpD*I2uJSYijdOUE&S2$ zd&$|@;CpgyT!;2a1-WO1rauc_HYqPwBLCOnPYuT|JfFh&TUm?s&_(%4ogY>|p5Dy! zq)gcN9)CvU+Fv()Mf09aiVvCN)hEpAzhL)liAo!ekc&MPS?YqKA6~7JVch#^)|B*Z zc}8pt6z5rOuz2^?Y2GF)pQ5R2tYdft_ANSiwlGg<{f;v(3YS}^e|FjVyLzF@hUU|C zm0zso8lsLk@m0vx&RoE;<;Z#FOLgy;H)Jl0UOt)S*YSR_W6nFe?!>4&viK}H7WU!f zlQVK+hqKaS4;8N6lQZ$`ihEpZ4~s2L?iX0F>GR99yS6e?Vp6I5T&iB>x$S*xo_4Zg zwo~^@zg0(rn37mD6LhVww(OGHr@>v;cW+*PnZCG^t=*fuP8nyvm@{kW&Nz{D^YLuy z0^6=#98%vyHdI2o~R>lN&q&Cch?mt`_FsdLn*L?eeTg zDmxQO=0%8Rd#SeMn*HyYeEh-u%&j-poA2J1FB>V=bFk&qnaxXf1sy7!a=7F4ZS$ux zhSAfHeO{P8cFXv+L=i0RYnM@9AbXMK}89%@MY;LR+4YvQ9h50Y~i2U?P44-=ROq(YQm+BlRvG+~I5}W*#t~9sn$`L*L{HLM2wZl!w_4`?TuxkJQEgNI&!>&`O*EYNud^h9aOuvE~>5<+pwbV zu9y+`^(B+DkAUp()bub1P6fT>rsuDn`me{Od|qp#4_huuQUxKDR&cs;Xz zW#_Bb+q`y@QfoCP9tjhkx?*BTK+zGqzubxITUI&$vbu5Y+c|Si9|vb&W;d1%)-B$* zS4QN-=sMr@*}*lP{g>{vInQ_Bo$(|^baGJsb4z2Z^Z(~gwlmrEIk;@KrNx2|drhNW z?XP%kc`qd)Ed24*TPLcw*dOYAZIQ*OI^p=F^bdmW&*fwd%H8Jfm%F|`OG)*Li>k-d zy^opF?Ykmg1nu)NVDnk@|dKZ-_uax~u)Qj;L@ z)T;K}e7741mY#2rVmiy@<&pU=mtD61!gW92cV_c1QTw>__#FuWjn6zyi*m~4H!qUQx8pp+BmKxiYxjd!^K=*k4WkEMClzc(3C57#_Te{$!?E*2(x)r!?j=jGxq|K)2kI(n_& zVgAHFbqT%}RDH48=BTva zo8yl^$tpUgYbW35_z?&u`cDJJ(sK3K@TVac}MH zsmf=vn)Z}lzs<{~@`m~CGe$-$`Rng@&ShoOW%Ih2YqVl_2m66}`!!ut_scF$*i^Mr zdS3tHhJF4$3zC(#i7wdv_zh$B2lh>JoBHNI5eQits%B>pQe5fRqZSuou9`9-lJ8wb zB0J-irXP~~rAoBcT219%9j#?i3!=UL|jRSS#x7uCp6{bSoTC|7q9i+z^n*pX}+U zv$rFxKux?UEarxGS&y`r_N?bh9?K#u=A3lieR8u_8fWPrjfA^JbIs<>n=)@Jt2}c- z(gp7HJ4L^Yw_TPK%fGkQ$M*$?GM~L}b&$Zh%`M*(f^D|X*6Im3ae7PP^Vw4?gy%VO zZ;)r@49;7Z)~0Imapr?do_aRQPgr;p+un$$+aGypcxO%bM<%8zOH=&L885xAkScUO zcn9}u6-TR7xBCNsbVj9` zyn6JAXZh?IrZ&2#*i<=JZVvUY6}o(K?~C`r?~WDq1s;62a~Gq=w<#xBZ|0xqj-9Ue z{9~ZKU8#EKMJ-p2n0(U!<+2ct;8)gvuis-hsc%%`6Z^+x*};uv&dVk!+ueO4Xdl0} z-JF0GG+*LWCe|nnzd(%rx{8wva99r>JX6c=;e7!4!j~r;tPS5did?oY2 zQ)$KB-LoadQjBxSH!O<@u7u$HA>KAYkUdn7&hf=fYeV6TY7;+Av*SNt2l)oZI`d`oUEX-(EJ` za`J6}*1ekR53AHwH$M3EI_#@NkKbRxZ%W;_c(a!s5EhVQ*i{(A^tGrw+A+NF_>;)W zs)Yy4-`t42@%2Gk&bKt5;()pa#wqE0T~%(seId1jdC38x+lA9Ui76|#P4Iihvo8IT zy2^WAU2G4d<(7ZJnkYrkJZ$JV&te$%Mq_^~a5l-L{a;-t??{ zQK`rILtQFK`rqbu-Cp|e-G_&qz_H8G8+cc$KMZdh)<`{hY>RPZ8$YXMFz7Hw`);#0r9VT@4v z`0NqaVczyb3hEluZK6-Nd3A9sq=d88XL;`4|L~%&(2u&UMZYh4Y?#V#DVCJ^I^==J zWGAmbGw$b@On!OUc(PO6Job}2&V{nM%}Lq3Lgs^5#7CZQNzL~RE8cRIv#yN_o^j_e z@2#v$-!E-_Fe&}J?b*o4zPKI6w^{!P%JuAG$(XXvXLZ3!1?I)`Hu&tyGVm1aHn=Qk z%~o#E=TO!2mRTb8{&Eh(E}lOZKg-qx)cshkG0FP(9zrv-FhYZ)r7#m+EWy2ISg$7YS^+jiZRxtp^)mOrTx_-j_)cD_IEuHU5Z zhnE;hwF=&1O?~e?labvdXV>y;bM@VF%<_779F=V~vRgKNx3ypsYxbRUu10Bl%~K=! zQty4$pI)@-iBRX`z=g{FyJwp%xFfu={>jHM^#@ZoUkI4MrWGY3db0o28NU1pa}2^~ zy!~>1Pq5S5bxa43T@YE2#;b6^>%>X7IO*uZlUDa$|4e>&^R{u_rBgEte$QwQX=7V& zQhkG$yY)9CQ{nMvb^bR3FCAvsl4QB$~l(NM6Sn-iY>AphBdP@AGD>9z0V`|1sT?&!FD znXSrmt90nU;>y4C-c`-bKlZ}GQSni>3&-lqksqEg`g6;e?5un~cgk*ALH+Zo0lWGq zD|DaS-gU`Lt2uYg38N{M=JkO_@rn;`?Dp7Qxha6RRsPAPM~MrI%`a^EJjeCikxR3B zWF3PIIObf`vyzP75qmY@m&!$-5C4$J0%KQUg&x79dU}%Px>pq{GRd(k#!f=rU=w& z_Xvsen!CLT4J;857wq|Ab?~O|cdN`N=T}YgubjJPL5bq>mb`si9{wq^wtxA>)jcZD z;Q-eJV}s*ew|#1#Gu@ZI;t;{@xB5)uev8->Wz2CV+wSbu%DyqdjF-#fuXRsv^3Hhc zC#nJ>?V10Sp1FwH&HWQNY0-3_$yxkr3KHD%_Q%tYrR|eUxf!|e!HXrGXSGsNn^ae= z)H(lYTcF%3l^wkP6InC(m zs%?J7tQALhXG}cd)4=@C)bzc{_Pnc>MjdNn+F#mB@0S$dm3sI&^J&+v)~gbj<1^y=MW-JZbKt}tce{a;rz z=5WSoM6&cf|F!+~+fN1}^SXAvzJ2VZ+%lWBOpj-8d9~xN zc|*8)7t`{|pA?oo2uV%a`%yFh$AWA6@3})_KeVqnUSxl7P3*ljng!xJ1s)yS*XDL6 zaAw+VzuOltw(>mc?6$OwU37eqoHAa@7V8@rhG|UrDWH`7tAf{iWZ}HOKti7(M3RwRn5|hT@&H+Q|o%xMwl8 zJzg;9Vx!EB0}A`!C?EN^li~6ym)9?yyS)AzJ;^9I(VS!E!Pk3_wRxvg{zUIZ>Kkr} zssCB17&7y7CZD6n$+PDwvN}Bb3=i+kHJBqDBAleDSn+#muOg3NcWcV`^4^WE}R>EKKlSR_?p27MyeZ#a~;` zn^T%1VxEfp-nsvG?s35l-FaPosj3b_#;n_q@cGC5F8?5zqm{Gf$0b|2WY@Gy+u0f> zENI;MB_P82)+P2eijI0K47Nv1S28QS$lvn(`1U=!tsk0pI&vL~n?5_xD=72e$3ruc z#8r2hR88FMTlviW^UQZYv~Q^075UkCxAK`l%hTW7d-bh%*|6TaUGMskv7Iw3#rNCy zB?sHI8d^ewyvtqK_)?gCO_(J6?WCoitNnR>$LLM>@(c0r8Mn!NDop)YSTRNa2h%gr zyA}O?%!~_EICxYdd%keIO%lE{IbyO$@Is}wo7dRFrWN=X$6Vg|bDs0h0Q-M;mdu^I zr!m`nX=78@b;j$bUQTvZC|Z8uOMYjx#>uW5s}ig}M{lZId-~#u4QJoFH-3CpsLXtR zcH+?s(>0aUy$&SnF8aG>=if{J|0_CGIbB$KdAoeUyGwfvY6Z34YdY_Von|Q+wQ9$M z3+wkxEJ^gZ9dEbcepA)lZ95xf&&*tQI7_TV<)ZA>O&+TyK1_+9DP!Aj{dsEF6bCPZ z-C{N8O|333DENBCMvJFiVTC`>wkZ3Cb)Vje>PkLqkT))5I(ysq_`XFsI}2>*%JuWU zUfT5YLDcu|w9w~oGu(Eu&uit`S$2GC=N!#0o0)Hl-;1t{{2-n#AUNN>_)UGs8a<0| zE3F(a?T=M@BHSw@pZRjt-VJK0d0l%av+u9veDdCJ{Ta8!kC98oyN=6G?rBqUc=R~t z@7p(Q+m3qhpX8l*e(}$|eNuM&9OnEq-o3}OZ4=YlgEP`U^>a??a12(Qr96Lm>fT-7 zlk2ig+0P#Pz_6b2=msX`M|EM>*LrgC#W|ltPQ2aXMl`rwH{_j?I6?TMW-(~Qk@(cd+Mid ze%%Dtnn^kS+k(CsRv(#owae?!;>S`#p*yx2c)n$Q+poPsdO)AtGn;_w1)xS+_}vg^Sh7F^4aB?9pKmAVW;1v{N?ti6vqPby|>Rx2u#e# zkiPf#PsBtCIinqJ-M<3zE*`k|E8k{H!L*I@G~Yi|@|(>%*)NTEQBzTNqO3<_wT9OakRL1#hV+8Ed4gEc)(-3oH6_i%ljoRF;&j5-~Zfp zMBt{>f(VV<{$0EK7B&irys}t#Ng!{9lwxqhiomLeQZ<%cE1I*LJXZSEU9)LiS5Z0RuCj^XpM{BT?=4qx%nIv%X~$oepla!NbMD!M z=R4fr_V0SwdPA|J!RF^gn;DnhRp+=ac^_$GdTH*$62BbPB%Pmsdcq4XS@jv%Uo*6= znx~<7x4DGL`j7WLlVY9#&ahO!vR|B&80sQ_N7xGdJtrFaOKe^6!rPrk@8rhD^`r-W zJJG%Md3?70x!Z>=N*DAr^ZI?~RDHdww#!0qvhL4^G0Lxbo9eCYllRLip1CBti6Q&? z^nDX%trA{_aN7hv`#}=V(p!mf+C3df?0w?SPaW+*y~?vTO>LJq)SU zj%VbWx!?YeuBp!1_j7%hryOp&HSJVPol!-m+J{5y_zFX|-+p}Hne+-~kM>Bbz76Iv zZj&o2;KN~wo)(_Q=j0#|EGr`eNmD5&uf2MpSrHd<2&?B&Hb^n zp^DVyhn`KvMyzU;9LF2y+|u>mzTiU+L+Od&ZPmJqJUCc1=Is$X=+l*xduzhPTQh~j z@+}jc+wIs2Rb=??=d_Gce;~dHM0yy@!{#vt6p?_cOs--FG2IdysBpWUby3=womyczk-gE$GN8txSY{Y zYBZU@kkR&T=-Q$!uYD~u?((vKD9!uyR9E20AGrg%eNS$5xn8cA7iZwT?$EMzFIx-3 zKNzn+HSu-2#F3Rh6PVLHTc1Vd0^m|0d z_ydQ_(br}tj2|r#yuUYG{jgnJi%-)Vv%<%ZnUu??N!mOwFu0p?<5!{bi~V|6wY?A8 zEjB$UI+xMv#aF|%{mT>5816Fel+}3|vFp;LSN%5APJLZ|xhKr*I;ZR`<9Q}`w`^X^ zB)aqD!6jOXjTg(fiK&9O%ItIk`_ zsr^$~$Z{^C0u#_AA{l4iAVg-a9vUTSwmYynr5Q+g3#Z z5xWFwhTuNo*L$PfQqFzl`FMYtcTcp=fr)Ij^HpNg1!`V2Y&bq)!;;IfS~1&YmDSvW zVpCU5e<|tOC$eEh>GN+{>Zvo2uw-qFSG)69EL33Q%>ygj^Fvk%Pkb;~CW ze3SCUS_3VM;xuat*i>~Da?|R^LtnkBbUf6oeyA#Chj3X`17iZttx%6P&jMYemu*r z*cZxE?g^14I!sbi6LR+)f{Qn}RcBZn|ZlOTi>dwH~?bA4!f+HjzDT}L#>^%F>W$K5; zyzXC4-nH+O$bJ(v!+Yy9DYv7``IZ%jNv`EvkaXJX-t{YQf23dv;$gKGYF> zLVj1llgCedE^<^{lZo87;zr^1)%O467AX{}P8JAfxMN;8zqNSn<;=UgHdPtVUD@Af zCq4Vey=@F4R}?tAt?DdP;{4_9e%pQ5p7UvMaV>cN&T$7H`;wyM81dA^s}W3RT| z68AU9`#r1M5gs4AsYq$dlJ2tl6Dq57-tg{d3~OBUviWYojE%Pft1fV4D16@C6F7x? z5qshe>!}hpch@yEo?4;%rPoEU^7o6Sd;doNI9YR_>B9!;W%crzGmh^H$hy?C=t`{T zd{N1yggzb9&xgh0_9d|TpZ~{o*lcCs0^2XUdhY$a%69XuZ`Z1?`&JlB6fgL_Ac@1j z|J6zJn!~Qz#x4_j7%Qvqn+vDgT~nE<|Mj`FTid@2&We5W?sQzax43Mh;e-Em2ak7>R1aLS*lkVC;x7?ZC#uDJG)czlF99drc4YAD>U>UKNs4Z z?BK!1P%PT~>|<7h)jckowllKZMSsh)yv&p3ygGGmb;_duYXqxh!d7khy-B?ClHCU3 z9pYSE=M;+Avp;SS&R+Ah_muy!wtLGD`93^bP_R~jyT8$n_qy(7Ckxf@opZ$tE3F!x z7rs5-D)H7KUfW zo)0`&^gL_hY|AF?*^lrvW!lU(3unK<7eGG9Wjis@IvJ_;}dANwG)O6^13rH296E+)B)sa;*;o}?327x5wLNu8W?XqsyB zv}ZjzP56*(|z5nlR&QCs&)p{_xl&6-<@`TD-qr5fKC-pTS>ihll zrs`keTfukcJhsU4*fIINHp|1#yYmAoE|1zCy!Q$mEmymGeK*hQPQz5!*&gA0>x@@#4A3p^y*2Tw{K*;L@^__Hw)XHW6W)5c zY?1y`f#*qK5%>JPolOElZu0A2kAC$2@Wy@eeKX2=RwR`Dnc}Lu#cNMf!UFlutJ)v+ zR_+ts7_sTb(OSE;F?FVU4(*6O@;t6AP3HHc1Cuq6{K$%(Z!o=ik@f;R*)%Re-qZX4 zg{?H2da~&9#H5RJg$n)NY*G-oT&?@}591}FXzM9oR@ceAdA+?*ekr4{VUbk!9Y_0| z&N=oMjuZtPOPBp}=Nqe4=TU(uzP(}Xv3&m;mI+T3Uo?BI;&Jg3joOdGuRed)G*s5Q z^R8#@WoL<#6R+m;Pu{Vj@w;%Cz#aj{x-}2x8d&X#?k;QLJ$m9+eRA95#K&I~H%M4- zh-f*`_@QpEWU-s|)CZ4lh;`WWcc&CFa4(eNds?%(O!JqdvT$OD>DH;o>uiMXg>8sG zxHs{~;S)U0VSb%9ubkWO6h5zwSC~BQ9@jjs)mb^-dNz+dBb6toE0*=}ygBSOG3976 z=jZTT0loKT9gCMN^z&u1+pd~w;_#EB?(gE6fooJb8_O6CbN!FEZwY=8K#03y z?%#GP(drmBH+%lg``>iAPI`Ol&RPwg((NV=Q(8KW(ofsH+Q!|d$?T(EV^RL)#CgL@ zdh(M3cs6A1bUVK`)cv0yPm*%?wdkIYoeNK`_?YbBf3(;me17kFD~}EDcAH;L+0nqM zoHygsp=bl)x2>`&HFc-nZI0b-$7d!sMXPCn!Q_uwEG0sXKPJ?r?3G#Pe}ShfXx;o7 zTUD;5?$LgnSSi5jdZS-E`Hjb+#l4ri16$17w_Km`m*=PL`FwsAzAvli&2HRg^ND?% zOz!p435^#vKik5Qm9#RfiEU>2^TQew551e$);60b+1xi|n~~fnrXxZ&g46Rwd~|w} z8kE*fp3}Z}=G@x<4_Np9VwlYQ$8%@ay3NX8Dw3ETj_?1nK!nqEvx>uWOTGr1K;O@Y z_s*TtDk!gV`Jis(o%ve~PS4(0FO&W{FWVq;`jNSN-o0m#J2Gc_YSRxfgFDkW?k#_} z)8&%Ukwb@O+*o;UM@oY1`hb3ubM35h-&Sot?8q+sttHIX;{L;XmmMx`XIq~i{?#+b;G3-Cb>Yy0JvVpM99!iP zVLfZvp8D5y5;_5@50^c2_dI^8VS(jhfKuaf$%{?QQ3)_PjNT{yfvEJ7DdEW7Am;c=c|D#!R~= zX|#wZUWixv$;sv0@6TmFGH+GJoQJ31`&e#S#BihLL_qAb=I87yJdQ55+gjsi{BJ_g z8XMspV~M-(5}4Gorxe}DtjaxZ%6^{p{DZhxKX=%FXjmW@@U6&_&;REVi6XCKAM9J8w!W?Z&lj1AaXXZZ4&9wvctia4i^sQ) zZ9V$XO|j0xqr#qP;8NzmHctD3V->DdFnT2%{MxH zuZp4Rko}*=2imUlE=787mA!TUr$yKG@7o_+v?sFvkvDrdyICsFOtZ3fyG*OI)ne7Q ztKVv@{mxf?S7PFQQgy6yY3|2_>0L~_)1rT@ezYk{=+WG-$K}1R6|ekq`nXG30{b%E zQ^&e)cNtjobLMTiE4pcS*J9nZrxti^^8NqycI)ZmDW_UDn;r^WJ;OHPbY6*N$A%Z? z{+rpQycfxzmRtY(u@W1@=e_2xw@o*wtMZnb>7QjipmacQ?_0I|v(h#dG2}g}St6OZ zQA|HvOD*n!A7@+8+I3HxpPUYm&e){BKWO9R0~`~&%&yhh=)}q`vx(@4bLDc$w>r_# zxM{Ttue*pzWgGw1HH9xezr1nz(jHx*=!dSmR`;at>+XINxb5Wv&I=vC#5`gruV~rp z^x`<%@!d~%v2NI;BUli8Q#x-(+{d7!b{rq4O^@BMAjL+4W5)XDVjX+#&faYIY_){O zf;k(Ej>Iahd4ANyWtpAgde_d_V+UTfyqIru>1Wl~c``oJs#;?>w%lLUoaNHHSoLbp z-St+V~}=z#`(7Qc7@>8j9R3QuqjlR4Tv<$&R2mT+6M zA3K6?HRk4aeq4TT&j*FV%R%BQ(N|i27d9QcaII_ahTU#;fvN8@#lBqHc18N*ir0@G zdGjS*xwvLQ>Zj@68x}Hlt8Mt~Ea^Gn#M(cHA|qG2#*|%lEVfw{@#0m~?r@DO{IR{} zj*iu5zVE*p)#}aM)GWzk@MnEa_qu!5n@)6|V${)E=O!Wb-{|e;sM?!1)-Abv>3HhQ zh{zrf9l^A|^7-EN2{#2ybscXVYX0#qIBdQQ+tZC|YaRFM39~tePE0*3xBcjUt{na) zO^=^Fn4D0N%z$EPind0&op06?$8sIp0q3UL|A9&Hn#0mG0tGa#X@AM}4TrP;YI;XPwlu%6o!)}3X(>8Q}Igo!_R3NU(D(_0o?tQcW6xAtgc`%_< zRyC~2!2Y=RE%s#_Px$e!cAW73`C+HsqH0FxyE{S->X=Eiu&R7yb+PXA)o3*8Iji{j z@0C8&qPKPiZK}W8BC1|*e8%_kfFPsxY~4#&9DFk4I)8fgeEhkkEcBM@vwtO~qOmzM zZqN4Sw25K7u&CBGN!9U4QVY|J{^fU7`7Ji8Yc)67zkhbtzi|Ep=Ue8n(Yr%?moe11 z-znVkI`ezM0iAZmrT0H9-r-+8_r^aVE7mtpziJTC#;=DdFP@+r2)gJxq5-*dHHui@X`L+TmP3G zbGOUHzL!+-Jhn`9!oF*BD-M+%mtAKh#kX70?Ujnzc@JB;<)3($x3GJ0D75X)T`FC) z_hTH_uPfK$Q#mKzHV$oL%Dq|pu6<=}jrIqN(v|+6){zglM`|(7X_c0`eRdU7t-{Hk z+Z^AoK2Ci5$w22oL6EnHU-GB!*-`xW&nV75y}>b1X=UepCGmGR?!4vi6Y)oO^VA!>?hxxqo&vPwe8BHv_KW~Tc<9hgfg`TulSLu`w+|Iv_ zh%ZI^9GmS7EeSD91WkZ{>kJ2rK7$xpGfoU7QM7lAn=pM)BHK9wPAbzZT!WcrY`gC zOT(tZyt@Bqm;I3lR4#7GIeqoy!bwlgY}*)aBrov!K}c+oRYYjzzT!ry&B7cD5|`ZC zvweH5`O0rgro5V+%jLhhuP~EDQF{)&+mdGZ+&K&_&XiZ@vp!0 z!zICXF_Xdl9lvfzry3i4cj}zCZNIIU*A-2jX491|OLDii{H-=@R@8m_W&%-+tujkBGj>Pk(SV^Jz}HvY59$cJZdiAI=_8 zu&8WoXx6*Z-Ssr?PoKtS`!{_jYW_^B3YEC`p{MlJ=axT4f>y7yT~;sh)Ift()`ahD7Dx9M70AEzdLV&ZS0` zYot;q{+GV}b4#{{qvEymbvv_k*>kMTziNEBFZ|y2ltsOi+9s8^iR#jaK4(6Db!
    Zx&QNLI7foLjQb_8#x! zMX%4goe#@6)S!GPgV|^HzaBGP-TWVFcO#FtPd&0km7n`xQFy?npl_374~E~CyZ`d= zpFb4_y6(+tQb__G*Gyw9r=7eyNyJdF`GUv(jU0S0?JFx5zj26-tqq*CA-&yH?9#Pa z$BtiSIK95SA=cO;Mn$FOsrPFcl}H{I(cYc!-}ZO2B-gug&o@0;y70mJ#Q)NoM_5vJ z&DPPepBBg9r|lgwC3SbwZsxekNGtiiIkKnLME)t>+dqjx zEmE~Z@q=<)--9Fd@81MpGhSXZVRO5C?AiW=IX{Q@1C{p5lhDYoom~@R5FZ*=z`eRFGTj^W$a%)#P`Z3SBFttfVmT^+?fhqdk zYv#W#V{Hf!*!(LpsW|ph$9q*zfyC)@X|}mViX{e;d%nppH@c@$?iwq2`s%%nKg&ZN zS*~ym2r9gNB`R9ZXO;1~M}O~R*Bcy^`?K0J|6vGE{8xL+o31kJ=5va$ifg?-Fk#)- zKOBsKF`w6FCNqaWQLI>}6FSeKC?I0b&7X$N*%kr(CRIraZ$6y4lW7^3))jN?)Ok*Z zv^>{Ynej_DZuFhu_W9SkMXMGk`z?KKUTncNiIEH)Q zYZEozx7)bs?T*Z~p{kr(L5EY-)+9;#m%R>sc|f9LYVz^ems=~el@>G1cyqhQL~~-x z>K>I8|3fopRrm7;C$&Ac+WT2igw@C;==Fqk*Gsuho?GR$%^~*Mo6vymNA^g_^w;gV zo%8)Z?`a30que!m>p$KKSS9^K<-%Nk5y8m}>$ETIl8gV;Cp;;@ z^f{zu`78`4Ih}H0jGFgVJN#T}px;Klx4a2&c=$`V+v=Mox+hD{O^kTDL7*_}K+Q7= z&1)s)i4Si`oD#?@(5hL~bdY!6*$YO?yAM5hBPgD1zjbo`_eP=9yn%eo=6w(Q(HVN4!(#08UA=9El;lFd?NyrsdTbEN=OH&^6AN-`67O&K@Ea^bf*OcnC zkb42@(-zm-E%Kg`_r~eqG{uwrtnwcx)Xw3%?DdOr*OPBHTV~|-+%9oWp3$Q=%PaZv zU!^C{JtS7^wo27jonLljZ~0W6~H{@7ncp`Jw1F&W0z#4ez=!B%U$|q{rwh}=zBzm{IjoUcb@6A8|LVTwp`Q2D1UodpCfhD6 zm|5RAS^OEp3-90iuFhC+Kz>R~_K(DzdM5q0V5X1!?AnQO5u8&SQ!`E(zV!Zi?r_2! z+i^$593;AT(9}$C-utDol7v>KwG%3u*mpw z@9aoT-=`|_-*!07Dl|KH;k2l{@~I%6g06_)@$(Ju?wI-Ee(H}E0p{)Rc74)YUZ+&m z`!#KYm`C&E&V!QTF~?N%+l512%zI|;+Ff(AzG1g~d#~q#lWKQF+4c)Ox7;Vs{(r{T zMSH@}37ffZaf|Cx7CU+BovPR!!^-ShfzzLo5;p$iR6e7f&6>}5BcW@0q~4?emNlAb zlg=>guvYe!eD_VIZ`!Y?{kvHV|EhH;zDaPKXnlM7KZegHei?6mmD!)#wEcYg*BF)6 ze=NE#@385SG`;7xN%>7Q|H+C;k)BJ>tjt_5u&K?eyrTQ-j3pDyO!K7jR%_4Lacg%^ ztVH_Dls2DDF%eeFFFh&v_b6bk`g5zhD||T?U65C>&)6;gcGf$mZ4=yIR+*QnynAb_ z#rLH;{&p45``3a$e2%l9J>Ro#6~~X~8cnlTRo*r1EeM<=sWr|1^Yy?v`uc8xXB0T* z>|eLSxW%>6Z*7g&oR>$Hb(SAunDK1uwZ|oMwm;2iH_$umkX&q4*RWjd+FXWDrLLV> ze21=dJdkR=W3%s(#{W~dBl^!OKA7w9c&^iglG$ZR0z%(k%rfawW9Dd+(zFvcxcK+R z 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%0AwR75~8LJmO?_1{{+RXbyU*Y;o1Fks1hf^ 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�#@s0)9=3*yejUh)P3d2 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≶++k6!mA8OCc^lWhv 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%0A?Lnaj_kHIKKZuW$9du&-EG~oI%=yvonW~T&2A)e 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

    }s3YW`?R)Q+rEity*$&n@IQ@ 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

    fix AtC kernel quartic_sphere 10.0

    # create a uniform 1 x 1 x 1 mesh that covers region contain the group
    - # with periodicity this effectively creats a system average
    + # with periodicity this effectively creates a system average
    fix_modify AtC mesh create 1 1 1 box p p p

    # change from default lagrangian map to eulerian
    diff --git a/doc/src/fix_atc.rst b/doc/src/fix_atc.rst index fe35111005..3322fda7e7 100644 --- a/doc/src/fix_atc.rst +++ b/doc/src/fix_atc.rst @@ -83,7 +83,7 @@ likewise for this post-processing example: fix AtC kernel quartic_sphere 10.0 # create a uniform 1 x 1 x 1 mesh that covers region contain the group - # with periodicity this effectively creats a system average + # with periodicity this effectively creates a system average fix_modify AtC mesh create 1 1 1 box p p p # change from default lagrangian map to eulerian diff --git a/doc/src/fix_ave_correlate_long.rst b/doc/src/fix_ave_correlate_long.rst index 579de24328..9416f42f1c 100644 --- a/doc/src/fix_ave_correlate_long.rst +++ b/doc/src/fix_ave_correlate_long.rst @@ -51,7 +51,7 @@ Syntax *nlen* args = Nlen Nlen = length of each correlator *ncount* args = Ncount - Ncount = number of values over which succesive correlators are averaged + Ncount = number of values over which successive correlators are averaged Examples """""""" diff --git a/doc/src/kim_commands.rst b/doc/src/kim_commands.rst index cefae204ce..5a4b5c56ae 100644 --- a/doc/src/kim_commands.rst +++ b/doc/src/kim_commands.rst @@ -41,7 +41,7 @@ Syntax on the prefix specified in *variable* and a number appended to indicate which element in the list of values is in the variable. *explicit* = returns the values separately in one more more variable names - provided as arguments that preceed *formatarg*\ . [default for *kim_param*] + provided as arguments that precede *formatarg*\ . [default for *kim_param*] * query\_function = name of the OpenKIM web API query function to be used * queryargs = a series of *keyword=value* pairs that represent the web query; supported keywords depend on the query function diff --git a/doc/src/pair_meamc.rst b/doc/src/pair_meamc.rst index 78b04f90de..098c3cb601 100644 --- a/doc/src/pair_meamc.rst +++ b/doc/src/pair_meamc.rst @@ -119,7 +119,7 @@ that will be used with other potentials. filenames can appear in any order, e.g. "Si C" or "C Si" in the example above. However, if the 2nd filename is not NULL (as in the example above), it contains settings that are Fortran-indexed for the - elements that preceed it. Thus you need to insure you list the + elements that precede it. Thus you need to insure you list the elements between the filenames in an order consistent with how the values in the 2nd filename are indexed. See details below on the syntax for settings in the 2nd file. @@ -230,7 +230,7 @@ where hcp = hexagonal close-packed dim = dimer dia = diamond (interlaced fcc for alloy) - dia3= diamond structure with primary 1NN and secondary 3NN interation + dia3= diamond structure with primary 1NN and secondary 3NN interaction b1 = rock salt (NaCl structure) c11 = MoSi2 structure l12 = Cu3Au structure (lower case L, followed by 12) diff --git a/doc/src/rerun.rst b/doc/src/rerun.rst index 0df10088fc..f604ca51e1 100644 --- a/doc/src/rerun.rst +++ b/doc/src/rerun.rst @@ -53,7 +53,7 @@ computed on the shapshot to produce thermodynamic or other output. This can be useful in the following kinds of scenarios, after an initial simulation produced the dump file: -* Compute the energy and forces of snaphots using a different potential. +* Compute the energy and forces of snapshots using a different potential. * Calculate one or more diagnostic quantities on the snapshots that weren't computed in the initial run. These can also be computed with settings not used in the initial run, e.g. computing an RDF via the diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index a76ee2461c..7c498d9215 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -2279,8 +2279,6 @@ Prakash pre Pre prec -preceed -preceeded precession prefactor prefactors @@ -2673,7 +2671,6 @@ smtbq sna snad snapcoeff -snaphots snapparam snav Snodin @@ -2817,7 +2814,6 @@ tdamp tdpd tDPD Tdrude -Technolgy Telsa tempCorrCoeff templated @@ -3140,7 +3136,6 @@ Whelan whitesmoke Wi Wicaksono -wih Wijk Wikipedia wildcard -- GitLab From 4f0e9e2d265965a46a789a4384136a9f69bb7e84 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 12 Mar 2020 06:51:06 -0400 Subject: [PATCH 243/689] some cleanup and consistency improvements in MESSAGE package code and docs --- doc/src/server_md.txt | 150 ---------------------------------- src/MESSAGE/fix_client_md.cpp | 2 +- src/MESSAGE/server_mc.cpp | 12 ++- src/MESSAGE/server_md.cpp | 2 +- 4 files changed, 7 insertions(+), 159 deletions(-) delete mode 100644 doc/src/server_md.txt diff --git a/doc/src/server_md.txt b/doc/src/server_md.txt deleted file mode 100644 index daa6ab57ce..0000000000 --- a/doc/src/server_md.txt +++ /dev/null @@ -1,150 +0,0 @@ -"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c - -:link(lws,http://lammps.sandia.gov) -:link(ld,Manual.html) -:link(lc,Commands_all.html) - -:line - -server md command :h3 - -[Syntax:] - -server md :pre - -md = the protocol argument to the "server"_server.html command - -[Examples:] - -server md :pre - -[Description:] - -This command starts LAMMPS running in "server" mode, where it will -expect messages from a separate "client" code that match the {md} -protocol for format and content explained below. For each message -LAMMPS receives it will send a message back to the client. - -The "Howto client/server"_Howto_client_server.html doc page gives an -overview of client/server coupling of LAMMPS with another code where -one code is the "client" and sends request messages to a "server" -code. The server responds to each request with a reply message. This -enables the two codes to work in tandem to perform a simulation. - -When this command is invoked, LAMMPS will run in server mode in an -endless loop, waiting for messages from the client code. The client -signals when it is done sending messages to LAMMPS, at which point the -loop will exit, and the remainder of the LAMMPS script will be -processed. - -The "server"_server.html doc page gives other options for using LAMMPS -in server mode. See an example of how this command is used in -examples/message/in.message.server. - -:line - -When using this command, LAMMPS (as the server code) receives the -current coordinates of all particles from the client code each -timestep, computes their interaction, and returns the energy, forces, -and pressure for the interacting particles to the client code, so it -can complete the timestep. This command could also be used with a -client code that performs energy minimization, using the server to -compute forces and energy each iteration of its minimizer. - -When using the "fix client/md"_fix_client_md.html command, LAMMPS (as -the client code) does the timestepping and receives needed energy, -forces, and pressure values from the server code. - -The format and content of the exchanged messages are explained here in -a conceptual sense. Python-style pseudo code for the library calls to -the CSlib is shown, which performs the actual message exchange between -the two codes. See the "CSlib website"_http://cslib.sandia.gov doc -pages for more details on the actual library syntax. The "cs" object -in this pseudo code is a pointer to an instance of the CSlib. - -See the src/MESSAGE/server_md.cpp and src/MESSAGE/fix_client_md.cpp -files for details on how LAMMPS uses these messages. See the -examples/COUPLE/lammps_vasp/vasp_wrap.py or -examples/COUPLE/lammps_nwchem/nwchem_wrap.py files for examples of how -a quantum code (VASP or NWChem) can use these messages. - -The following pseudo-code uses these values, defined as enums. - -Define: - -SETUP=1, STEP=2 -DIM=1, PERIODICITY=2, ORIGIN=3, BOX=4, NATOMS=5, NTYPES=6, TYPES=7, COORDS=8, UNITS-9, CHARGE=10 -FORCES=1, ENERGY=2, PRESSURE=3, ERROR=4 :pre - -[Client sends 2 kinds of messages]: - -# required fields: DIM, PERIODICTY, ORIGIN, BOX, NATOMS, NTYPES, TYPES, COORDS -# optional fields: UNITS, CHARGE :pre - -cs->send(SETUP,nfields) # msgID with nfields :pre - -cs->pack_int(DIM,dim) # dimension (2,3) of simulation -cs->pack(PERIODICITY,3,xyz) # periodicity flags in 3 dims -cs->pack(ORIGIN,3,origin) # lower-left corner of simulation box -cs->pack(BOX,9,box) # 3 edge vectors of simulation box -cs->pack_int(NATOMS,natoms) # total number of atoms -cs->pack_int(NTYPES,ntypes) # number of atom types -cs->pack(TYPES,natoms,type) # vector of per-atom types -cs->pack(COORDS,3*natoms,x) # vector of 3N atom coords -cs->pack_string(UNITS,units) # units = "lj", "real", "metal", etc -cs->pack(CHARGE,natoms,q) # vector of per-atom charge :pre - -# required fields: COORDS -# optional fields: ORIGIN, BOX :pre - -cs->send(STEP,nfields) # msgID with nfields :pre - -cs->pack(COORDS,3*natoms,x) # vector of 3N atom coords -cs->pack(ORIGIN,3,origin) # lower-left corner of simulation box -cs->pack(BOX,9,box) # 3 edge vectors of simulation box :pre - -[Server replies to either kind of message]: - -# required fields: FORCES, ENERGY, PRESSURE -# optional fields: ERROR :pre - -cs->send(msgID,nfields) # msgID with nfields -cs->pack(FORCES,3*Natoms,f) # vector of 3N forces on atoms -cs->pack(ENERGY,1,poteng) # total potential energy of system -cs->pack(PRESSURE,6,press) # global pressure tensor (6-vector) -cs->pack_int(ERROR,flag) # server had an error (e.g. DFT non-convergence) :pre - -:line - -The units for various quantities that are sent and received iva -messages are defined for atomic-scale simulations in the table below. -The client and server codes (including LAMMPS) can use internal units -different than these (e.g. "real units"_units.html in LAMMPS), so long -as they convert to these units for messaging. - -COORDS, ORIGIN, BOX = Angstroms -CHARGE = multiple of electron charge (1.0 is a proton) -ENERGY = eV -FORCES = eV/Angstrom -PRESSURE = bars :ul - -Note that these are "metal units"_units.html in LAMMPS. - -If you wish to run LAMMPS in another its non-atomic units, e.g. "lj -units"_units.html, then the client and server should exchange a UNITS -message as indicated above, and both the client and server should -agree on the units for the data they exchange. - -:line - -[Restrictions:] - -This command is part of the MESSAGE package. It is only enabled if -LAMMPS was built with that package. See the "Build -package"_Build_package.html doc page for more info. - -[Related commands:] - -"message"_message.html, "fix client/md"_fix_client_md.html - -[Default:] none diff --git a/src/MESSAGE/fix_client_md.cpp b/src/MESSAGE/fix_client_md.cpp index 1a9437ebe2..1cbce3a7f9 100644 --- a/src/MESSAGE/fix_client_md.cpp +++ b/src/MESSAGE/fix_client_md.cpp @@ -45,7 +45,7 @@ FixClientMD::FixClientMD(LAMMPS *lmp, int narg, char **arg) : if (!atom->map_style) error->all(FLERR,"Fix client/md requires atom map"); if (sizeof(tagint) != 4) - error->all(FLERR,"Fix client/md requires 4-byte atom IDs"); + error->all(FLERR,"Fix client/md only supports 32-bit atom IDs"); if (strcmp(update->unit_style,"real") == 0) units = REAL; else if (strcmp(update->unit_style,"metal") == 0) units = METAL; diff --git a/src/MESSAGE/server_mc.cpp b/src/MESSAGE/server_mc.cpp index 8152b1f772..c4e64b4bf8 100644 --- a/src/MESSAGE/server_mc.cpp +++ b/src/MESSAGE/server_mc.cpp @@ -43,17 +43,17 @@ void ServerMC::loop() CSlib *cs = (CSlib *) lmp->cslib; - // require atom map + if (domain->box_exist == 0) + error->all(FLERR,"Server command before simulation box is defined"); - if (!atom->map_style) error->all(FLERR,"Server mode requires atom map"); + if (!atom->map_style) error->all(FLERR,"Server mc requires atom map"); + if (atom->tag_enable == 0) error->all(FLERR,"Server mc requires atom IDs"); + if (sizeof(tagint) != 4) error->all(FLERR,"Server mc requires 32-bit atom IDs"); // initialize LAMMPS for dynamics input->one("run 0"); - //update->whichflag = 1; - //lmp->init(); - // loop on messages // receive a message, process it, send return message if necessary @@ -123,8 +123,6 @@ void ServerMC::loop() int nsteps = cs->unpack_int(1); - //input->one("run 100"); - update->nsteps = nsteps; update->firststep = update->ntimestep; update->laststep = update->ntimestep + nsteps; diff --git a/src/MESSAGE/server_md.cpp b/src/MESSAGE/server_md.cpp index e16095ad4c..418162e5d9 100644 --- a/src/MESSAGE/server_md.cpp +++ b/src/MESSAGE/server_md.cpp @@ -48,7 +48,7 @@ ServerMD::ServerMD(LAMMPS *lmp) : Pointers(lmp) if (!atom->map_style) error->all(FLERR,"Server md requires atom map"); if (atom->tag_enable == 0) error->all(FLERR,"Server md requires atom IDs"); - if (sizeof(tagint) != 4) error->all(FLERR,"Server md requires 4-byte atom IDs"); + if (sizeof(tagint) != 4) error->all(FLERR,"Server md requires 32-bit atom IDs"); if (strcmp(update->unit_style,"real") == 0) units = REAL; else if (strcmp(update->unit_style,"metal") == 0) units = METAL; -- GitLab From e2b7054f74ee5217e3e0ce1070a570e8c84abc21 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 12 Mar 2020 06:59:04 -0400 Subject: [PATCH 244/689] include required header --- src/MESSAGE/server_mc.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/MESSAGE/server_mc.cpp b/src/MESSAGE/server_mc.cpp index c4e64b4bf8..af7850a0e9 100644 --- a/src/MESSAGE/server_mc.cpp +++ b/src/MESSAGE/server_mc.cpp @@ -13,6 +13,7 @@ #include "server_mc.h" #include "atom.h" +#include "domain.h" #include "update.h" #include "integrate.h" #include "input.h" -- GitLab From 010b1f7434f074c68f819a5c81c20d15b3ae71ff Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 12 Mar 2020 08:04:26 -0400 Subject: [PATCH 245/689] more conversion of parsed-literal to code-block and a bunch of other issues --- doc/src/Errors_common.rst | 2 +- doc/src/Speed_intel.rst | 10 ++++---- doc/src/Speed_kokkos.rst | 20 ++++++++-------- doc/src/compute_dpd_atom.rst | 4 +++- doc/src/dump.rst | 16 ++++++------- doc/src/dump_molfile.rst | 4 ++-- doc/src/dump_netcdf.rst | 4 ++-- doc/src/dump_vtk.rst | 6 ++--- doc/src/echo.rst | 4 ++-- doc/src/fix.rst | 2 +- doc/src/fix_langevin_spin.rst | 4 ++-- doc/src/fix_saed_vtk.rst | 4 ++-- doc/src/fix_setforce.rst | 2 +- doc/src/fix_shake.rst | 2 +- doc/src/fix_shardlow.rst | 2 +- doc/src/fix_smd.rst | 2 +- doc/src/fix_smd_setvel.rst | 4 ++-- doc/src/group.rst | 8 +++---- doc/src/group2ndx.rst | 2 +- doc/src/hyper.rst | 2 +- doc/src/if.rst | 18 +++++++------- doc/src/include.rst | 2 +- doc/src/info.rst | 2 +- doc/src/jump.rst | 26 ++++++++++----------- doc/src/label.rst | 2 +- doc/src/lattice.rst | 10 ++++---- doc/src/log.rst | 2 +- doc/src/mass.rst | 6 ++--- doc/src/message.rst | 21 +++++++++++++---- doc/src/minimize.rst | 2 +- doc/src/molecule.rst | 2 +- doc/src/neb.rst | 4 ++-- doc/src/neb_spin.rst | 2 +- doc/src/neighbor.rst | 2 +- doc/src/newton.rst | 4 ++-- doc/src/next.rst | 8 +++---- doc/src/package.rst | 6 ++--- doc/src/partition.rst | 6 ++--- doc/src/prd.rst | 2 +- doc/src/print.rst | 2 +- doc/src/processors.rst | 14 +++++------ doc/src/quit.rst | 2 +- doc/src/region.rst | 8 +++---- doc/src/replicate.rst | 2 +- doc/src/rerun.rst | 2 +- doc/src/restart.rst | 8 +++---- doc/src/run.rst | 12 +++++----- doc/src/server.rst | 2 +- doc/src/server_mc.rst | 2 +- doc/src/server_md.rst | 2 +- doc/src/set.rst | 8 +++---- doc/src/shell.rst | 6 ++--- doc/src/suffix.rst | 2 +- doc/src/tad.rst | 2 +- doc/src/temper.rst | 10 ++++---- doc/src/temper_grem.rst | 25 ++++++++++---------- doc/src/temper_npt.rst | 2 +- doc/src/thermo.rst | 6 ++--- doc/src/timer.rst | 4 ++-- doc/src/timestep.rst | 2 +- doc/src/uncompute.rst | 2 +- doc/src/undump.rst | 2 +- doc/src/unfix.rst | 2 +- doc/utils/sphinx-config/false_positives.txt | 1 + 64 files changed, 189 insertions(+), 172 deletions(-) diff --git a/doc/src/Errors_common.rst b/doc/src/Errors_common.rst index 0926e3a72c..d74d5f7f35 100644 --- a/doc/src/Errors_common.rst +++ b/doc/src/Errors_common.rst @@ -71,7 +71,7 @@ Some commands allow for using variable references in place of numeric constants so that the value can be evaluated and may change over the course of a run. This is typically done with the syntax *v\_name* for a parameter, where name is the name of the variable. On the other hand, -immediate variable expansion with the syntax $\ *name* is performed while +immediate variable expansion with the syntax ${name} is performed while reading the input and before parsing commands, .. note:: diff --git a/doc/src/Speed_intel.rst b/doc/src/Speed_intel.rst index 956e03cb87..1cad9cbeb8 100644 --- a/doc/src/Speed_intel.rst +++ b/doc/src/Speed_intel.rst @@ -192,7 +192,7 @@ will report every hardware thread as a separate core allowing one to determine the number of hardware threads available. On Linux systems, this information can normally be obtained with: -.. parsed-literal:: +.. code-block:: bash cat /proc/cpuinfo @@ -219,7 +219,7 @@ Phi x200 processors making it easier to cross-compile. For users with recent installations of Intel Parallel Studio, the process can be as simple as: -.. parsed-literal:: +.. code-block:: bash make yes-user-intel source /opt/intel/parallel_studio_xe_2016.3.067/psxevars.sh @@ -334,7 +334,7 @@ desired. Examples (see documentation for your MPI/Machine for differences in launching MPI applications): -.. parsed-literal:: +.. code-block:: bash mpirun -np 72 -ppn 36 lmp_machine -sf intel -in in.script # 2 nodes, 36 MPI tasks/node, $OMP_NUM_THREADS OpenMP Threads mpirun -np 72 -ppn 36 lmp_machine -sf intel -in in.script -pk intel 0 omp 2 mode double # Don't use any co-processors that might be available, use 2 OpenMP threads for each task, use double precision @@ -346,14 +346,14 @@ can be edited to enable the USER-INTEL package. This requires adding the :doc:`package intel ` command to the top of the input script. For the second example above, this would be: -.. parsed-literal:: +.. code-block:: LAMMPS package intel 0 omp 2 mode double To enable the USER-INTEL package only for individual styles, you can add an "intel" suffix to the individual style, e.g.: -.. parsed-literal:: +.. code-block:: LAMMPS pair_style lj/cut/intel 2.5 diff --git a/doc/src/Speed_kokkos.rst b/doc/src/Speed_kokkos.rst index 44ac153e60..46b4be571c 100644 --- a/doc/src/Speed_kokkos.rst +++ b/doc/src/Speed_kokkos.rst @@ -71,7 +71,7 @@ Kokkos. E.g. the mpirun command in OpenMPI does this via its -np and Here is a quick overview of how to use the KOKKOS package for CPU acceleration, assuming one or more 16-core nodes. -.. parsed-literal:: +.. code-block:: bash mpirun -np 16 lmp_kokkos_mpi_only -k on -sf kk -in in.lj # 1 node, 16 MPI tasks/node, no multi-threading mpirun -np 2 -ppn 1 lmp_kokkos_omp -k on t 16 -sf kk -in in.lj # 2 nodes, 1 MPI task/node, 16 threads/task @@ -119,7 +119,7 @@ below. page for details and default settings. Experimenting with its options can provide a speed-up for specific calculations. For example: -.. parsed-literal:: +.. code-block:: bash mpirun -np 16 lmp_kokkos_mpi_only -k on -sf kk -pk kokkos newton on neigh half comm no -in in.lj # Newton on, Half neighbor list, non-threaded comm @@ -180,9 +180,9 @@ tasks. Examples of mpirun commands that follow these rules are shown below. -.. parsed-literal:: +.. code-block:: bash - Intel KNL node with 68 cores (272 threads/node via 4x hardware threading): + # Running on an Intel KNL node with 68 cores (272 threads/node via 4x hardware threading): mpirun -np 64 lmp_kokkos_phi -k on t 4 -sf kk -in in.lj # 1 node, 64 MPI tasks/node, 4 threads/task mpirun -np 66 lmp_kokkos_phi -k on t 4 -sf kk -in in.lj # 1 node, 66 MPI tasks/node, 4 threads/task mpirun -np 32 lmp_kokkos_phi -k on t 8 -sf kk -in in.lj # 1 node, 32 MPI tasks/node, 8 threads/task @@ -205,7 +205,7 @@ threads/task as Nt. The product of these two values should be N, i.e. details and default settings. Experimenting with its options can provide a speed-up for specific calculations. For example: -.. parsed-literal:: +.. code-block:: bash mpirun -np 64 lmp_kokkos_phi -k on t 4 -sf kk -pk kokkos comm host -in in.reax # Newton on, half neighbor list, threaded comm mpirun -np 64 lmp_kokkos_phi -k on t 4 -sf kk -pk kokkos newton off neigh full comm no -in in.lj # Newton off, full neighbor list, non-threaded comm @@ -246,7 +246,7 @@ then the number of MPI tasks/node should not exceed N. Here are examples of how to use the KOKKOS package for GPUs, assuming one or more nodes, each with two GPUs: -.. parsed-literal:: +.. code-block:: bash mpirun -np 2 lmp_kokkos_cuda_openmpi -k on g 2 -sf kk -in in.lj # 1 node, 2 MPI tasks/node, 2 GPUs/node mpirun -np 32 -ppn 2 lmp_kokkos_cuda_openmpi -k on g 2 -sf kk -in in.lj # 16 nodes, 2 MPI tasks/node, 2 GPUs/node (32 GPUs total) @@ -266,7 +266,7 @@ one or more nodes, each with two GPUs: default settings. Experimenting with its options can provide a speed-up for specific calculations. For example: -.. parsed-literal:: +.. code-block:: bash mpirun -np 2 lmp_kokkos_cuda_openmpi -k on g 2 -sf kk -pk kokkos newton on neigh half binsize 2.8 -in in.lj # Newton on, half neighbor list, set binsize = neighbor ghost cutoff @@ -308,7 +308,7 @@ hardware options appropriate to your system, as documented above. You can use the :doc:`suffix kk ` command, or you can explicitly add a "kk" suffix to individual styles in your input script, e.g. -.. parsed-literal:: +.. code-block:: LAMMPS pair_style lj/cut/kk 2.5 @@ -323,7 +323,7 @@ used together in a few special cases. In the Makefile, the KOKKOS\_DEVICES variable must include both "Cuda" and "OpenMP", as is the case for /src/MAKE/OPTIONS/Makefile.kokkos\_cuda\_mpi -.. parsed-literal:: +.. code-block:: bash KOKKOS_DEVICES=Cuda,OpenMP @@ -340,7 +340,7 @@ as "t Nt" and the number of GPUs as "g Ng" For example, the command to run with 1 GPU and 8 OpenMP threads is then: -.. parsed-literal:: +.. code-block:: bash mpiexec -np 1 lmp_kokkos_cuda_openmpi -in in.lj -k on g 1 t 8 -sf kk diff --git a/doc/src/compute_dpd_atom.rst b/doc/src/compute_dpd_atom.rst index 6abac88965..d1a683db87 100644 --- a/doc/src/compute_dpd_atom.rst +++ b/doc/src/compute_dpd_atom.rst @@ -16,7 +16,9 @@ Syntax Examples """""""" -compute 1 all dpd/atom +.. code-block:: LAMMPS + + compute 1 all dpd/atom Description """"""""""" diff --git a/doc/src/dump.rst b/doc/src/dump.rst index 3d243f71a4..2f1c58158f 100644 --- a/doc/src/dump.rst +++ b/doc/src/dump.rst @@ -125,18 +125,18 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS dump myDump all atom 100 dump.atom dump myDump all atom/mpiio 100 dump.atom.mpiio dump myDump all atom/gz 100 dump.atom.gz dump 2 subgroup atom 50 dump.run.bin dump 2 subgroup atom 50 dump.run.mpiio.bin - dump 4a all custom 100 dump.myforce.\* id type x y vx fx + dump 4a all custom 100 dump.myforce.* id type x y vx fx dump 4b flow custom 100 dump.%.myforce id type c_myF[3] v_ke dump 4b flow custom 100 dump.%.myforce id type c_myF[\*] v_ke - dump 2 inner cfg 10 dump.snap.\*.cfg mass type xs ys zs vx vy vz - dump snap all cfg 100 dump.config.\*.cfg mass type xs ys zs id type c_Stress[2] + dump 2 inner cfg 10 dump.snap.*.cfg mass type xs ys zs vx vy vz + dump snap all cfg 100 dump.config.*.cfg mass type xs ys zs id type c_Stress[2] dump 1 all xtc 1000 file.xtc Description @@ -425,7 +425,7 @@ library, which is part of the MPI standard for versions 2.0 and above. Using MPI-IO requires two steps. First, build LAMMPS with its MPIIO package installed, e.g. -.. parsed-literal:: +.. code-block:: bash make yes-mpiio # installs the MPIIO package make mpi # build LAMMPS for your platform @@ -481,10 +481,10 @@ had been listed one by one. E.g. these 2 dump commands are equivalent, since the :doc:`compute stress/atom ` command creates a per-atom array with 6 columns: -.. parsed-literal:: +.. code-block:: LAMMPS compute myPress all stress/atom NULL - dump 2 all custom 100 tmp.dump id myPress[\*] + dump 2 all custom 100 tmp.dump id myPress[*] dump 2 all custom 100 tmp.dump id myPress[1] myPress[2] myPress[3] & myPress[4] myPress[5] myPress[6] @@ -537,7 +537,7 @@ values. Here is an example of how to dump bond info for a system, including the distance and energy of each bond: -.. parsed-literal:: +.. code-block:: LAMMPS compute 1 all property/local batom1 batom2 btype compute 2 all bond/local dist eng diff --git a/doc/src/dump_molfile.rst b/doc/src/dump_molfile.rst index 099ac25ef5..69bd8aa8c2 100644 --- a/doc/src/dump_molfile.rst +++ b/doc/src/dump_molfile.rst @@ -21,10 +21,10 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS dump mf1 all molfile 10 melt1.xml hoomd - dump mf2 all molfile 10 melt2-\*.pdb pdb . + dump mf2 all molfile 10 melt2-*.pdb pdb . dump mf3 all molfile 50 melt3.xyz xyz .:/home/akohlmey/vmd/plugins/LINUX/molfile Description diff --git a/doc/src/dump_netcdf.rst b/doc/src/dump_netcdf.rst index 3dd8a7c5c5..5627060452 100644 --- a/doc/src/dump_netcdf.rst +++ b/doc/src/dump_netcdf.rst @@ -24,12 +24,12 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS dump 1 all netcdf 100 traj.nc type x y z vx vy vz dump_modify 1 append yes at -1 thermo yes dump 1 all netcdf/mpiio 1000 traj.nc id type x y z - dump 1 all netcdf 1000 traj.\*.nc id type x y z + dump 1 all netcdf 1000 traj.*.nc id type x y z Description """"""""""" diff --git a/doc/src/dump_vtk.rst b/doc/src/dump_vtk.rst index 8b5843a86b..e5264b783c 100644 --- a/doc/src/dump_vtk.rst +++ b/doc/src/dump_vtk.rst @@ -20,10 +20,10 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS - dump dmpvtk all vtk 100 dump\*.myforce.vtk id type vx fx - dump dmpvtp flow vtk 100 dump\*.%.displace.vtp id type c_myD[1] c_myD[2] c_myD[3] v_ke + dump dmpvtk all vtk 100 dump*.myforce.vtk id type vx fx + dump dmpvtp flow vtk 100 dump*.%.displace.vtp id type c_myD[1] c_myD[2] c_myD[3] v_ke Description """"""""""" diff --git a/doc/src/echo.rst b/doc/src/echo.rst index d91571ed0c..6fc00aa1e6 100644 --- a/doc/src/echo.rst +++ b/doc/src/echo.rst @@ -15,7 +15,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS echo both echo log @@ -40,6 +40,6 @@ Restrictions Default """"""" -.. parsed-literal:: +.. code-block:: LAMMPS echo log diff --git a/doc/src/fix.rst b/doc/src/fix.rst index 42fb071a43..b6088376bc 100644 --- a/doc/src/fix.rst +++ b/doc/src/fix.rst @@ -18,7 +18,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS fix 1 all nve fix 3 all nvt temp 300.0 300.0 0.01 diff --git a/doc/src/fix_langevin_spin.rst b/doc/src/fix_langevin_spin.rst index 3ed7c3bbab..7113f1459c 100644 --- a/doc/src/fix_langevin_spin.rst +++ b/doc/src/fix_langevin_spin.rst @@ -19,7 +19,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS fix 2 all langevin/spin 300.0 0.01 21 @@ -53,7 +53,7 @@ Note: due to the form of the sLLG equation, this fix has to be defined just before the nve/spin fix (and after all other magnetic fixes). As an example: -.. parsed-literal:: +.. code-block:: LAMMPS fix 1 all precession/spin zeeman 0.01 0.0 0.0 1.0 fix 2 all langevin/spin 300.0 0.01 21 diff --git a/doc/src/fix_saed_vtk.rst b/doc/src/fix_saed_vtk.rst index 1368a80139..d0adefee00 100644 --- a/doc/src/fix_saed_vtk.rst +++ b/doc/src/fix_saed_vtk.rst @@ -33,7 +33,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS compute 1 all saed 0.0251 Al O Kmax 1.70 Zone 0 0 1 dR_Ewald 0.01 c 0.5 0.5 0.5 compute 2 all saed 0.0251 Ni Kmax 1.70 Zone 0 0 0 c 0.05 0.05 0.05 manual echo @@ -65,7 +65,7 @@ which store their own "group" definitions. Fix saed/vtk is designed to work only with :doc:`compute saed ` values, e.g. -.. parsed-literal:: +.. code-block:: LAMMPS compute 3 top saed 0.0251 Al O fix saed/vtk 1 1 1 c_3 file Al2O3_001.saed diff --git a/doc/src/fix_setforce.rst b/doc/src/fix_setforce.rst index 27ddc5bf0d..1b53bfe200 100644 --- a/doc/src/fix_setforce.rst +++ b/doc/src/fix_setforce.rst @@ -31,7 +31,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS fix freeze indenter setforce 0.0 0.0 0.0 fix 2 edge setforce NULL 0.0 0.0 diff --git a/doc/src/fix_shake.rst b/doc/src/fix_shake.rst index 2df89918bc..d687920e97 100644 --- a/doc/src/fix_shake.rst +++ b/doc/src/fix_shake.rst @@ -39,7 +39,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS fix 1 sub shake 0.0001 20 10 b 4 19 a 3 5 2 fix 1 sub shake 0.0001 20 10 t 5 6 m 1.0 a 31 diff --git a/doc/src/fix_shardlow.rst b/doc/src/fix_shardlow.rst index 8fd26c8471..a5ce32c89a 100644 --- a/doc/src/fix_shardlow.rst +++ b/doc/src/fix_shardlow.rst @@ -19,7 +19,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS fix 1 all shardlow diff --git a/doc/src/fix_smd.rst b/doc/src/fix_smd.rst index 9c269891c1..ddd6a15505 100644 --- a/doc/src/fix_smd.rst +++ b/doc/src/fix_smd.rst @@ -37,7 +37,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS fix pull cterm smd cvel 20.0 -0.00005 tether NULL NULL 100.0 0.0 fix pull cterm smd cvel 20.0 -0.0001 tether 25.0 25 25.0 0.0 diff --git a/doc/src/fix_smd_setvel.rst b/doc/src/fix_smd_setvel.rst index bd14ca1765..bdf97354f5 100644 --- a/doc/src/fix_smd_setvel.rst +++ b/doc/src/fix_smd_setvel.rst @@ -25,9 +25,9 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS - fix top_velocity top_group setvel 1.0 0.0 0.0 + fix top_velocity top_group smd/setvel 1.0 0.0 0.0 Description """"""""""" diff --git a/doc/src/group.rst b/doc/src/group.rst index 87c76f8ee4..42e1d29a85 100644 --- a/doc/src/group.rst +++ b/doc/src/group.rst @@ -48,7 +48,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS group edge region regstrip group water type 3 4 @@ -155,7 +155,7 @@ For example, these lines define a variable "eatom" that calculates the potential energy of each atom and includes it in the group if its potential energy is above the threshold value -3.0. -.. parsed-literal:: +.. code-block:: LAMMPS compute 1 all pe/atom compute 2 all reduce sum c_1 @@ -167,7 +167,7 @@ potential energy is above the threshold value -3.0. Note that these lines -.. parsed-literal:: +.. code-block:: LAMMPS compute 2 all reduce sum c_1 thermo_style custom step temp pe c_2 @@ -266,7 +266,7 @@ used to model a quench of the system, freezing atoms outside the shrinking sphere, then converting the remaining atoms to a static group and running further. -.. parsed-literal:: +.. code-block:: LAMMPS variable nsteps equal 5000 variable rad equal 18-(step/v_nsteps)\*(18-5) diff --git a/doc/src/group2ndx.rst b/doc/src/group2ndx.rst index b8b04ff19c..84e7b6df32 100644 --- a/doc/src/group2ndx.rst +++ b/doc/src/group2ndx.rst @@ -20,7 +20,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS group2ndx allindex.ndx group2ndx someindex.ndx upper lower mobile diff --git a/doc/src/hyper.rst b/doc/src/hyper.rst index 60e5020ad4..d17af1d407 100644 --- a/doc/src/hyper.rst +++ b/doc/src/hyper.rst @@ -32,7 +32,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS compute event all event/displace 1.0 fix HG mobile hyper/global 3.0 0.3 0.4 800.0 diff --git a/doc/src/if.rst b/doc/src/if.rst index 4b7a4dbcbf..fff561bd77 100644 --- a/doc/src/if.rst +++ b/doc/src/if.rst @@ -21,7 +21,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS if "${steps} > 1000" then quit if "${myString} == a10" then quit @@ -75,7 +75,7 @@ above. Note that by using the line continuation character "&", the if command can be spread across many lines, though it is still a single command: -.. parsed-literal:: +.. code-block:: LAMMPS if "$a < $b" then & "print 'Minimum value = $a'" & @@ -99,7 +99,7 @@ checked, so long as it is current on the timestep when the run completes. As explained on the :doc:`variable ` doc page, this can be insured by including the variable in thermodynamic output. -.. parsed-literal:: +.. code-block:: LAMMPS variable myTemp equal temp label loop @@ -115,19 +115,19 @@ Here is an example of a double loop which uses the if and :doc:`jump ` commands to break out of the inner loop when a condition is met, then continues iterating through the outer loop. -.. parsed-literal:: +.. code-block:: LAMMPS label loopa variable a loop 5 label loopb variable b loop 5 - print "A,B = $a,$b" - run 10000 - if "$b > 2" then "jump SELF break" + print "A,B = $a,$b" + run 10000 + if "$b > 2" then "jump SELF break" next b jump in.script loopb - label break - variable b delete + label break + variable b delete next a jump SELF loopa diff --git a/doc/src/include.rst b/doc/src/include.rst index 3721eabff2..e98ffa05e4 100644 --- a/doc/src/include.rst +++ b/doc/src/include.rst @@ -15,7 +15,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS include newfile include in.run2 diff --git a/doc/src/info.rst b/doc/src/info.rst index f83813e637..77d430ea66 100644 --- a/doc/src/info.rst +++ b/doc/src/info.rst @@ -17,7 +17,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS info system info groups computes variables diff --git a/doc/src/jump.rst b/doc/src/jump.rst index d067b53832..d597b336d3 100644 --- a/doc/src/jump.rst +++ b/doc/src/jump.rst @@ -16,7 +16,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS jump newfile jump in.run2 runloop @@ -39,7 +39,7 @@ script is re-opened and read again. The SELF option is not guaranteed to work when the current input script is being read through stdin (standard input), e.g. -.. parsed-literal:: +.. code-block:: bash lmp_g++ < in.script @@ -47,7 +47,7 @@ since the SELF option invokes the C-library rewind() call, which may not be supported for stdin on some systems or by some MPI implementations. This can be worked around by using the :doc:`-in command-line switch `, e.g. -.. parsed-literal:: +.. code-block:: bash lmp_g++ -in in.script @@ -56,7 +56,7 @@ the script name as a variable to the input script. In the latter case, a :doc:`variable ` called "fname" could be used in place of SELF, e.g. -.. parsed-literal:: +.. code-block:: bash lmp_g++ -var fname in.script < in.script @@ -70,7 +70,7 @@ etc. The :doc:`next ` command is used to exit the loop after 10 iterations. When the "a" variable has been incremented for the tenth time, it will cause the next jump command to be skipped. -.. parsed-literal:: +.. code-block:: LAMMPS variable a loop 10 label loop @@ -87,7 +87,7 @@ partitions of 10 procs each. An in.file containing the example variable and jump command will cause each partition to run a different simulation. -.. parsed-literal:: +.. code-block:: LAMMPS mpirun -np 40 lmp_ibm -partition 4x10 -in in.file @@ -101,7 +101,7 @@ checked, so long as it is current on the timestep when the run completes. As explained on the :doc:`variable ` doc page, this can be insured by including the variable in thermodynamic output. -.. parsed-literal:: +.. code-block:: LAMMPS variable myTemp equal temp label loop @@ -117,19 +117,19 @@ Here is an example of a double loop which uses the if and :doc:`jump ` commands to break out of the inner loop when a condition is met, then continues iterating through the outer loop. -.. parsed-literal:: +.. code-block:: LAMMPS label loopa variable a loop 5 label loopb variable b loop 5 - print "A,B = $a,$b" - run 10000 - if "$b > 2" then "jump SELF break" + print "A,B = $a,$b" + run 10000 + if "$b > 2" then "jump SELF break" next b jump in.script loopb - label break - variable b delete + label break + variable b delete next a jump SELF loopa diff --git a/doc/src/label.rst b/doc/src/label.rst index 75c5d2cccc..0b1273008f 100644 --- a/doc/src/label.rst +++ b/doc/src/label.rst @@ -15,7 +15,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS label xyz label loop diff --git a/doc/src/lattice.rst b/doc/src/lattice.rst index 97d20ca181..693d0cd84a 100644 --- a/doc/src/lattice.rst +++ b/doc/src/lattice.rst @@ -38,7 +38,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS lattice fcc 3.52 lattice hex 0.85 @@ -254,11 +254,11 @@ in commands that use the spacings should be decipherable. Example commands for generating a Wurtzite crystal (courtesy of Aidan Thompson), with its 8 atom unit cell. -.. parsed-literal:: +.. code-block:: LAMMPS variable a equal 4.340330 - variable b equal $a\*sqrt(3.0) - variable c equal $a\*sqrt(8.0/3.0) + variable b equal $a*sqrt(3.0) + variable c equal $a*sqrt(8.0/3.0) variable 1_3 equal 1.0/3.0 variable 2_3 equal 2.0/3.0 @@ -304,7 +304,7 @@ Related commands Default """"""" -.. parsed-literal:: +.. code-block:: LAMMPS lattice none 1.0 diff --git a/doc/src/log.rst b/doc/src/log.rst index ab8f1b73d1..5c412d4d9f 100644 --- a/doc/src/log.rst +++ b/doc/src/log.rst @@ -16,7 +16,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS log log.equil log log.equil append diff --git a/doc/src/mass.rst b/doc/src/mass.rst index 4185cfbd7d..55ba9c61bf 100644 --- a/doc/src/mass.rst +++ b/doc/src/mass.rst @@ -16,11 +16,11 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS mass 1 1.0 - mass \* 62.5 - mass 2\* 62.5 + mass * 62.5 + mass 2* 62.5 Description """"""""""" diff --git a/doc/src/message.rst b/doc/src/message.rst index d1c6423e3d..f4ca5735e0 100644 --- a/doc/src/message.rst +++ b/doc/src/message.rst @@ -28,7 +28,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS message client md file tmp.couple message server md file tmp.couple @@ -95,7 +95,7 @@ code's machine. Support for socket messaging is provided by the open-source `ZeroMQ library `_, which must be installed on your system. The client specifies an IP address (IPv4 format) or the DNS name of the machine the server code is running on, -followed by a 4-digit port ID for the socket, separated by a colon. +followed by a 4 or 5 digit port ID for the socket, separated by a colon. E.g. .. parsed-literal:: @@ -110,7 +110,20 @@ what the client specifies. .. note:: - What are allowed port IDs? + On Linux or Unix machines port IDs below 1024 are reserved to the + superuser and thus not available. Other ports may already be in + use and cannot be opened by a second process. On a Linux machine + the commands "netstat -t4an" or "ss -t4an" will list all locally + used port IDs for IPv4 addresses. + +.. note:: + + On many machines (and sometimes on local networks) also ports IDs + may be blocked by default through firewalls. In that case either + access to the required port (or a desired range of ports) has to + be selectively enabled to the firewall disabled (the latter is + usually not a good idea unless you are on a (small) local network + that is already protected from outside access. .. note:: @@ -120,7 +133,7 @@ what the client specifies. For mode *mpi/one*\ , the 2 codes communicate via MPI and are launched by the same mpirun command, e.g. with this syntax for OpenMPI: -.. parsed-literal:: +.. code-block:: bash mpirun -np 2 lmp_mpi -mpicolor 0 -in in.client -log log.client : -np 4 othercode args # LAMMPS is client mpirun -np 2 othercode args : -np 4 lmp_mpi -mpicolor 1 -in in.server # LAMMPS is server diff --git a/doc/src/minimize.rst b/doc/src/minimize.rst index 07fef5ca95..dde5284b7a 100644 --- a/doc/src/minimize.rst +++ b/doc/src/minimize.rst @@ -21,7 +21,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS minimize 1.0e-4 1.0e-6 100 1000 minimize 0.0 1.0e-8 1000 100000 diff --git a/doc/src/molecule.rst b/doc/src/molecule.rst index e25684d6f4..f6839c57df 100644 --- a/doc/src/molecule.rst +++ b/doc/src/molecule.rst @@ -39,7 +39,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS molecule 1 mymol.txt molecule 1 co2.txt h2o.txt diff --git a/doc/src/neb.rst b/doc/src/neb.rst index c7641ed7c2..bd08ae3d1d 100644 --- a/doc/src/neb.rst +++ b/doc/src/neb.rst @@ -34,7 +34,7 @@ keyword = *verbose* Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS neb 0.1 0.0 1000 500 50 final coords.final neb 0.0 0.001 1000 500 50 each coords.initial.$i @@ -147,7 +147,7 @@ For a *file-style* setting of *each*\ , a filename is specified which is assumed to be unique to each replica. This can be done by using a variable in the filename, e.g. -.. parsed-literal:: +.. code-block:: LAMMPS variable i equal part neb 0.0 0.001 1000 500 50 each coords.initial.$i diff --git a/doc/src/neb_spin.rst b/doc/src/neb_spin.rst index 9e9431671a..cbeca25327 100644 --- a/doc/src/neb_spin.rst +++ b/doc/src/neb_spin.rst @@ -38,7 +38,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS neb/spin 0.1 0.0 1000 500 50 final coords.final neb/spin 0.0 0.001 1000 500 50 each coords.initial.$i diff --git a/doc/src/neighbor.rst b/doc/src/neighbor.rst index aa05146805..1bb591587c 100644 --- a/doc/src/neighbor.rst +++ b/doc/src/neighbor.rst @@ -16,7 +16,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS neighbor 0.3 bin neighbor 2.0 nsq diff --git a/doc/src/newton.rst b/doc/src/newton.rst index ca981e917a..df1298a9e4 100644 --- a/doc/src/newton.rst +++ b/doc/src/newton.rst @@ -18,7 +18,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS newton off newton on off @@ -64,6 +64,6 @@ Related commands Default """"""" -.. parsed-literal:: +.. code-block:: LAMMPS newton on diff --git a/doc/src/next.rst b/doc/src/next.rst index 828d6bd0f5..fd62e29ffe 100644 --- a/doc/src/next.rst +++ b/doc/src/next.rst @@ -15,7 +15,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS next x next a t x myTemp @@ -82,7 +82,7 @@ command with an *index*\ -style variable. If this input script is named in.polymer, 8 simulations would be run using data files from directories run1 through run8. -.. parsed-literal:: +.. code-block:: LAMMPS variable d index run1 run2 run3 run4 run5 run6 run7 run8 shell cd $d @@ -103,7 +103,7 @@ finished. Jump and next commands can also be nested to enable multi-level loops. For example, this script will run 15 simulations in a double loop. -.. parsed-literal:: +.. code-block:: LAMMPS variable i loop 3 variable j loop 5 @@ -121,7 +121,7 @@ Here is an example of a double loop which uses the :doc:`if ` and :doc:`jump ` commands to break out of the inner loop when a condition is met, then continues iterating through the outer loop. -.. parsed-literal:: +.. code-block:: LAMMPS label loopa variable a loop 5 diff --git a/doc/src/package.rst b/doc/src/package.rst index a4a70ccb59..059dfba957 100644 --- a/doc/src/package.rst +++ b/doc/src/package.rst @@ -102,7 +102,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS package gpu 1 package gpu 1 split 0.75 @@ -230,7 +230,7 @@ As an example, if you have two GPUs per node and 8 CPU cores per node, and would like to run on 4 nodes (32 cores) with dynamic balancing of force calculation across CPU and GPU cores, you could specify -.. parsed-literal:: +.. code-block:: bash mpirun -np 32 -sf gpu -in in.script # launch command package gpu 2 split -1 # input script command @@ -566,7 +566,7 @@ performance. Here are examples of how to set the environment variable when launching LAMMPS: -.. parsed-literal:: +.. code-block:: bash env OMP_NUM_THREADS=4 lmp_machine -sf omp -in in.script env OMP_NUM_THREADS=2 mpirun -np 2 lmp_machine -sf omp -in in.script diff --git a/doc/src/partition.rst b/doc/src/partition.rst index 7edddb6f92..be333ba581 100644 --- a/doc/src/partition.rst +++ b/doc/src/partition.rst @@ -17,12 +17,12 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS partition yes 1 processors 4 10 6 partition no 5 print "Active partition" - partition yes \*5 fix all nve - partition yes 6\* fix all nvt temp 1.0 1.0 0.1 + partition yes *5 fix all nve + partition yes 6* fix all nvt temp 1.0 1.0 0.1 Description """"""""""" diff --git a/doc/src/prd.rst b/doc/src/prd.rst index d3a9dcf339..d849c8f5a8 100644 --- a/doc/src/prd.rst +++ b/doc/src/prd.rst @@ -39,7 +39,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS prd 5000 100 10 10 100 1 54982 prd 5000 100 10 10 100 1 54982 min 0.1 0.1 100 200 diff --git a/doc/src/print.rst b/doc/src/print.rst index b1a4a681d0..b9ed8555fa 100644 --- a/doc/src/print.rst +++ b/doc/src/print.rst @@ -24,7 +24,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS print "Done with equilibration" file info.dat print Vol=$v append info.dat screen no diff --git a/doc/src/processors.rst b/doc/src/processors.rst index 7c5db5563b..8fe13f69eb 100644 --- a/doc/src/processors.rst +++ b/doc/src/processors.rst @@ -41,15 +41,15 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS - processors \* \* 5 + processors * * 5 processors 2 4 4 - processors \* \* 8 map xyz - processors \* \* \* grid numa - processors \* \* \* grid twolevel 4 \* \* 1 + processors * * 8 map xyz + processors * * * grid numa + processors * * * grid twolevel 4 * * 1 processors 4 8 16 grid custom myfile - processors \* \* \* part 1 2 multiple + processors * * * part 1 2 multiple Description """"""""""" @@ -93,7 +93,7 @@ Px,Py,Pz values for different partitions. You can use the :doc:`partition ` command to specify different processor grids for different partitions, e.g. -.. parsed-literal:: +.. code-block:: LAMMPS partition yes 1 processors 4 4 4 partition yes 2 processors 2 3 2 diff --git a/doc/src/quit.rst b/doc/src/quit.rst index 08b96e28ce..8059232c6a 100644 --- a/doc/src/quit.rst +++ b/doc/src/quit.rst @@ -15,7 +15,7 @@ status = numerical exit status (optional) Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS quit if "$n > 10000" then "quit 1" diff --git a/doc/src/region.rst b/doc/src/region.rst index d791ab8642..f080992311 100644 --- a/doc/src/region.rst +++ b/doc/src/region.rst @@ -72,7 +72,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS region 1 block -3.0 5.0 INF 10.0 INF INF region 2 sphere 0.0 0.0 0.0 5 side out @@ -289,7 +289,7 @@ For example, these commands would displace a region from its initial position, in the positive x direction, effectively at a constant velocity: -.. parsed-literal:: +.. code-block:: LAMMPS variable dx equal ramp(0,10) region 2 sphere 10.0 10.0 0.0 5 move v_dx NULL NULL @@ -299,10 +299,10 @@ Note that the initial displacement is 0.0, though that is not required. Either of these variables would "wiggle" the region back and forth in the y direction: -.. parsed-literal:: +.. code-block:: LAMMPS variable dy equal swiggle(0,5,100) - variable dysame equal 5\*sin(2\*PI\*elaplong\*dt/100) + variable dysame equal 5*sin(2*PI*elaplong*dt/100) region 2 sphere 10.0 10.0 0.0 5 move NULL v_dy NULL The *rotate* keyword rotates the region around a rotation axis *R* = diff --git a/doc/src/replicate.rst b/doc/src/replicate.rst index 8aef4086aa..18038ae2dd 100644 --- a/doc/src/replicate.rst +++ b/doc/src/replicate.rst @@ -21,7 +21,7 @@ nx,ny,nz = replication factors in each dimension Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS replicate 2 3 2 diff --git a/doc/src/rerun.rst b/doc/src/rerun.rst index f604ca51e1..c92947ac6d 100644 --- a/doc/src/rerun.rst +++ b/doc/src/rerun.rst @@ -33,7 +33,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS rerun dump.file dump x y z vx vy vz rerun dump1.txt dump2.txt first 10000 every 1000 dump x y z diff --git a/doc/src/restart.rst b/doc/src/restart.rst index e11fe00971..fbbcdd27b4 100644 --- a/doc/src/restart.rst +++ b/doc/src/restart.rst @@ -29,7 +29,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS restart 0 restart 1000 poly.restart @@ -85,7 +85,7 @@ file via the MPI-IO library, which is part of the MPI standard for versions 2.0 and above. Using MPI-IO requires two steps. First, build LAMMPS with its MPIIO package installed, e.g. -.. parsed-literal:: +.. code-block:: bash make yes-mpiio # installs the MPIIO package make mpi # build LAMMPS for your platform @@ -117,7 +117,7 @@ For example, the following commands will write restart files every step from 1100 to 1200, and could be useful for debugging a simulation where something goes wrong at step 1163: -.. parsed-literal:: +.. code-block:: LAMMPS variable s equal stride(1100,1200,1) restart v_s tmp.restart @@ -180,6 +180,6 @@ Related commands Default """"""" -.. parsed-literal:: +.. code-block:: LAMMPS restart 0 diff --git a/doc/src/run.rst b/doc/src/run.rst index 15c2b3c030..f36fb73187 100644 --- a/doc/src/run.rst +++ b/doc/src/run.rst @@ -31,7 +31,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS run 10000 run 1000000 upto @@ -70,7 +70,7 @@ keywords. For example, consider this fix followed by 10 run commands: -.. parsed-literal:: +.. code-block:: LAMMPS fix 1 all nvt 200.0 300.0 1.0 run 1000 start 0 stop 10000 @@ -144,14 +144,14 @@ of M steps each. After each M-length run, the specified commands are invoked. If only a single command is specified as NULL, then no command is invoked. Thus these lines: -.. parsed-literal:: +.. code-block:: LAMMPS variable q equal x[100] run 6000 every 2000 "print 'Coord = $q'" are the equivalent of: -.. parsed-literal:: +.. code-block:: LAMMPS variable q equal x[100] run 2000 @@ -169,7 +169,7 @@ Note that by using the line continuation character "&", the run every command can be spread across many lines, though it is still a single command: -.. parsed-literal:: +.. code-block:: LAMMPS run 100000 every 1000 & "print 'Minimum value = $a'" & @@ -187,7 +187,7 @@ skipped for intermediate runs. You might wish to specify a command that exits the run by jumping out of the loop, e.g. -.. parsed-literal:: +.. code-block:: LAMMPS variable t equal temp run 10000 every 100 "if '$t < 300.0' then 'jump SELF afterrun'" diff --git a/doc/src/server.rst b/doc/src/server.rst index ce83c4c12a..a25d97ba40 100644 --- a/doc/src/server.rst +++ b/doc/src/server.rst @@ -15,7 +15,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS server md diff --git a/doc/src/server_mc.rst b/doc/src/server_mc.rst index c1ff976ea7..bf02da8e95 100644 --- a/doc/src/server_mc.rst +++ b/doc/src/server_mc.rst @@ -15,7 +15,7 @@ mc = the protocol argument to the :doc:`server ` command Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS server mc diff --git a/doc/src/server_md.rst b/doc/src/server_md.rst index 0782c64258..11b0db6554 100644 --- a/doc/src/server_md.rst +++ b/doc/src/server_md.rst @@ -15,7 +15,7 @@ md = the protocol argument to the :doc:`server ` command Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS server md diff --git a/doc/src/set.rst b/doc/src/set.rst index 790ed5040c..6d81eb1936 100644 --- a/doc/src/set.rst +++ b/doc/src/set.rst @@ -120,16 +120,16 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS set group solvent type 2 set group solvent type/fraction 2 0.5 12393 set group edge bond 4 set region half charge 0.5 set type 3 charge 0.5 - set type 1\*3 charge 0.5 - set atom \* charge v_atomfile - set atom 100\*200 x 0.5 y 1.0 + set type 1*3 charge 0.5 + set atom * charge v_atomfile + set atom 100*200 x 0.5 y 1.0 set atom 100 vx 0.0 vy 0.0 vz -1.0 set atom 1492 type 3 diff --git a/doc/src/shell.rst b/doc/src/shell.rst index 9374a32c9a..08c6a8b635 100644 --- a/doc/src/shell.rst +++ b/doc/src/shell.rst @@ -32,7 +32,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS shell cd sub1 shell cd .. @@ -89,7 +89,7 @@ Any other cmd is passed as-is to the shell along with its arguments as one string, invoked by the C-library system() call. For example, these lines in your input script: -.. parsed-literal:: +.. code-block:: LAMMPS variable n equal 10 variable foo string file2 @@ -97,7 +97,7 @@ these lines in your input script: would be the same as invoking -.. parsed-literal:: +.. code-block:: bash % my_setup file1 10 file2 diff --git a/doc/src/suffix.rst b/doc/src/suffix.rst index f9dd9a32f7..68cbf5d25a 100644 --- a/doc/src/suffix.rst +++ b/doc/src/suffix.rst @@ -16,7 +16,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS suffix off suffix on diff --git a/doc/src/tad.rst b/doc/src/tad.rst index 2a036218a5..b8de42a7eb 100644 --- a/doc/src/tad.rst +++ b/doc/src/tad.rst @@ -41,7 +41,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS tad 2000 50 1800 2300 0.01 0.01 event tad 2000 50 1800 2300 0.01 0.01 event & diff --git a/doc/src/temper.rst b/doc/src/temper.rst index fe0976d28b..3ac6481ff1 100644 --- a/doc/src/temper.rst +++ b/doc/src/temper.rst @@ -21,7 +21,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS temper 100000 100 $t tempfix 0 58728 temper 40000 100 $t tempfix 0 32285 $w @@ -50,7 +50,7 @@ variable previously set in the input script, so that each partition is assigned a different temperature. See the :doc:`variable ` command for more details. For example: -.. parsed-literal:: +.. code-block:: LAMMPS variable t world 300.0 310.0 320.0 330.0 fix myfix all nvt temp $t $t 100.0 @@ -102,10 +102,10 @@ screen.N files as time proceeds. You can have each replica create its own dump file in the following manner: -.. parsed-literal:: +.. code-block:: LAMMPS variable rep world 0 1 2 3 4 5 6 7 - dump 1 all atom 1000 dump.temper.$\ *rep* + dump 1 all atom 1000 dump.temper.${rep} .. note:: @@ -143,7 +143,7 @@ log file listed the following for a simulation with 5 replicas: then a setting of -.. parsed-literal:: +.. code-block:: LAMMPS variable w world 2 4 0 1 3 diff --git a/doc/src/temper_grem.rst b/doc/src/temper_grem.rst index e5103ed39b..c492adfa69 100644 --- a/doc/src/temper_grem.rst +++ b/doc/src/temper_grem.rst @@ -22,10 +22,10 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS - temper/grem 100000 1000 $\ *lambda* fxgREM fxnvt 0 58728 - temper/grem 40000 100 $\ *lambda* fxgREM fxnpt 0 32285 $\ *walkers* + temper/grem 100000 1000 ${lambda} fxgREM fxnvt 0 58728 + temper/grem 40000 100 ${lambda} fxgREM fxnpt 0 32285 ${walkers} Description """"""""""" @@ -47,17 +47,18 @@ has the same dependencies, restraints, and input variables which are discussed there in greater detail. Instead of temperature, this command performs replica exchanges in -lambda as per the generalized ensemble enforced by :doc:`fix grem `. The desired lambda is specified by *lambda*\ , -which is typically a variable previously set in the input script, so -that each partition is assigned a different temperature. See the -:doc:`variable ` command for more details. For example: +lambda as per the generalized ensemble enforced by :doc:`fix grem +`. The desired lambda is specified by *lambda*\ , which is +typically a variable previously set in the input script, so that each +partition is assigned a different temperature. See the :doc:`variable +` command for more details. For example: -.. parsed-literal:: +.. code-block:: LAMMPS variable lambda world 400 420 440 460 fix fxnvt all nvt temp 300.0 300.0 100.0 - fix fxgREM all grem $\ *lambda* -0.05 -50000 fxnvt - temper 100000 100 $\ *lambda* fxgREM fxnvt 3847 58382 + fix fxgREM all grem ${lambda} -0.05 -50000 fxnvt + temper/grem 100000 100 ${lambda} fxgREM fxnvt 3847 58382 would define 4 lambdas with constant kinetic temperature but unique generalized temperature, and assign one of them to :doc:`fix grem ` used by each replica, and to the grem command. @@ -87,12 +88,12 @@ a simulation with 5 replicas: then a setting of -.. parsed-literal:: +.. code-block:: LAMMPS variable walkers world 2 4 0 1 3 would be used to restart the run with a grem command like the example -above with $\ *walkers* as the last argument. This functionality is +above with ${walkers} as the last argument. This functionality is identical to :doc:`temper `. ---------- diff --git a/doc/src/temper_npt.rst b/doc/src/temper_npt.rst index 98ae977696..e0897886f4 100644 --- a/doc/src/temper_npt.rst +++ b/doc/src/temper_npt.rst @@ -22,7 +22,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS temper/npt 100000 100 $t nptfix 0 58728 1 temper/npt 2500000 1000 300 nptfix 0 32285 $p diff --git a/doc/src/thermo.rst b/doc/src/thermo.rst index 5419ca1860..3ab789457e 100644 --- a/doc/src/thermo.rst +++ b/doc/src/thermo.rst @@ -16,7 +16,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS thermo 100 @@ -45,7 +45,7 @@ options for :doc:`equal-style variables `. For example, the following commands will output thermodynamic info at timesteps 0,10,20,30,100,200,300,1000,2000,etc: -.. parsed-literal:: +.. code-block:: LAMMPS variable s equal logfreq(10,3,10) thermo v_s @@ -62,6 +62,6 @@ Related commands Default """"""" -.. parsed-literal:: +.. code-block:: LAMMPS thermo 0 diff --git a/doc/src/timer.rst b/doc/src/timer.rst index 7aa9184622..eac86656af 100644 --- a/doc/src/timer.rst +++ b/doc/src/timer.rst @@ -26,7 +26,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS timer full sync timer timeout 2:00:00 every 100 @@ -125,7 +125,7 @@ Related commands Default """"""" -.. parsed-literal:: +.. code-block:: LAMMPS timer normal nosync timer timeout off diff --git a/doc/src/timestep.rst b/doc/src/timestep.rst index a1f0cea7a9..7ee090740a 100644 --- a/doc/src/timestep.rst +++ b/doc/src/timestep.rst @@ -15,7 +15,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS timestep 2.0 timestep 0.003 diff --git a/doc/src/uncompute.rst b/doc/src/uncompute.rst index 3721bbf614..16efdb86bf 100644 --- a/doc/src/uncompute.rst +++ b/doc/src/uncompute.rst @@ -15,7 +15,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS uncompute 2 uncompute lower-boundary diff --git a/doc/src/undump.rst b/doc/src/undump.rst index 79f0859663..b45e10082b 100644 --- a/doc/src/undump.rst +++ b/doc/src/undump.rst @@ -15,7 +15,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS undump mine undump 2 diff --git a/doc/src/unfix.rst b/doc/src/unfix.rst index 5b74cb7dcb..e5696a1d7d 100644 --- a/doc/src/unfix.rst +++ b/doc/src/unfix.rst @@ -15,7 +15,7 @@ Syntax Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS unfix 2 unfix lower-boundary diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index 7c498d9215..264c3fab50 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -1929,6 +1929,7 @@ Nelement Nelements nemd netcdf +netstat Nettleton Neumann Nevent -- GitLab From de6d1efe7ae79c713c949ebb2eec8f20ef44ad0d Mon Sep 17 00:00:00 2001 From: Giacomo Fiorin Date: Thu, 12 Mar 2020 10:33:48 -0400 Subject: [PATCH 246/689] Remove now unneeded check for C++ standard in Lepton CMake build --- cmake/Modules/Packages/USER-COLVARS.cmake | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/cmake/Modules/Packages/USER-COLVARS.cmake b/cmake/Modules/Packages/USER-COLVARS.cmake index b7fb91917c..a112fbb6aa 100644 --- a/cmake/Modules/Packages/USER-COLVARS.cmake +++ b/cmake/Modules/Packages/USER-COLVARS.cmake @@ -5,22 +5,7 @@ if(PKG_USER-COLVARS) file(GLOB COLVARS_SOURCES ${COLVARS_SOURCE_DIR}/[^.]*.cpp) # Build Lepton by default - set(COLVARS_LEPTON_DEFAULT ON) - # but not if C++11 is disabled per user request - if(DEFINED DISABLE_CXX11_REQUIREMENT) - if(DISABLE_CXX11_REQUIREMENT) - set(COLVARS_LEPTON_DEFAULT OFF) - endif() - endif() - - option(COLVARS_LEPTON "Build and link the Lepton library" ${COLVARS_LEPTON_DEFAULT}) - - # Verify that the user's choice is consistent - if(DEFINED DISABLE_CXX11_REQUIREMENT) - if((DISABLE_CXX11_REQUIREMENT) AND (COLVARS_LEPTON)) - message(FATAL_ERROR "Building the Lepton library requires C++11 or later.") - endif() - endif() + option(COLVARS_LEPTON "Build and link the Lepton library" ON) if(COLVARS_LEPTON) set(LEPTON_DIR ${LAMMPS_LIB_SOURCE_DIR}/colvars/lepton) -- GitLab From 437055f9130b1e083ec78d9a6cceb37503f14189 Mon Sep 17 00:00:00 2001 From: "Jibril B. Coulibaly" Date: Thu, 12 Mar 2020 11:11:38 -0500 Subject: [PATCH 247/689] implement the `scale` keyword of `fix adapt` for diameter and charge --- src/fix_adapt.cpp | 51 ++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/src/fix_adapt.cpp b/src/fix_adapt.cpp index 8668690e1d..10ac290d02 100644 --- a/src/fix_adapt.cpp +++ b/src/fix_adapt.cpp @@ -235,7 +235,7 @@ int FixAdapt::setmask() void FixAdapt::post_constructor() { - if (!resetflag) return; + // Create local Fix Store even when ressetflag == false, to be able to use `scale` keyword for charge and diameter if (!diamflag && !chgflag) return; // new id = fix-ID + FIX_STORE_ATTRIBUTE @@ -251,7 +251,7 @@ void FixAdapt::post_constructor() newarg[4] = (char *) "1"; newarg[5] = (char *) "1"; - if (diamflag) { + if (diamflag && atom->radius_flag) {// Previously unsafe! The radius_flag was not checked, could run an atom_style w/o radius attribute and get here without a previous check / error ! int n = strlen(id) + strlen("_FIX_STORE_DIAM") + 1; id_fix_diam = new char[n]; strcpy(id_fix_diam,id); @@ -274,7 +274,7 @@ void FixAdapt::post_constructor() } } - if (chgflag) { + if (chgflag && atom->q_flag) {// Previously unsafe! The q_flag was not checked, could run an atom_style w/o charge attribute and get here without a previous check / error ! int n = strlen(id) + strlen("_FIX_STORE_CHG") + 1; id_fix_chg = new char[n]; strcpy(id_fix_chg,id); @@ -455,7 +455,7 @@ void FixAdapt::init() } // fixes that store initial per-atom values - + /* Unnecessary ? `fix_diam` and `fix_chg` seem to be already defined in FixAdapt::post_constructor(), commenting them out does not crash my MWE if (id_fix_diam) { int ifix = modify->find_fix(id_fix_diam); if (ifix < 0) error->all(FLERR,"Could not find fix adapt storage fix ID"); @@ -465,7 +465,7 @@ void FixAdapt::init() int ifix = modify->find_fix(id_fix_chg); if (ifix < 0) error->all(FLERR,"Could not find fix adapt storage fix ID"); fix_chg = (FixStore *) modify->fix[ifix]; - } + }*/ if (strstr(update->integrate_style,"respa")) nlevels_respa = ((Respa *) update->integrate)->nlevels; @@ -568,38 +568,39 @@ void FixAdapt::change_settings() // also scale rmass to new value if (ad->aparam == DIAMETER) { - int mflag = 0; - if (atom->rmass_flag) mflag = 1; + /* `mflag` unnecessary ? the test if (!atom->radius_flag) in FixAdapt::init() should perevent `atom->rmass_flag == false`. Unless there can be combinations of atoms with `radius` but without `rmass` + It could also be unsafe since rmass_flag could be added using `fix property/atom` even for an atom_style that does not have radius attributes */ double density; - double *radius = atom->radius; + double *vec = fix_diam->vstore; // Get initial radius to use `scale` keyword + double *radius = atom->radius; double *rmass = atom->rmass; int *mask = atom->mask; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; - if (mflag == 0) { - for (i = 0; i < nall; i++) - if (mask[i] & groupbit) - radius[i] = 0.5*value; - } else { - for (i = 0; i < nall; i++) - if (mask[i] & groupbit) { - density = rmass[i] / (4.0*MY_PI/3.0 * - radius[i]*radius[i]*radius[i]); - radius[i] = 0.5*value; - rmass[i] = 4.0*MY_PI/3.0 * - radius[i]*radius[i]*radius[i] * density; - } - } + for (i = 0; i < nall; i++) + if (mask[i] & groupbit) { + density = rmass[i] / (4.0*MY_PI/3.0 * + radius[i]*radius[i]*radius[i]); + if (scaleflag) radius[i] = value * vec[i]; + else radius[i] = 0.5*value; + rmass[i] = 4.0*MY_PI/3.0 * + radius[i]*radius[i]*radius[i] * density; + } + } else if (ad->aparam == CHARGE) { - double *q = atom->q; + double *vec = fix_chg->vstore; // Get initial charge to use `scale` keyword + double *q = atom->q; int *mask = atom->mask; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; for (i = 0; i < nall; i++) - if (mask[i] & groupbit) q[i] = value; + if (mask[i] & groupbit) { + if (scaleflag) q[i] = value * vec[i]; + else q[i] = value; + } } } } @@ -607,7 +608,7 @@ void FixAdapt::change_settings() modify->addstep_compute(update->ntimestep + nevery); // re-initialize pair styles if any PAIR settings were changed - // ditto for bond styles if any BOND setitings were changes + // ditto for bond styles if any BOND settings were changed // this resets other coeffs that may depend on changed values, // and also offset and tail corrections -- GitLab From c139898f9fad16f79de576cbd9b96ddaf5370783 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 12 Mar 2020 14:26:04 -0400 Subject: [PATCH 248/689] Convert a first set of AtC documentation html files to rst and add infrastructure files and links --- doc/src/Manual.rst | 1 + doc/src/atc_mesh_create.rst | 46 +++++++++++++++++++++++++++++ doc/src/atc_mesh_create_nodeset.rst | 45 ++++++++++++++++++++++++++++ doc/src/atc_mesh_quadrature.rst | 44 +++++++++++++++++++++++++++ doc/src/atc_mesh_read.rst | 46 +++++++++++++++++++++++++++++ doc/src/atc_mesh_write.rst | 43 +++++++++++++++++++++++++++ doc/src/fix_atc.rst | 40 ++++++++++++++++--------- doc/src/fix_modify_atc_commands.rst | 8 +++++ 8 files changed, 259 insertions(+), 14 deletions(-) create mode 100644 doc/src/atc_mesh_create.rst create mode 100644 doc/src/atc_mesh_create_nodeset.rst create mode 100644 doc/src/atc_mesh_quadrature.rst create mode 100644 doc/src/atc_mesh_read.rst create mode 100644 doc/src/atc_mesh_write.rst create mode 100644 doc/src/fix_modify_atc_commands.rst diff --git a/doc/src/Manual.rst b/doc/src/Manual.rst index f805c594c6..a9afb122ad 100644 --- a/doc/src/Manual.rst +++ b/doc/src/Manual.rst @@ -72,6 +72,7 @@ every LAMMPS command. angles dihedrals impropers + fix_modify_atc_commands Indices and tables ================== diff --git a/doc/src/atc_mesh_create.rst b/doc/src/atc_mesh_create.rst new file mode 100644 index 0000000000..404102ccd9 --- /dev/null +++ b/doc/src/atc_mesh_create.rst @@ -0,0 +1,46 @@ +.. index:: fix_modify AtC mesh create + +fix_modify AtC mesh create command +=================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify mesh create + +* AtC fixID = ID of :doc:`fix atc ` instance +* mesh create = name of the AtC sub-command +* nx ny nz = number of elements in x-, y-, and z-direction +* region-ID = ID of region that is to be meshed +* f or p = periodicity flags for x-, y-, and z-direction + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC mesh create 10 1 1 feRegion p p p + +Description +""""""""""" + +Creates a uniform mesh in a rectangular region. + +Restrictions +"""""""""""" + +Creates only uniform rectangular grids in a rectangular region + +Related AtC commands +"""""""""""""""""""" + +:doc:`fix_modify AtC mesh quadrature ` + +Default +""""""" + +When created, the mesh defaults to gauss2 (2-point Gaussian) +quadrature. Use the :doc:`fix_modify AtC mesh quadrature +` command to change the quadrature style. diff --git a/doc/src/atc_mesh_create_nodeset.rst b/doc/src/atc_mesh_create_nodeset.rst new file mode 100644 index 0000000000..854091aa80 --- /dev/null +++ b/doc/src/atc_mesh_create_nodeset.rst @@ -0,0 +1,45 @@ +.. index:: fix_modify AtC mesh create_nodeset + +fix_modify AtC mesh create_nodeset command +========================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify mesh create_nodeset + +* AtC fixID = ID of :doc:`fix atc ` instance +* mesh create\_nodeset = name of the AtC sub-command +* id = id to assign to the collection of FE nodes +* = coordinates of the bounding box that contains only the desired nodes + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC mesh create_nodeset lbc -12.1 -11.9 -12 12 -12 12 + +Description +""""""""""" + +Command to assign an id to a set of FE nodes to be used subsequently in +defining boundary conditions. + +Restrictions +"""""""""""" + +None + +Related AtC commands +"""""""""""""""""""" + +:doc:`fix_modify AtC mesh create ` +:doc:`fix_modify AtC mesh read ` + +Default +""""""" + +Coordinates are assumed to be in lattice units. diff --git a/doc/src/atc_mesh_quadrature.rst b/doc/src/atc_mesh_quadrature.rst new file mode 100644 index 0000000000..4efee0433a --- /dev/null +++ b/doc/src/atc_mesh_quadrature.rst @@ -0,0 +1,44 @@ +.. index:: fix_modify AtC mesh quadrature + +fix_modify AtC mesh quadrature command +====================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify mesh quatrature + +* AtC fixID = ID of :doc:`fix atc ` instance +* mesh quadrature = name of the AtC sub-command +* quad = *nodal* or *gauss1* or *gauss2* or *gauss3* or *face* + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC mesh quadrature face + +Description +""""""""""" + +(Re-)assigns the quadrature style for an existing mesh. When a mesh is +created its quadrature method defaults to gauss2. Use this call to +change it after the fact. + +Restrictions +"""""""""""" + +None. + +Related AtC commands +"""""""""""""""""""" + +:doc:`fix_modify AtC mesh create ` + +Default +""""""" + +None. diff --git a/doc/src/atc_mesh_read.rst b/doc/src/atc_mesh_read.rst new file mode 100644 index 0000000000..b3a6d5e1d7 --- /dev/null +++ b/doc/src/atc_mesh_read.rst @@ -0,0 +1,46 @@ +.. index:: fix_modify AtC mesh read + +fix_modify AtC mesh read command +=================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify mesh read + +* AtC fixID = ID of :doc:`fix atc ` instance +* mesh read = name of the AtC sub-command +* filename = name of the file containing the mesh to be read +* f or p = periodicity flags for x-, y-, and z-direction (optional) + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC mesh read myComponent.mesh p p p + fix_modify AtC mesh read myOtherComponent.exo + +Description +""""""""""" + +Reads a mesh from a text or exodus file, and assigns periodic boundary +conditions if needed. + +Restrictions +"""""""""""" + +None + +Related AtC commands +"""""""""""""""""""" + +:doc:`fix_modify AtC mesh create ` +:doc:`fix_modify AtC mesh write ` + +Default +""""""" + +Periodicity flags are set to false (f) by default. diff --git a/doc/src/atc_mesh_write.rst b/doc/src/atc_mesh_write.rst new file mode 100644 index 0000000000..015c98f519 --- /dev/null +++ b/doc/src/atc_mesh_write.rst @@ -0,0 +1,43 @@ +.. index:: fix_modify AtC mesh write + +fix_modify AtC mesh write command +=================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify mesh write + +* AtC fixID = ID of :doc:`fix atc ` instance +* mesh write = name of the AtC sub-command +* filename = name of the file containing the mesh to be write + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC mesh write myMesh.mesh + +Description +""""""""""" + +Writes a mesh to a text file. + +Restrictions +"""""""""""" + +None + +Related AtC commands +"""""""""""""""""""" + +:doc:`fix_modify AtC mesh create ` +:doc:`fix_modify AtC mesh read ` + +Default +""""""" + +None. diff --git a/doc/src/fix_atc.rst b/doc/src/fix_atc.rst index 3322fda7e7..232adc70f0 100644 --- a/doc/src/fix_atc.rst +++ b/doc/src/fix_atc.rst @@ -36,7 +36,12 @@ Examples Description """"""""""" -This fix is the beginning to creating a coupled FE/MD simulation and/or an on-the-fly estimation of continuum fields. The coupled versions of this fix do Verlet integration and the post-processing does not. After instantiating this fix, several other fix\_modify commands will be needed to set up the problem, e.g. define the finite element mesh and prescribe initial and boundary conditions. +This fix is the beginning to creating a coupled FE/MD simulation and/or +an on-the-fly estimation of continuum fields. The coupled versions of +this fix do Verlet integration and the post-processing does not. After +instantiating this fix, several other fix\_modify commands will be +needed to set up the problem, e.g. define the finite element mesh and +prescribe initial and boundary conditions. .. image:: JPG/atc_nanotube.jpg :align: center @@ -115,17 +120,21 @@ Note coupling and post-processing can be combined in the same simulations using **Restart, fix\_modify, output, run start/stop, minimize info:** -No information about this fix is written to :doc:`binary restart files `. The :doc:`fix_modify ` options -relevant to this fix are listed below. No global scalar or vector or -per-atom quantities are stored by this fix for access by various -:doc:`output commands `. No parameter of this fix can be -used with the *start/stop* keywords of the :doc:`run ` command. -This fix is not invoked during :doc:`energy minimization `. +No information about this fix is written to :doc:`binary restart files +`. The :doc:`fix_modify ` options relevant to this +fix are listed below. No global scalar or vector or per-atom quantities +are stored by this fix for access by various :doc:`output commands +`. No parameter of this fix can be used with the +*start/stop* keywords of the :doc:`run ` command. This fix is not +invoked during :doc:`energy minimization `. Restrictions """""""""""" -Thermal and two\_temperature (coupling) types use a Verlet time-integration algorithm. The hardy type does not contain its own time-integrator and must be used with a separate fix that does contain one, e.g. nve, nvt, etc. In addition, currently: +Thermal and two\_temperature (coupling) types use a Verlet +time-integration algorithm. The hardy type does not contain its own +time-integrator and must be used with a separate fix that does contain +one, e.g. nve, nvt, etc. In addition, currently: * the coupling is restricted to thermal physics * the FE computations are done in serial on each processor. @@ -133,15 +142,18 @@ Thermal and two\_temperature (coupling) types use a Verlet time-integration algo Related commands """""""""""""""" -After specifying this fix in your input script, several other :doc:`fix_modify ` commands are used to setup the problem, e.g. define the finite element mesh and prescribe initial and boundary conditions. +After specifying this fix in your input script, several other +:doc:`fix_modify ` commands are used to setup the problem, +e.g. define the finite element mesh and prescribe initial and boundary +conditions. *fix\_modify* commands for setup: -* `fix_modify AtC mesh create `_ -* `fix_modify AtC mesh quadrature `_ -* `fix_modify AtC mesh read `_ -* `fix_modify AtC mesh write `_ -* `fix_modify AtC mesh create_nodeset `_ +* :doc:`fix_modify AtC mesh create ` +* :doc:`fix_modify AtC mesh quadrature ` +* :doc:`fix_modify AtC mesh read ` +* :doc:`fix_modify AtC mesh write ` +* :doc:`fix_modify AtC mesh create_nodeset ` * `fix_modify AtC mesh add_to_nodeset `_ * `fix_modify AtC mesh create_faceset box `_ * `fix_modify AtC mesh create_faceset plane `_ diff --git a/doc/src/fix_modify_atc_commands.rst b/doc/src/fix_modify_atc_commands.rst new file mode 100644 index 0000000000..ec326b8bf4 --- /dev/null +++ b/doc/src/fix_modify_atc_commands.rst @@ -0,0 +1,8 @@ +fix_modify AtC commands +############################ + +.. toctree:: + :maxdepth: 1 + :glob: + + atc_* -- GitLab From 0a21cdadb587867985575b1a7398ea43179db437 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 12 Mar 2020 15:49:05 -0400 Subject: [PATCH 249/689] converted 4 more fix_modify atc commands --- doc/src/atc_mesh_add_to_nodeset.rst | 44 +++++++++++++++++++ doc/src/atc_mesh_create_faceset_box.rst | 48 +++++++++++++++++++++ doc/src/atc_mesh_create_faceset_plane.rst | 47 ++++++++++++++++++++ doc/src/atc_mesh_create_nodeset.rst | 3 +- doc/src/fix_atc.rst | 6 +-- doc/utils/sphinx-config/false_positives.txt | 9 ++++ 6 files changed, 152 insertions(+), 5 deletions(-) create mode 100644 doc/src/atc_mesh_add_to_nodeset.rst create mode 100644 doc/src/atc_mesh_create_faceset_box.rst create mode 100644 doc/src/atc_mesh_create_faceset_plane.rst diff --git a/doc/src/atc_mesh_add_to_nodeset.rst b/doc/src/atc_mesh_add_to_nodeset.rst new file mode 100644 index 0000000000..579da425da --- /dev/null +++ b/doc/src/atc_mesh_add_to_nodeset.rst @@ -0,0 +1,44 @@ +.. index:: fix_modify AtC mesh add_to_nodeset + +fix_modify AtC mesh add_to_nodeset command +========================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify mesh add_to_nodeset + +* AtC fixID = ID of :doc:`fix atc ` instance +* mesh create\_nodeset = name of the AtC sub-command +* id = id to assign to the collection of FE nodes +* = coordinates of the bounding box that contains the desired nodes to be added + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC mesh add_to_nodeset lbc -12.1 -11.9 -12 12 -12 12 + +Description +""""""""""" + +Command to add nodes to an already existing FE nodeset. + +Restrictions +"""""""""""" + +None + +Related AtC commands +"""""""""""""""""""" + +:doc:`fix_modify AtC mesh create_nodeset ` + + +Default +""""""" + +Coordinates are assumed to be in lattice units. diff --git a/doc/src/atc_mesh_create_faceset_box.rst b/doc/src/atc_mesh_create_faceset_box.rst new file mode 100644 index 0000000000..6915534025 --- /dev/null +++ b/doc/src/atc_mesh_create_faceset_box.rst @@ -0,0 +1,48 @@ +.. index:: fix_modify AtC mesh create_faceset box + +fix_modify AtC mesh create_faceset box command +============================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify mesh create_faceset box [units] + +* AtC fixID = ID of :doc:`fix atc ` instance +* mesh create\_faceset = name of the AtC sub-command +* id = id to assign to the collection of FE faces +* box = use bounding box to define FE faces +* = coordinates of the bounding box that is coincident with the desired FE faces +* = "in" gives inner faces to the box, "out" gives the outer faces to the box +* units = option to specify real as opposed to lattice units + + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC mesh create_faceset obndy box -4.0 4.0 -12 12 -12 12 out + + +Description +""""""""""" + +Command to assign an id to a set of FE faces. + +Restrictions +"""""""""""" + +Only viable for rectangular grids. + +Related AtC commands +"""""""""""""""""""" + +:doc:`fix_modify AtC mesh create_faceset plane ` + +Default +""""""" + +The default options are units = lattice and the use of outer faces. diff --git a/doc/src/atc_mesh_create_faceset_plane.rst b/doc/src/atc_mesh_create_faceset_plane.rst new file mode 100644 index 0000000000..a6b8e53175 --- /dev/null +++ b/doc/src/atc_mesh_create_faceset_plane.rst @@ -0,0 +1,47 @@ +.. index:: fix_modify AtC mesh create_faceset plane + +fix_modify AtC mesh create_faceset plane command +================================================ + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify mesh create_faceset plane [units] + +* AtC fixID = ID of :doc:`fix atc ` instance +* mesh create\_faceset = name of the AtC sub-command +* id = id to assign to the collection of FE faces +* plane = use plane to define faceset +* ,, = plane is specified as the x|y|z=val1 plane bounded by the segments x|y|z = [lval2,uval2] +* units = option to specify real as opposed to lattice units + + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC mesh create_faceset xyplane plane y 0 x -4 0 + + +Description +""""""""""" + +Command to assign an id to a set of FE faces. + +Restrictions +"""""""""""" + +Only viable for rectangular grids. + +Related AtC commands +"""""""""""""""""""" + +:doc:`fix_modify AtC mesh create_faceset box ` + +Default +""""""" + +The default options are units = lattice. diff --git a/doc/src/atc_mesh_create_nodeset.rst b/doc/src/atc_mesh_create_nodeset.rst index 854091aa80..d2e2dd5a9a 100644 --- a/doc/src/atc_mesh_create_nodeset.rst +++ b/doc/src/atc_mesh_create_nodeset.rst @@ -36,8 +36,7 @@ None Related AtC commands """""""""""""""""""" -:doc:`fix_modify AtC mesh create ` -:doc:`fix_modify AtC mesh read ` +:doc:`fix_modify AtC mesh add_to_nodeset ` Default """"""" diff --git a/doc/src/fix_atc.rst b/doc/src/fix_atc.rst index 232adc70f0..165dad223d 100644 --- a/doc/src/fix_atc.rst +++ b/doc/src/fix_atc.rst @@ -154,9 +154,9 @@ conditions. * :doc:`fix_modify AtC mesh read ` * :doc:`fix_modify AtC mesh write ` * :doc:`fix_modify AtC mesh create_nodeset ` -* `fix_modify AtC mesh add_to_nodeset `_ -* `fix_modify AtC mesh create_faceset box `_ -* `fix_modify AtC mesh create_faceset plane `_ +* :doc:`fix_modify AtC mesh add_to_nodeset ` +* :doc:`fix_modify AtC mesh create_faceset box ` +* :doc:`fix_modify AtC mesh create_faceset plane ` * `fix_modify AtC mesh create_elementset `_ * `fix_modify AtC mesh delete_elements `_ * `fix_modify AtC mesh nodeset_to_elementset `_ diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index 264c3fab50..a28b82212f 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -845,6 +845,7 @@ extrema exy ey ez +faceset factorizable factorizations Fahrenberger @@ -1583,6 +1584,7 @@ lucy Luding Lussetti Lustig +lval lwsock lx ly @@ -1980,6 +1982,7 @@ Nocedal nocite nocoeff nodeless +nodeset Noehring noforce Noid @@ -3020,6 +3023,7 @@ util utils utsa Uttormark +uval uvm uwo Uzdin @@ -3180,6 +3184,7 @@ xmax Xmax xmgrace xMIC +xmin xmovie Xmovie xmu @@ -3213,6 +3218,8 @@ yhi yi ylat ylo +ymax +ymin Yoshida ys ysu @@ -3246,6 +3253,8 @@ Ziegenhain Zj zlim zlo +zmax +zmin zmq zN zs -- GitLab From cbd8d07dafeb07b8f9a5a3061ddbcaa6f13a5278 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 12 Mar 2020 16:34:42 -0400 Subject: [PATCH 250/689] convert elementset AtC commands --- doc/src/atc_mesh_create_elementset.rst | 45 +++++++++++++++++++ doc/src/atc_mesh_delete_elements.rst | 43 ++++++++++++++++++ doc/src/atc_mesh_nodeset_to_elementset.rst | 49 +++++++++++++++++++++ doc/src/fix_atc.rst | 6 +-- doc/utils/sphinx-config/false_positives.txt | 1 + 5 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 doc/src/atc_mesh_create_elementset.rst create mode 100644 doc/src/atc_mesh_delete_elements.rst create mode 100644 doc/src/atc_mesh_nodeset_to_elementset.rst diff --git a/doc/src/atc_mesh_create_elementset.rst b/doc/src/atc_mesh_create_elementset.rst new file mode 100644 index 0000000000..f657198751 --- /dev/null +++ b/doc/src/atc_mesh_create_elementset.rst @@ -0,0 +1,45 @@ +.. index:: fix_modify AtC mesh create_elementset + +fix_modify AtC mesh create_elementset command +============================================= + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify mesh create_elementset + +* AtC fixID = ID of :doc:`fix atc ` instance +* mesh create\_elementset = name of the AtC sub-command +* id = id to assign to the collection of FE nodes +* = coordinates of the bounding box that contains only the desired elements + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC mesh create_elementset middle -4.1 4.1 -100 100 -100 1100 + +Description +""""""""""" + +Command to assign an id to a set of FE elements to be used subsequently +in defining material and mesh-based operations. + +Restrictions +"""""""""""" + +Only viable for rectangular grids. + +Related AtC commands +"""""""""""""""""""" + +:doc:`fix_modify AtC mesh delete_elements ` +:doc:`fix_modify AtC mesh nodeset_to_elementset ` + +Default +""""""" + +Coordinates are assumed to be in lattice units. diff --git a/doc/src/atc_mesh_delete_elements.rst b/doc/src/atc_mesh_delete_elements.rst new file mode 100644 index 0000000000..c7f86abfd6 --- /dev/null +++ b/doc/src/atc_mesh_delete_elements.rst @@ -0,0 +1,43 @@ +.. index:: fix_modify AtC mesh delete_elements + +fix_modify AtC mesh delete_elements command +============================================= + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify mesh delete_elements + +* AtC fixID = ID of :doc:`fix atc ` instance +* mesh create\_elementset = name of the AtC sub-command +* id = id of the element set + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC mesh delete_elements gap + +Description +""""""""""" + +Deletes a group of elements from the mesh. + +Restrictions +"""""""""""" + +None. + +Related AtC commands +"""""""""""""""""""" + +:doc:`fix_modify AtC mesh create_elementset ` +:doc:`fix_modify AtC mesh nodeset_to_elementset ` + +Default +""""""" + +None. diff --git a/doc/src/atc_mesh_nodeset_to_elementset.rst b/doc/src/atc_mesh_nodeset_to_elementset.rst new file mode 100644 index 0000000000..0df933aaeb --- /dev/null +++ b/doc/src/atc_mesh_nodeset_to_elementset.rst @@ -0,0 +1,49 @@ +.. index:: fix_modify AtC mesh nodeset_to_elementset + +fix_modify AtC mesh nodeset_to_elementset command +================================================= + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify mesh nodeset_to_elementset + +* AtC fixID = ID of :doc:`fix atc ` instance +* mesh nodeset\_to\_elementset = name of the AtC sub-command +* nodeset\_id = id of desired nodeset from which to create the elementset +* elementset\_id = id to assign to the collection of FE elements +* = flag to choose either the maximal or minimal elementset + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC mesh nodeset_to_elementset myNodeset myElementset min + + +Description +""""""""""" + +Command to create an elementset from an existing nodeset. Either the +minimal element set of elements with all nodes in the set, or maximal +element set with all elements with at least one node in the set, can be +created. + +Restrictions +"""""""""""" + +None. + +Related AtC commands +"""""""""""""""""""" + +:doc:`fix_modify AtC mesh create_elementset ` +:doc:`fix_modify AtC mesh delete_elements ` + +Default +""""""" + +Unless specified, the maximal element set is created. diff --git a/doc/src/fix_atc.rst b/doc/src/fix_atc.rst index 165dad223d..0798dbc033 100644 --- a/doc/src/fix_atc.rst +++ b/doc/src/fix_atc.rst @@ -157,9 +157,9 @@ conditions. * :doc:`fix_modify AtC mesh add_to_nodeset ` * :doc:`fix_modify AtC mesh create_faceset box ` * :doc:`fix_modify AtC mesh create_faceset plane ` -* `fix_modify AtC mesh create_elementset `_ -* `fix_modify AtC mesh delete_elements `_ -* `fix_modify AtC mesh nodeset_to_elementset `_ +* :doc:`fix_modify AtC mesh create_elementset ` +* :doc:`fix_modify AtC mesh delete_elements ` +* :doc:`fix_modify AtC mesh nodeset_to_elementset ` * `fix_modify AtC boundary `_ * `fix_modify AtC internal_quadrature `_ * `fix_modify AtC time_integration (thermal) `_ diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index a28b82212f..61c8b3ab70 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -746,6 +746,7 @@ electronegative electronegativity Eleftheriou ElementN +elementset elif Elj Ellad -- GitLab From 9f537f7f406ee4526a98253a45208dae8c4d8886 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Thu, 12 Mar 2020 11:42:58 -0600 Subject: [PATCH 251/689] cmake: ninja-1.10 supports Fortran now --- cmake/CMakeLists.txt | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index c2357fa059..83b86a7b30 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -587,10 +587,25 @@ if(BUILD_TOOLS) add_executable(binary2txt ${LAMMPS_TOOLS_DIR}/binary2txt.cpp) install(TARGETS binary2txt DESTINATION ${CMAKE_INSTALL_BINDIR}) - # ninja-build currently does not support fortran. thus we skip building this tool + # ninja-build<1.10 does not support fortran. thus we skip building this tool if(CMAKE_GENERATOR STREQUAL "Ninja") - message(STATUS "Skipping building 'chain.x' with Ninja build tool due to lack of Fortran support") + set(CMAKE_GENERATOR_SUPPORT_FORTRAN FALSE) + execute_process(COMMAND "${CMAKE_MAKE_PROGRAM}" --version + OUTPUT_VARIABLE NINJA_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE _Ninja_version_result + ) + if(_Ninja_version_result) + message(WARNING "Unable to determine ninja version: ${_Ninja_version_result}") + elseif(NINJA_VERSION VERSION_LESS "1.10") + message(WARNING "Ninja build tool too old, skipping building 'chain.x' due to lack of Fortran support, please install ninja-1.10 or newer") + else() + set(CMAKE_GENERATOR_SUPPORT_FORTRAN TRUE) + endif() else() + set(CMAKE_GENERATOR_SUPPORT_FORTRAN TRUE) + endif() + if(CMAKE_GENERATOR_SUPPORT_FORTRAN) enable_language(Fortran) add_executable(chain.x ${LAMMPS_TOOLS_DIR}/chain.f) target_link_libraries(chain.x ${CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES}) -- GitLab From 4df25d9c0b80870b1d3a74c71ec45a526dceb608 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 12 Mar 2020 21:27:44 -0400 Subject: [PATCH 252/689] four more subcommands converted --- doc/src/atc_boundary_type.rst | 38 +++++++++++ doc/src/atc_electron_integration.rst | 44 +++++++++++++ doc/src/atc_internal_quadrature.rst | 41 ++++++++++++ doc/src/atc_mesh_create_elementset.rst | 4 +- doc/src/atc_mesh_delete_elements.rst | 4 +- doc/src/atc_mesh_nodeset_to_elementset.rst | 4 +- doc/src/atc_mesh_read.rst | 4 +- doc/src/atc_mesh_write.rst | 4 +- doc/src/atc_time_integration.rst | 77 ++++++++++++++++++++++ doc/src/fix_atc.rst | 9 ++- 10 files changed, 214 insertions(+), 15 deletions(-) create mode 100644 doc/src/atc_boundary_type.rst create mode 100644 doc/src/atc_electron_integration.rst create mode 100644 doc/src/atc_internal_quadrature.rst create mode 100644 doc/src/atc_time_integration.rst diff --git a/doc/src/atc_boundary_type.rst b/doc/src/atc_boundary_type.rst new file mode 100644 index 0000000000..ad4b715532 --- /dev/null +++ b/doc/src/atc_boundary_type.rst @@ -0,0 +1,38 @@ +.. index:: fix_modify AtC boundary type + +fix_modify AtC boundary type command +============================================= + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify boundary type + +* AtC fixID = ID of :doc:`fix atc ` instance +* boundary type = name of the AtC sub-command +* atom-type-id = type id for atoms that represent a fictitious boundary internal to the FE mesh + + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC boundary type ghost_atoms + +Description +""""""""""" + +Command to define the atoms that represent the ficticious boundary internal to the FE mesh. For fully overlapped MD/FE domains with periodic boundary conditions no boundary atoms should be defined. + +Restrictions +"""""""""""" + +None. + +Default +""""""" + +None. diff --git a/doc/src/atc_electron_integration.rst b/doc/src/atc_electron_integration.rst new file mode 100644 index 0000000000..cd9b16ba83 --- /dev/null +++ b/doc/src/atc_electron_integration.rst @@ -0,0 +1,44 @@ +.. index:: fix_modify AtC extrinsic electron_integration + +fix_modify AtC extrinsic electron_integration command +===================================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify extrinsic electron_integration [] + +* AtC fixID = ID of :doc:`fix atc ` instance +* extrinsic electron_integration = name of the AtC sub-command +* integration\_type = *explicit* or *implicit* or *steadydescriptor* +* num\_subcycle\_steps = number of subcycle steps for the electron time integration (optional) + + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC extrinsic electron_integration implicit + fix_modify AtC extrinsic electron_integration explicit 100 + +Description +""""""""""" + +Switches between integration schemes for the electron temperature. The +number of subcyling steps used to integrate the electron temperature for +one LAMMPS timestep can be manually adjusted to capture fast electron +dynamics. + +Restrictions +"""""""""""" + +For use only with the two\_temperature type of the AtC fix (see +:doc:`fix atc ` command) + +Default +""""""" + +*implicit* and *subcycle\_steps* = 1 diff --git a/doc/src/atc_internal_quadrature.rst b/doc/src/atc_internal_quadrature.rst new file mode 100644 index 0000000000..7b503bca8e --- /dev/null +++ b/doc/src/atc_internal_quadrature.rst @@ -0,0 +1,41 @@ +.. index:: fix_modify AtC internal_quadrature + +fix_modify AtC internal_quadrature command +========================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify internal_quadrature [region] + +* AtC fixID = ID of :doc:`fix atc ` instance +* internal_quadrature = name of the AtC sub-command +* on or off = select whether internal quadrature is enabled or not +* region = treat finite elements as within MD region (optional) + + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC internal_quadrature off + +Description +""""""""""" + +Command to use or not use atomic quadrature on internal elements fully +filled with atoms. By turning the internal quadrature off these elements +do not contribute to the governing PDE and the fields at the internal +nodes follow the weighted averages of the atomic data. + +Optional region tag specifies which finite element nodes will be treated +as being within the MD region. This option is only valid with +internal_quadrature off. + +Default +""""""" + +on. diff --git a/doc/src/atc_mesh_create_elementset.rst b/doc/src/atc_mesh_create_elementset.rst index f657198751..d2bc39426a 100644 --- a/doc/src/atc_mesh_create_elementset.rst +++ b/doc/src/atc_mesh_create_elementset.rst @@ -36,8 +36,8 @@ Only viable for rectangular grids. Related AtC commands """""""""""""""""""" -:doc:`fix_modify AtC mesh delete_elements ` -:doc:`fix_modify AtC mesh nodeset_to_elementset ` +- :doc:`fix_modify AtC mesh delete_elements ` +- :doc:`fix_modify AtC mesh nodeset_to_elementset ` Default """"""" diff --git a/doc/src/atc_mesh_delete_elements.rst b/doc/src/atc_mesh_delete_elements.rst index c7f86abfd6..e9e7eed79b 100644 --- a/doc/src/atc_mesh_delete_elements.rst +++ b/doc/src/atc_mesh_delete_elements.rst @@ -34,8 +34,8 @@ None. Related AtC commands """""""""""""""""""" -:doc:`fix_modify AtC mesh create_elementset ` -:doc:`fix_modify AtC mesh nodeset_to_elementset ` +- :doc:`fix_modify AtC mesh create_elementset ` +- :doc:`fix_modify AtC mesh nodeset_to_elementset ` Default """"""" diff --git a/doc/src/atc_mesh_nodeset_to_elementset.rst b/doc/src/atc_mesh_nodeset_to_elementset.rst index 0df933aaeb..da3063b0f1 100644 --- a/doc/src/atc_mesh_nodeset_to_elementset.rst +++ b/doc/src/atc_mesh_nodeset_to_elementset.rst @@ -40,8 +40,8 @@ None. Related AtC commands """""""""""""""""""" -:doc:`fix_modify AtC mesh create_elementset ` -:doc:`fix_modify AtC mesh delete_elements ` +- :doc:`fix_modify AtC mesh create_elementset ` +- :doc:`fix_modify AtC mesh delete_elements ` Default """"""" diff --git a/doc/src/atc_mesh_read.rst b/doc/src/atc_mesh_read.rst index b3a6d5e1d7..7ba4431f84 100644 --- a/doc/src/atc_mesh_read.rst +++ b/doc/src/atc_mesh_read.rst @@ -37,8 +37,8 @@ None Related AtC commands """""""""""""""""""" -:doc:`fix_modify AtC mesh create ` -:doc:`fix_modify AtC mesh write ` +- :doc:`fix_modify AtC mesh create ` +- :doc:`fix_modify AtC mesh write ` Default """"""" diff --git a/doc/src/atc_mesh_write.rst b/doc/src/atc_mesh_write.rst index 015c98f519..c09ba2b87e 100644 --- a/doc/src/atc_mesh_write.rst +++ b/doc/src/atc_mesh_write.rst @@ -34,8 +34,8 @@ None Related AtC commands """""""""""""""""""" -:doc:`fix_modify AtC mesh create ` -:doc:`fix_modify AtC mesh read ` +- :doc:`fix_modify AtC mesh create ` +- :doc:`fix_modify AtC mesh read ` Default """"""" diff --git a/doc/src/atc_time_integration.rst b/doc/src/atc_time_integration.rst new file mode 100644 index 0000000000..438537088a --- /dev/null +++ b/doc/src/atc_time_integration.rst @@ -0,0 +1,77 @@ +.. index:: fix_modify AtC time_integration + +fix_modify AtC time_integration command +============================================= + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify time_integration + +* AtC fixID = ID of :doc:`fix atc ` instance +* time\_integration = name of the AtC sub-command +* descriptor = *gear* or *fractional_step* or *verlet* + + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify atc time_integration fractional_step + + +Description +""""""""""" + +Command to select the thermal or momentum time integration. + +--------- + +Options for thermal time integration: + +*gear* + atomic velocity update with 2nd order Verlet, nodal temperature update + with 3rd or 4th order Gear, thermostats based on controlling power + +*fractional\_step* + atomic velocity update with 2nd order Verlet, mixed nodal temperature + update, 3/4 Gear for continuum and 2 Verlet for atomic contributions, + thermostats based on controlling discrete energy changes + +--------- + +Options for momentum time integration: + +*verlet* + atomic velocity update with 2nd order Verlet, nodal temperature update + with 2nd order Verlet, kinetostats based on controlling force + +*fractional\_step* + atomic velocity update with 2nd order Verlet, mixed nodal momentum + update, 2nd order Verlet for continuum and exact 2nd order Verlet for + atomic contributions, kinetostats based on controlling discrete + momentum changes + +*gear* + atomic velocity update with 2nd order Verlet, nodal temperature update + with 3rd or 4th order Gear, kinetostats based on controlling power. + +--------- + +Restrictions +"""""""""""" + +None. + +Related commands +"""""""""""""""" + +:doc:`fix atc ` + +Default +""""""" + +None. diff --git a/doc/src/fix_atc.rst b/doc/src/fix_atc.rst index 0798dbc033..617ce9ca05 100644 --- a/doc/src/fix_atc.rst +++ b/doc/src/fix_atc.rst @@ -160,11 +160,10 @@ conditions. * :doc:`fix_modify AtC mesh create_elementset ` * :doc:`fix_modify AtC mesh delete_elements ` * :doc:`fix_modify AtC mesh nodeset_to_elementset ` -* `fix_modify AtC boundary `_ -* `fix_modify AtC internal_quadrature `_ -* `fix_modify AtC time_integration (thermal) `_ -* `fix_modify AtC time_integration (momentum) `_ -* `fix_modify AtC extrinsic electron_integration `_ +* :doc:`fix_modify AtC boundary type ` +* :doc:`fix_modify AtC internal_quadrature ` +* :doc:`fix_modify AtC time_integration ` +* :doc:`fix_modify AtC extrinsic electron_integration ` * `fix_modify AtC internal_element_set `_ * `fix_modify AtC decomposition `_ -- GitLab From 3708c9f3f1c7856a1a8da1bbceca88f7ef598c19 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 12 Mar 2020 21:32:06 -0400 Subject: [PATCH 253/689] fix spelling issues --- doc/src/atc_boundary_type.rst | 4 +++- doc/src/atc_electron_integration.rst | 4 ++-- doc/utils/sphinx-config/false_positives.txt | 3 +++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/doc/src/atc_boundary_type.rst b/doc/src/atc_boundary_type.rst index ad4b715532..c18f8cc640 100644 --- a/doc/src/atc_boundary_type.rst +++ b/doc/src/atc_boundary_type.rst @@ -25,7 +25,9 @@ Examples Description """"""""""" -Command to define the atoms that represent the ficticious boundary internal to the FE mesh. For fully overlapped MD/FE domains with periodic boundary conditions no boundary atoms should be defined. +Command to define the atoms that represent the fictitious boundary +internal to the FE mesh. For fully overlapped MD/FE domains with +periodic boundary conditions no boundary atoms should be defined. Restrictions """""""""""" diff --git a/doc/src/atc_electron_integration.rst b/doc/src/atc_electron_integration.rst index cd9b16ba83..83f8efcef3 100644 --- a/doc/src/atc_electron_integration.rst +++ b/doc/src/atc_electron_integration.rst @@ -8,7 +8,7 @@ Syntax .. parsed-literal:: - fix_modify extrinsic electron_integration [] + fix_modify extrinsic electron_integration [] * AtC fixID = ID of :doc:`fix atc ` instance * extrinsic electron_integration = name of the AtC sub-command @@ -28,7 +28,7 @@ Description """"""""""" Switches between integration schemes for the electron temperature. The -number of subcyling steps used to integrate the electron temperature for +number of subcycling steps used to integrate the electron temperature for one LAMMPS timestep can be manually adjusted to capture fast electron dynamics. diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index 61c8b3ab70..393fb39e58 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -1382,6 +1382,7 @@ Khvostov Ki Kikugawa kim +kinetostats kJ kk Klahn @@ -2759,6 +2760,8 @@ Stukowski Su subbox subcutoff +subcycle +subcycling Subramaniyan subscripted subscripting -- GitLab From 0548dbc729ee9dcea73da5fc2bf931ae281f715b Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 12 Mar 2020 22:41:23 -0400 Subject: [PATCH 254/689] a couple more inputs and some formatting tuning/tweaking --- doc/src/atc_atom_element_map.rst | 41 +++++++++++++++++ doc/src/atc_boundary_type.rst | 2 +- doc/src/atc_electron_integration.rst | 8 ++-- doc/src/atc_internal_element_set.rst | 51 +++++++++++++++++++++ doc/src/atc_mesh_add_to_nodeset.rst | 2 +- doc/src/atc_mesh_create_elementset.rst | 2 +- doc/src/atc_mesh_create_faceset_box.rst | 2 +- doc/src/atc_mesh_create_faceset_plane.rst | 2 +- doc/src/atc_mesh_create_nodeset.rst | 2 +- doc/src/atc_mesh_delete_elements.rst | 2 +- doc/src/atc_mesh_nodeset_to_elementset.rst | 6 +-- doc/src/atc_time_integration.rst | 8 ++-- doc/src/fix_atc.rst | 26 +++++------ doc/utils/sphinx-config/false_positives.txt | 1 + 14 files changed, 124 insertions(+), 31 deletions(-) create mode 100644 doc/src/atc_atom_element_map.rst create mode 100644 doc/src/atc_internal_element_set.rst diff --git a/doc/src/atc_atom_element_map.rst b/doc/src/atc_atom_element_map.rst new file mode 100644 index 0000000000..0fe8cdde3a --- /dev/null +++ b/doc/src/atc_atom_element_map.rst @@ -0,0 +1,41 @@ +.. index:: fix_modify AtC atom_element_map + +fix_modify AtC atom_element_map command +======================================= + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify atom_element_map [] + +* AtC fixID = ID of :doc:`fix atc ` instance +* atom_element_map = name of the AtC sub-command +* *eulerian* or *lagrangian* = frame of reference +* frequency = frequency of updating atom-to-continuum maps based on the current configuration - (only for eulerian) + + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify atc atom_element_map eulerian 100 + +Description +""""""""""" + +Changes frame of reference from *eulerian* to *lagrangian* or vice versa +and sets the frequency for which the map from atoms to elements is +reformed and all the attendant data is recalculated. + +Restrictions +"""""""""""" + +Cannot change map type after initialization. + +Default +""""""" + +*lagrangian* diff --git a/doc/src/atc_boundary_type.rst b/doc/src/atc_boundary_type.rst index c18f8cc640..72cd5aeb27 100644 --- a/doc/src/atc_boundary_type.rst +++ b/doc/src/atc_boundary_type.rst @@ -1,7 +1,7 @@ .. index:: fix_modify AtC boundary type fix_modify AtC boundary type command -============================================= +==================================== Syntax """""" diff --git a/doc/src/atc_electron_integration.rst b/doc/src/atc_electron_integration.rst index 83f8efcef3..3bf9a91ba2 100644 --- a/doc/src/atc_electron_integration.rst +++ b/doc/src/atc_electron_integration.rst @@ -12,8 +12,8 @@ Syntax * AtC fixID = ID of :doc:`fix atc ` instance * extrinsic electron_integration = name of the AtC sub-command -* integration\_type = *explicit* or *implicit* or *steadydescriptor* -* num\_subcycle\_steps = number of subcycle steps for the electron time integration (optional) +* integration_type = *explicit* or *implicit* or *steadydescriptor* +* num_subcycle_steps = number of subcycle steps for the electron time integration (optional) Examples @@ -35,10 +35,10 @@ dynamics. Restrictions """""""""""" -For use only with the two\_temperature type of the AtC fix (see +For use only with the two_temperature type of the AtC fix (see :doc:`fix atc ` command) Default """"""" -*implicit* and *subcycle\_steps* = 1 +*implicit* and *subcycle_steps* = 1 diff --git a/doc/src/atc_internal_element_set.rst b/doc/src/atc_internal_element_set.rst new file mode 100644 index 0000000000..8f2c5cd298 --- /dev/null +++ b/doc/src/atc_internal_element_set.rst @@ -0,0 +1,51 @@ +.. index:: fix_modify AtC internal_element_set + +fix_modify AtC internal_element_set command +=========================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify internal_element_set + +* AtC fixID = ID of :doc:`fix atc ` instance +* internal_element_set = name of the AtC sub-command +* element_set_name = name of element set defining internal region, or *off* + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC internal_element_set myElementSet + fix_modify AtC internal_element_set off + +Description +""""""""""" + +Enables AtC to base the region for internal atoms to be an element +set. If no ghost atoms are used, all the AtC atoms must be constrained +to remain in this element set by the user, e.g., with walls. If boundary +atoms are used in conjunction with Eulerian atom maps AtC will partition +all atoms of a boundary or internal type to be of type internal if they +are in the internal region or to be of type boundary otherwise. + +Restrictions +"""""""""""" + +If boundary atoms are used in conjunction with Eulerian atom maps, the +Eulerian reset frequency must be an integer multiple of the Lammps +reneighbor frequency. + +Related AtC Sub-commands +"""""""""""""""""""""""" + +- :doc:`fix_modify AtC atom_element_map ` +- :doc:`fix_modify AtC boundary type ` + +Default +""""""" + +*off* diff --git a/doc/src/atc_mesh_add_to_nodeset.rst b/doc/src/atc_mesh_add_to_nodeset.rst index 579da425da..56fb55b6cb 100644 --- a/doc/src/atc_mesh_add_to_nodeset.rst +++ b/doc/src/atc_mesh_add_to_nodeset.rst @@ -11,7 +11,7 @@ Syntax fix_modify mesh add_to_nodeset * AtC fixID = ID of :doc:`fix atc ` instance -* mesh create\_nodeset = name of the AtC sub-command +* mesh create_nodeset = name of the AtC sub-command * id = id to assign to the collection of FE nodes * = coordinates of the bounding box that contains the desired nodes to be added diff --git a/doc/src/atc_mesh_create_elementset.rst b/doc/src/atc_mesh_create_elementset.rst index d2bc39426a..24408cb830 100644 --- a/doc/src/atc_mesh_create_elementset.rst +++ b/doc/src/atc_mesh_create_elementset.rst @@ -11,7 +11,7 @@ Syntax fix_modify mesh create_elementset * AtC fixID = ID of :doc:`fix atc ` instance -* mesh create\_elementset = name of the AtC sub-command +* mesh create_elementset = name of the AtC sub-command * id = id to assign to the collection of FE nodes * = coordinates of the bounding box that contains only the desired elements diff --git a/doc/src/atc_mesh_create_faceset_box.rst b/doc/src/atc_mesh_create_faceset_box.rst index 6915534025..2a80fae0c1 100644 --- a/doc/src/atc_mesh_create_faceset_box.rst +++ b/doc/src/atc_mesh_create_faceset_box.rst @@ -11,7 +11,7 @@ Syntax fix_modify mesh create_faceset box [units] * AtC fixID = ID of :doc:`fix atc ` instance -* mesh create\_faceset = name of the AtC sub-command +* mesh create_faceset = name of the AtC sub-command * id = id to assign to the collection of FE faces * box = use bounding box to define FE faces * = coordinates of the bounding box that is coincident with the desired FE faces diff --git a/doc/src/atc_mesh_create_faceset_plane.rst b/doc/src/atc_mesh_create_faceset_plane.rst index a6b8e53175..5cf7659ac2 100644 --- a/doc/src/atc_mesh_create_faceset_plane.rst +++ b/doc/src/atc_mesh_create_faceset_plane.rst @@ -11,7 +11,7 @@ Syntax fix_modify mesh create_faceset plane [units] * AtC fixID = ID of :doc:`fix atc ` instance -* mesh create\_faceset = name of the AtC sub-command +* mesh create_faceset = name of the AtC sub-command * id = id to assign to the collection of FE faces * plane = use plane to define faceset * ,, = plane is specified as the x|y|z=val1 plane bounded by the segments x|y|z = [lval2,uval2] diff --git a/doc/src/atc_mesh_create_nodeset.rst b/doc/src/atc_mesh_create_nodeset.rst index d2e2dd5a9a..dd7b8630be 100644 --- a/doc/src/atc_mesh_create_nodeset.rst +++ b/doc/src/atc_mesh_create_nodeset.rst @@ -11,7 +11,7 @@ Syntax fix_modify mesh create_nodeset * AtC fixID = ID of :doc:`fix atc ` instance -* mesh create\_nodeset = name of the AtC sub-command +* mesh create_nodeset = name of the AtC sub-command * id = id to assign to the collection of FE nodes * = coordinates of the bounding box that contains only the desired nodes diff --git a/doc/src/atc_mesh_delete_elements.rst b/doc/src/atc_mesh_delete_elements.rst index e9e7eed79b..dfab9677b7 100644 --- a/doc/src/atc_mesh_delete_elements.rst +++ b/doc/src/atc_mesh_delete_elements.rst @@ -11,7 +11,7 @@ Syntax fix_modify mesh delete_elements * AtC fixID = ID of :doc:`fix atc ` instance -* mesh create\_elementset = name of the AtC sub-command +* mesh create_elementset = name of the AtC sub-command * id = id of the element set Examples diff --git a/doc/src/atc_mesh_nodeset_to_elementset.rst b/doc/src/atc_mesh_nodeset_to_elementset.rst index da3063b0f1..a1ec879787 100644 --- a/doc/src/atc_mesh_nodeset_to_elementset.rst +++ b/doc/src/atc_mesh_nodeset_to_elementset.rst @@ -11,9 +11,9 @@ Syntax fix_modify mesh nodeset_to_elementset * AtC fixID = ID of :doc:`fix atc ` instance -* mesh nodeset\_to\_elementset = name of the AtC sub-command -* nodeset\_id = id of desired nodeset from which to create the elementset -* elementset\_id = id to assign to the collection of FE elements +* mesh nodeset_to_elementset = name of the AtC sub-command +* nodeset_id = id of desired nodeset from which to create the elementset +* elementset_id = id to assign to the collection of FE elements * = flag to choose either the maximal or minimal elementset Examples diff --git a/doc/src/atc_time_integration.rst b/doc/src/atc_time_integration.rst index 438537088a..0780ece4fb 100644 --- a/doc/src/atc_time_integration.rst +++ b/doc/src/atc_time_integration.rst @@ -1,7 +1,7 @@ .. index:: fix_modify AtC time_integration fix_modify AtC time_integration command -============================================= +======================================= Syntax """""" @@ -11,7 +11,7 @@ Syntax fix_modify time_integration * AtC fixID = ID of :doc:`fix atc ` instance -* time\_integration = name of the AtC sub-command +* time_integration = name of the AtC sub-command * descriptor = *gear* or *fractional_step* or *verlet* @@ -36,7 +36,7 @@ Options for thermal time integration: atomic velocity update with 2nd order Verlet, nodal temperature update with 3rd or 4th order Gear, thermostats based on controlling power -*fractional\_step* +*fractional_step* atomic velocity update with 2nd order Verlet, mixed nodal temperature update, 3/4 Gear for continuum and 2 Verlet for atomic contributions, thermostats based on controlling discrete energy changes @@ -49,7 +49,7 @@ Options for momentum time integration: atomic velocity update with 2nd order Verlet, nodal temperature update with 2nd order Verlet, kinetostats based on controlling force -*fractional\_step* +*fractional_step* atomic velocity update with 2nd order Verlet, mixed nodal momentum update, 2nd order Verlet for continuum and exact 2nd order Verlet for atomic contributions, kinetostats based on controlling discrete diff --git a/doc/src/fix_atc.rst b/doc/src/fix_atc.rst index 617ce9ca05..6ad61f48b4 100644 --- a/doc/src/fix_atc.rst +++ b/doc/src/fix_atc.rst @@ -12,7 +12,7 @@ Syntax * fixID = name of fix * group = name of group fix is to be applied -* type = *thermal* or *two\_temperature* or *hardy* or *field* +* type = *thermal* or *two_temperature* or *hardy* or *field* .. parsed-literal:: @@ -21,7 +21,7 @@ Syntax *hardy* = on-the-fly post-processing using kernel localization functions (see "related" section for possible fields) *field* = on-the-fly post-processing using mesh-based localization functions (see "related" section for possible fields) -* parameter\_file = name of the file with material parameters. Note: Neither hardy nor field requires a parameter file +* parameter_file = name of the file with material parameters. Note: Neither hardy nor field requires a parameter file Examples """""""" @@ -39,7 +39,7 @@ Description This fix is the beginning to creating a coupled FE/MD simulation and/or an on-the-fly estimation of continuum fields. The coupled versions of this fix do Verlet integration and the post-processing does not. After -instantiating this fix, several other fix\_modify commands will be +instantiating this fix, several other fix_modify commands will be needed to set up the problem, e.g. define the finite element mesh and prescribe initial and boundary conditions. @@ -118,7 +118,7 @@ Note coupling and post-processing can be combined in the same simulations using ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. The :doc:`fix_modify ` options relevant to this @@ -131,7 +131,7 @@ invoked during :doc:`energy minimization `. Restrictions """""""""""" -Thermal and two\_temperature (coupling) types use a Verlet +Thermal and two_temperature (coupling) types use a Verlet time-integration algorithm. The hardy type does not contain its own time-integrator and must be used with a separate fix that does contain one, e.g. nve, nvt, etc. In addition, currently: @@ -147,7 +147,7 @@ After specifying this fix in your input script, several other e.g. define the finite element mesh and prescribe initial and boundary conditions. -*fix\_modify* commands for setup: +*fix_modify* commands for setup: * :doc:`fix_modify AtC mesh create ` * :doc:`fix_modify AtC mesh quadrature ` @@ -164,10 +164,10 @@ conditions. * :doc:`fix_modify AtC internal_quadrature ` * :doc:`fix_modify AtC time_integration ` * :doc:`fix_modify AtC extrinsic electron_integration ` -* `fix_modify AtC internal_element_set `_ +* :doc:`fix_modify AtC internal_element_set ` * `fix_modify AtC decomposition `_ -*fix\_modify* commands for boundary and initial conditions: +*fix_modify* commands for boundary and initial conditions: * `fix_modify AtC initial `_ * `fix_modify AtC fix `_ @@ -177,7 +177,7 @@ conditions. * `fix_modify AtC source `_ * `fix_modify AtC remove_source `_ -*fix\_modify* commands for control and filtering: +*fix_modify* commands for control and filtering: * `fix_modify AtC control `_ * `fix_modify AtC control thermal `_ @@ -193,7 +193,7 @@ conditions. * `fix_modify AtC extrinsic exchange `_ * `fix_modify AtC poisson_solver `_ -*fix\_modify* commands for output: +*fix_modify* commands for output: * `fix_modify AtC output `_ * `fix_modify AtC output nodeset `_ @@ -204,7 +204,7 @@ conditions. * `fix_modify AtC write_restart `_ * `fix_modify AtC read_restart `_ -*fix\_modify* commands for post-processing: +*fix_modify* commands for post-processing: * `fix_modify AtC kernel `_ * `fix_modify AtC fields `_ @@ -216,9 +216,9 @@ conditions. * `fix_modify AtC sample_frequency `_ * `fix_modify AtC set `_ -miscellaneous *fix\_modify* commands: +miscellaneous *fix_modify* commands: -* `fix_modify AtC atom_element_map `_ +* :doc:`fix_modify AtC atom_element_map ` * `fix_modify AtC atom_weight `_ * `fix_modify AtC write_atom_weights `_ * `fix_modify AtC reset_time `_ diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index 393fb39e58..81c2bb3789 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -826,6 +826,7 @@ ethernet etol etot etotal +Eulerian eulerimplicit Europhys ev -- GitLab From 357467390118cdce5bd4afa5f318f6ed97dfb2f0 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 13 Mar 2020 05:15:35 -0400 Subject: [PATCH 255/689] four more atc subcommand doc files converted --- doc/src/atc_decomposition.rst | 43 ++++++++++++++++++++ doc/src/atc_fix.rst | 45 +++++++++++++++++++++ doc/src/atc_initial.rst | 39 ++++++++++++++++++ doc/src/atc_unfix.rst | 43 ++++++++++++++++++++ doc/src/fix_atc.rst | 8 ++-- doc/utils/sphinx-config/false_positives.txt | 1 + 6 files changed, 175 insertions(+), 4 deletions(-) create mode 100644 doc/src/atc_decomposition.rst create mode 100644 doc/src/atc_fix.rst create mode 100644 doc/src/atc_initial.rst create mode 100644 doc/src/atc_unfix.rst diff --git a/doc/src/atc_decomposition.rst b/doc/src/atc_decomposition.rst new file mode 100644 index 0000000000..2a056bab78 --- /dev/null +++ b/doc/src/atc_decomposition.rst @@ -0,0 +1,43 @@ +.. index:: fix_modify AtC decomposition + +fix_modify AtC decomposition command +==================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify decomposition + +* AtC fixID = ID of :doc:`fix atc ` instance +* decomposition = name of the AtC sub-command +* type = *replicated_memory* or *distributed_memory* + + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC decomposition distributed_memory + +Description +""""""""""" + +Command for assigning the distribution of work and memory for parallel +runs. With *replicated_memory* the nodal information is replicated on +each processor, and with *distributed_memory* only the owned nodal +information kept on each processor. The *replicated_memory* option +is most appropriate for simulations were the number of nodes is much +smaller than the number of atoms. + +Restrictions +"""""""""""" + +None. + +Default +""""""" + +replicated_memory diff --git a/doc/src/atc_fix.rst b/doc/src/atc_fix.rst new file mode 100644 index 0000000000..e0b8141b8f --- /dev/null +++ b/doc/src/atc_fix.rst @@ -0,0 +1,45 @@ +.. index:: fix_modify AtC fix + +fix_modify AtC initial command +============================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify fix + +* AtC fixID = ID of :doc:`fix atc ` instance +* fix = name of the AtC sub-command +* field = field kind name valid for type of physics: *temperature* or *electron_temperature* +* nodeset = name of set of nodes to apply boundary condition +* *constant* or *function* = value or name of function followed by its parameters + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC fix temperature groupNAME 10. + fix_modify AtC fix temperature groupNAME 0 0 0 10.0 0 0 1.0 + +Description +""""""""""" + +Creates a constraint on the values of the specified field at specified nodes. + +Restrictions +"""""""""""" + +The keyword *all* is reserved and thus not available as nodeset name. + +Related AtC commands +"""""""""""""""""""" + +:doc:`fix_modify AtC unfix ` + +Default +""""""" + +None. diff --git a/doc/src/atc_initial.rst b/doc/src/atc_initial.rst new file mode 100644 index 0000000000..ab0f922a6c --- /dev/null +++ b/doc/src/atc_initial.rst @@ -0,0 +1,39 @@ +.. index:: fix_modify AtC initial + +fix_modify AtC initial command +==================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify initial + +* AtC fixID = ID of :doc:`fix atc ` instance +* initial = name of the AtC sub-command +* field = field kind name valid for type of physics: *temperature* or *electron_temperature* +* nodeset = name of set of nodes to apply initial condition +* *constant* or *function* = value or name of function followed by its parameters + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify atc initial temperature groupNAME 10. + +Description +""""""""""" + +Sets the initial values for the specified field at the specified nodes. + +Restrictions +"""""""""""" + +The keyword *all* is reserved and thus not available as nodeset name. + +Default +""""""" + +None. diff --git a/doc/src/atc_unfix.rst b/doc/src/atc_unfix.rst new file mode 100644 index 0000000000..0e340eecd3 --- /dev/null +++ b/doc/src/atc_unfix.rst @@ -0,0 +1,43 @@ +.. index:: fix_modify AtC unfix + +fix_modify AtC initial command +============================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify unfix + +* AtC fixID = ID of :doc:`fix atc ` instance +* unfix = name of the AtC sub-command +* field = field kind name valid for type of physics: *temperature* or *electron_temperature* +* nodeset = name of set of nodes to apply boundary condition + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC unfix temperature groupNAME + +Description +""""""""""" + +Removes constraint on field values for specified nodes. + +Restrictions +"""""""""""" + +The keyword *all* is reserved and thus not available as nodeset name. + +Related AtC commands +"""""""""""""""""""" + +:doc:`fix_modify AtC fix ` + +Default +""""""" + +None. diff --git a/doc/src/fix_atc.rst b/doc/src/fix_atc.rst index 6ad61f48b4..78d6793a96 100644 --- a/doc/src/fix_atc.rst +++ b/doc/src/fix_atc.rst @@ -165,13 +165,13 @@ conditions. * :doc:`fix_modify AtC time_integration ` * :doc:`fix_modify AtC extrinsic electron_integration ` * :doc:`fix_modify AtC internal_element_set ` -* `fix_modify AtC decomposition `_ +* :doc:`fix_modify AtC decomposition ` *fix_modify* commands for boundary and initial conditions: -* `fix_modify AtC initial `_ -* `fix_modify AtC fix `_ -* `fix_modify AtC unfix `_ +* :doc:`fix_modify AtC initial ` +* :doc:`fix_modify AtC fix ` +* :doc:`fix_modify AtC unfix ` * `fix_modify AtC fix_flux `_ * `fix_modify AtC unfix_flux `_ * `fix_modify AtC source `_ diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index 81c2bb3789..0685c3582b 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -827,6 +827,7 @@ etol etot etotal Eulerian +eulerian eulerimplicit Europhys ev -- GitLab From 5a81f694950e6bf4246f1f1fbb50e7cd838c7a0d Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 13 Mar 2020 10:19:12 -0400 Subject: [PATCH 256/689] next set of converted AtC documentation --- doc/src/atc_control_momentum.rst | 77 ++++++++++++++++++++++++ doc/src/atc_control_thermal.rst | 87 ++++++++++++++++++++++++++++ doc/src/atc_fix.rst | 4 +- doc/src/atc_fix_flux.rst | 47 +++++++++++++++ doc/src/atc_internal_element_set.rst | 4 +- doc/src/atc_remove_source.rst | 43 ++++++++++++++ doc/src/atc_source.rst | 47 +++++++++++++++ doc/src/atc_unfix.rst | 2 +- doc/src/atc_unfix_flux.rst | 44 ++++++++++++++ doc/src/fix_atc.rst | 14 ++--- 10 files changed, 356 insertions(+), 13 deletions(-) create mode 100644 doc/src/atc_control_momentum.rst create mode 100644 doc/src/atc_control_thermal.rst create mode 100644 doc/src/atc_fix_flux.rst create mode 100644 doc/src/atc_remove_source.rst create mode 100644 doc/src/atc_source.rst create mode 100644 doc/src/atc_unfix_flux.rst diff --git a/doc/src/atc_control_momentum.rst b/doc/src/atc_control_momentum.rst new file mode 100644 index 0000000000..69790a79ab --- /dev/null +++ b/doc/src/atc_control_momentum.rst @@ -0,0 +1,77 @@ +.. index:: fix_modify AtC control momentum + +fix_modify AtC control momentum command +======================================= + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify control + fix_modify AtC control momentum none + fix_modify AtC control momentum rescale + fix_modify AtC control momentum glc_displacement + fix_modify AtC control momentum glc_velocity + fix_modify AtC control momentum hoover + fix_modify AtC control momentum flux [faceset face_set_id, interpolate] + +* AtC fixID = ID of :doc:`fix atc ` instance +* control = name of the AtC sub-command +* physics_type = *thermal* or *momentum* +* solution_parameter = *max_iterations* or *tolerance* +* value = solution_parameter value +* momentum option = *none* or *rescale* or *glc_displacement* or *glc_velocity* *hoover* or *flux* +* frequency = time step frequency for applying displacement and velocity rescaling +* faceset_id = id of boundary face set (optional, only for *faceset*) + + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC control momentum none + fix_modify AtC control momentum flux faceset bndy_faces + fix_modify AtC control momentum glc_velocity + +Description +""""""""""" + +The general version of *control* sets the numerical parameters for the +matrix solvers used in the specified control algorithm. Many solution +approaches require iterative solvers, and these methods enable users to +provide the maximum number of iterations and the relative tolerance. + +The *control momentum* version sets the momentum exchange mechanism from +the finite elements to the atoms, managed through a control algorithm. +*rescale* computes a scale factor for each atom to match the finite +element temperature. *hoover* is a Gaussian least-constraint isokinetic +thermostat enforces that the nodal restricted atomic temperature matches +the finite element temperature. *flux* is a similar mode, but rather +adds energy to the atoms based on conservation of energy. + +*correction_max_iterations* sets the maximum number of iterations to +compute the 2nd order in time correction term for lambda with the +fractional step method. The method uses the same tolerance as the +controller's matrix solver. + +Restrictions +"""""""""""" + +Only for be used with the specific controllers *thermal* or *momentum*. +They are ignored if a lumped solution is requested. + +*control momentum* is only for be used with specific transfers: elastic +*rescale* not valid with time filtering activated + +Related AtC commands +"""""""""""""""""""" + +:doc:`fix_modify AtC control thermal ` + +Default +""""""" + +- *max_iterations* is the number of rows in the matrix. +- *tolerance* is 1.0e-10. diff --git a/doc/src/atc_control_thermal.rst b/doc/src/atc_control_thermal.rst new file mode 100644 index 0000000000..0cd4904e2d --- /dev/null +++ b/doc/src/atc_control_thermal.rst @@ -0,0 +1,87 @@ +.. index:: fix_modify AtC control thermal + +fix_modify AtC control thermal command +====================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify control + fix_modify control thermal + fix_modify control thermal rescale + fix_modify control thermal flux + fix_modify control thermal correction_max_iterations + +* AtC fixID = ID of :doc:`fix atc ` instance +* control = name of the AtC sub-command +* physics_type = *thermal* or *momentum* +* solution_parameter = *max_iterations* or *tolerance* +* value = solution_parameter value +* thermal control_type = *none* or *rescale* or *hoover* or *flux* +* frequency = time step frequency for applying velocity rescaling +* boundary_integration_type = *faceset* or *interpolate* (optional) +* faceset_id = id of boundary face set (optional, only for *faceset*) +* correction_max_iterations = maximum number of iterations that will be used by iterative matrix solvers for *thermal* physics type + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC control thermal none + fix_modify AtC control thermal rescale 10 + fix_modify AtC control thermal hoover + fix_modify AtC control thermal flux + fix_modify AtC control thermal flux faceset bndy_faces + fix_modify AtC control thermal correction_max_iterations 10 + +Description +""""""""""" + +The general version of *control* sets the numerical parameters for the +matrix solvers used in the specified control algorithm. Many solution +approaches require iterative solvers, and these methods enable users to +provide the maximum number of iterations and the relative tolerance. + +The *control thermal* version sets the energy exchange mechanism from +the finite elements to the atoms, managed through a control algorithm. +*rescale* computes a scale factor for each atom to match the finite +element temperature. *hoover* is a Gaussian least-constraint isokinetic +thermostat enforces that the nodal restricted atomic temperature matches +the finite element temperature. *flux* is a similar mode, but rather +adds energy to the atoms based on conservation of energy. *hoover* and +*flux* allow the prescription of sources or fixed temperatures on the +atoms. + +*correction_max_iterations* sets the maximum number of iterations to +compute the 2nd order in time correction term for lambda with the +fractional step method. The method uses the same tolerance as the +controller's matrix solver. + +Restrictions +"""""""""""" + +Only for be used with the specific controllers *thermal* or *momentum*. +They are ignored if a lumped solution is requested. + +*control thermal* is only for be used with specific transfers: thermal (*rescale*\ , *hoover*\ , *flux*\ ), *two_temperature* (*flux*\ ). +*rescale* not valid with time filtering activated + +*correction_max_iterations* is only for use with *thermal* physics using +the fractional step method. + +Related AtC commands +"""""""""""""""""""" + +:doc:`fix_modify AtC control momentum ` + +Default +""""""" + +- *max_iterations* is the number of rows in the matrix. +- *tolerance* is 1.0e-10. +- *rescale* frequency is 1 +- *flux* boundary_integration_type is *interpolate* +- *correction_max_iterations* is 20 diff --git a/doc/src/atc_fix.rst b/doc/src/atc_fix.rst index e0b8141b8f..4e955ea4e4 100644 --- a/doc/src/atc_fix.rst +++ b/doc/src/atc_fix.rst @@ -1,7 +1,7 @@ .. index:: fix_modify AtC fix -fix_modify AtC initial command -============================== +fix_modify AtC fix command +========================== Syntax """""" diff --git a/doc/src/atc_fix_flux.rst b/doc/src/atc_fix_flux.rst new file mode 100644 index 0000000000..461d615162 --- /dev/null +++ b/doc/src/atc_fix_flux.rst @@ -0,0 +1,47 @@ +.. index:: fix_modify AtC fix_flux + +fix_modify AtC fix_flux command +=============================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify fix_flux + +* AtC fixID = ID of :doc:`fix atc ` instance +* fix_flux = name of the AtC sub-command +* field = field kind name valid for type of physics: *temperature* or *electron_temperature* +* face_set = name of set of element faces +* *value* or *function* = value or name of function followed by its parameters + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC fix_flux temperature faceSet 10.0 + +Description +""""""""""" + +Command for fixing normal fluxes e.g. heat_flux. This command only +prescribes the normal component of the physical flux, e.g. heat (energy) +flux. The units are in AtC units, i.e. derived from the LAMMPS length, +time, and mass scales. + +Restrictions +"""""""""""" + +Only normal fluxes (Neumann data) can be prescribed. + +Related AtC commands +"""""""""""""""""""" + +:doc:`fix_modify AtC unfix_flux ` + +Default +""""""" + +None. diff --git a/doc/src/atc_internal_element_set.rst b/doc/src/atc_internal_element_set.rst index 8f2c5cd298..8dfa55eadb 100644 --- a/doc/src/atc_internal_element_set.rst +++ b/doc/src/atc_internal_element_set.rst @@ -39,8 +39,8 @@ If boundary atoms are used in conjunction with Eulerian atom maps, the Eulerian reset frequency must be an integer multiple of the Lammps reneighbor frequency. -Related AtC Sub-commands -"""""""""""""""""""""""" +Related AtC commands +"""""""""""""""""""" - :doc:`fix_modify AtC atom_element_map ` - :doc:`fix_modify AtC boundary type ` diff --git a/doc/src/atc_remove_source.rst b/doc/src/atc_remove_source.rst new file mode 100644 index 0000000000..587d04731b --- /dev/null +++ b/doc/src/atc_remove_source.rst @@ -0,0 +1,43 @@ +.. index:: fix_modify AtC remove_source + +fix_modify AtC remove_source command +==================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify remove_source + +* AtC fixID = ID of :doc:`fix atc ` instance +* remove_source = name of the AtC sub-command +* field = field kind name valid for type of physics: *temperature* or *electron_temperature* +* element_set = name of set of elements + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC remove_source temperature groupNAME + +Description +""""""""""" + +Remove a domain source. + +Restrictions +"""""""""""" + +The keyword *all* is reserved and thus not available as element_set name. + +Related AtC commands +"""""""""""""""""""" + +:doc:`fix_modify AtC source ` + +Default +""""""" + +None. diff --git a/doc/src/atc_source.rst b/doc/src/atc_source.rst new file mode 100644 index 0000000000..9c3849070f --- /dev/null +++ b/doc/src/atc_source.rst @@ -0,0 +1,47 @@ +.. index:: fix_modify AtC source + +fix_modify AtC source command +============================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify source + +* AtC fixID = ID of :doc:`fix atc ` instance +* source = name of the AtC sub-command +* field = field kind name valid for type of physics: *temperature* or *electron_temperature* +* element_set = name of set of elements +* *value* or *function* = value or name of function followed by its parameters + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC source temperature middle temporal_ramp 10.0 0.0 + +Description +""""""""""" + +Add domain sources to the mesh. The units are consistent with LAMMPS's +units for mass, length and time and are defined by the PDE being solved, +e.g. for thermal transfer the balance equation is for energy and source +is energy per time. + +Restrictions +"""""""""""" + +The keyword *all* is reserved and thus not available as element_set name. + +Related AtC commands +"""""""""""""""""""" + +:doc:`fix_modify AtC remove_source ` + +Default +""""""" + +None. diff --git a/doc/src/atc_unfix.rst b/doc/src/atc_unfix.rst index 0e340eecd3..1241d51bae 100644 --- a/doc/src/atc_unfix.rst +++ b/doc/src/atc_unfix.rst @@ -1,6 +1,6 @@ .. index:: fix_modify AtC unfix -fix_modify AtC initial command +fix_modify AtC unfix command ============================== Syntax diff --git a/doc/src/atc_unfix_flux.rst b/doc/src/atc_unfix_flux.rst new file mode 100644 index 0000000000..a756f63a75 --- /dev/null +++ b/doc/src/atc_unfix_flux.rst @@ -0,0 +1,44 @@ +.. index:: fix_modify AtC unfix_flux + +fix_modify AtC unfix_flux command +================================= + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify unfix_flux + +* AtC fixID = ID of :doc:`fix atc ` instance +* unfix_flux = name of the AtC sub-command +* field = field kind name valid for type of physics: *temperature* or *electron_temperature* +* face_set = name of set of element faces + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC unfix_flux temperature faceSet + +Description +""""""""""" + +Command for removing prescribed normal fluxes e.g. heat_flux, stress. + + +Restrictions +"""""""""""" + +None. + +Related AtC commands +"""""""""""""""""""" + +:doc:`fix_modify AtC fix_flux ` + +Default +""""""" + +None. diff --git a/doc/src/fix_atc.rst b/doc/src/fix_atc.rst index 78d6793a96..b22d3359d1 100644 --- a/doc/src/fix_atc.rst +++ b/doc/src/fix_atc.rst @@ -172,17 +172,15 @@ conditions. * :doc:`fix_modify AtC initial ` * :doc:`fix_modify AtC fix ` * :doc:`fix_modify AtC unfix ` -* `fix_modify AtC fix_flux `_ -* `fix_modify AtC unfix_flux `_ -* `fix_modify AtC source `_ -* `fix_modify AtC remove_source `_ +* :doc:`fix_modify AtC fix_flux ` +* :doc:`fix_modify AtC unfix_flux ` +* :doc:`fix_modify AtC source ` +* :doc:`fix_modify AtC remove_source ` *fix_modify* commands for control and filtering: -* `fix_modify AtC control `_ -* `fix_modify AtC control thermal `_ -* `fix_modify AtC control thermal correction_max_iterations `_ -* `fix_modify AtC control momentum `_ +* :doc:`fix_modify AtC control thermal ` +* :doc:`fix_modify AtC control momentum ` * `fix_modify AtC control localized_lambda `_ * `fix_modify AtC control lumped_lambda_solve `_ * `fix_modify AtC control mask_direction `_ control -- GitLab From 80d413b86c684d8d02120400dfbeee72a683dc45 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 13 Mar 2020 11:06:11 -0400 Subject: [PATCH 257/689] add reference to the fix_modify command overview in fix atc docs into all atc subcommand docs --- doc/src/atc_atom_element_map.rst | 5 +++ doc/src/atc_boundary_type.rst | 5 +++ doc/src/atc_control_localized_lambda.rst | 46 ++++++++++++++++++++++ doc/src/atc_control_momentum.rst | 3 +- doc/src/atc_control_thermal.rst | 3 +- doc/src/atc_decomposition.rst | 5 +++ doc/src/atc_electron_integration.rst | 5 +++ doc/src/atc_fix.rst | 3 +- doc/src/atc_fix_flux.rst | 3 +- doc/src/atc_initial.rst | 5 +++ doc/src/atc_internal_element_set.rst | 1 + doc/src/atc_internal_quadrature.rst | 5 +++ doc/src/atc_mesh_add_to_nodeset.rst | 3 +- doc/src/atc_mesh_create.rst | 3 +- doc/src/atc_mesh_create_elementset.rst | 1 + doc/src/atc_mesh_create_faceset_box.rst | 3 +- doc/src/atc_mesh_create_faceset_plane.rst | 3 +- doc/src/atc_mesh_create_nodeset.rst | 3 +- doc/src/atc_mesh_delete_elements.rst | 1 + doc/src/atc_mesh_nodeset_to_elementset.rst | 1 + doc/src/atc_mesh_quadrature.rst | 3 +- doc/src/atc_mesh_read.rst | 1 + doc/src/atc_mesh_write.rst | 1 + doc/src/atc_remove_source.rst | 3 +- doc/src/atc_source.rst | 3 +- doc/src/atc_time_integration.rst | 7 ++-- doc/src/atc_unfix.rst | 3 +- doc/src/atc_unfix_flux.rst | 3 +- doc/src/fix_atc.rst | 4 +- 29 files changed, 117 insertions(+), 18 deletions(-) create mode 100644 doc/src/atc_control_localized_lambda.rst diff --git a/doc/src/atc_atom_element_map.rst b/doc/src/atc_atom_element_map.rst index 0fe8cdde3a..11f58d0841 100644 --- a/doc/src/atc_atom_element_map.rst +++ b/doc/src/atc_atom_element_map.rst @@ -35,6 +35,11 @@ Restrictions Cannot change map type after initialization. +Related AtC commands +"""""""""""""""""""" + +- :ref:`fix_modify AtC command overview ` + Default """"""" diff --git a/doc/src/atc_boundary_type.rst b/doc/src/atc_boundary_type.rst index 72cd5aeb27..26b40e5a12 100644 --- a/doc/src/atc_boundary_type.rst +++ b/doc/src/atc_boundary_type.rst @@ -34,6 +34,11 @@ Restrictions None. +Related AtC commands +"""""""""""""""""""" + +- :ref:`fix_modify AtC command overview ` + Default """"""" diff --git a/doc/src/atc_control_localized_lambda.rst b/doc/src/atc_control_localized_lambda.rst new file mode 100644 index 0000000000..eb286756b7 --- /dev/null +++ b/doc/src/atc_control_localized_lambda.rst @@ -0,0 +1,46 @@ +.. index:: fix_modify AtC control localized_lambda + +fix_modify AtC control localized_lambda command +=============================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify control localized_lambda + +* AtC fixID = ID of :doc:`fix atc ` instance +* control localized_lambda = name of the AtC sub-command +* *on* or *off* = Toggles state of localization algorithm + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC control localized_lambda on + +Description +""""""""""" + +Turns the localization algorithms *on* or *off* for control algorithms +to restrict the influence of FE coupling or boundary conditions to a +region near the boundary of the MD region. Control algorithms will not +affect atoms in elements not possessing faces on the boundary of the +region. Flux-based control is localized via row-sum lumping while +quantity control is done by solving a truncated matrix equation. + +Restrictions +"""""""""""" + +None. + +Related AtC commands +"""""""""""""""""""" +- :ref:`fix_modify AtC command overview ` + +Default +""""""" + +off diff --git a/doc/src/atc_control_momentum.rst b/doc/src/atc_control_momentum.rst index 69790a79ab..7a9e88c721 100644 --- a/doc/src/atc_control_momentum.rst +++ b/doc/src/atc_control_momentum.rst @@ -68,7 +68,8 @@ They are ignored if a lumped solution is requested. Related AtC commands """""""""""""""""""" -:doc:`fix_modify AtC control thermal ` +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC control thermal ` Default """"""" diff --git a/doc/src/atc_control_thermal.rst b/doc/src/atc_control_thermal.rst index 0cd4904e2d..dc3f28f8eb 100644 --- a/doc/src/atc_control_thermal.rst +++ b/doc/src/atc_control_thermal.rst @@ -75,7 +75,8 @@ the fractional step method. Related AtC commands """""""""""""""""""" -:doc:`fix_modify AtC control momentum ` +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC control momentum ` Default """"""" diff --git a/doc/src/atc_decomposition.rst b/doc/src/atc_decomposition.rst index 2a056bab78..50d11bf52f 100644 --- a/doc/src/atc_decomposition.rst +++ b/doc/src/atc_decomposition.rst @@ -37,6 +37,11 @@ Restrictions None. +Related AtC commands +"""""""""""""""""""" + +- :ref:`fix_modify AtC command overview ` + Default """"""" diff --git a/doc/src/atc_electron_integration.rst b/doc/src/atc_electron_integration.rst index 3bf9a91ba2..e3928a69fb 100644 --- a/doc/src/atc_electron_integration.rst +++ b/doc/src/atc_electron_integration.rst @@ -38,6 +38,11 @@ Restrictions For use only with the two_temperature type of the AtC fix (see :doc:`fix atc ` command) +Related AtC commands +"""""""""""""""""""" + +- :ref:`fix_modify AtC command overview ` + Default """"""" diff --git a/doc/src/atc_fix.rst b/doc/src/atc_fix.rst index 4e955ea4e4..d3ba972508 100644 --- a/doc/src/atc_fix.rst +++ b/doc/src/atc_fix.rst @@ -37,7 +37,8 @@ The keyword *all* is reserved and thus not available as nodeset name. Related AtC commands """""""""""""""""""" -:doc:`fix_modify AtC unfix ` +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC unfix ` Default """"""" diff --git a/doc/src/atc_fix_flux.rst b/doc/src/atc_fix_flux.rst index 461d615162..12699e9163 100644 --- a/doc/src/atc_fix_flux.rst +++ b/doc/src/atc_fix_flux.rst @@ -39,7 +39,8 @@ Only normal fluxes (Neumann data) can be prescribed. Related AtC commands """""""""""""""""""" -:doc:`fix_modify AtC unfix_flux ` +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC unfix_flux ` Default """"""" diff --git a/doc/src/atc_initial.rst b/doc/src/atc_initial.rst index ab0f922a6c..fd45da0679 100644 --- a/doc/src/atc_initial.rst +++ b/doc/src/atc_initial.rst @@ -33,6 +33,11 @@ Restrictions The keyword *all* is reserved and thus not available as nodeset name. +Related AtC commands +"""""""""""""""""""" + +- :ref:`fix_modify AtC command overview ` + Default """"""" diff --git a/doc/src/atc_internal_element_set.rst b/doc/src/atc_internal_element_set.rst index 8dfa55eadb..4a376f55a3 100644 --- a/doc/src/atc_internal_element_set.rst +++ b/doc/src/atc_internal_element_set.rst @@ -42,6 +42,7 @@ reneighbor frequency. Related AtC commands """""""""""""""""""" +- :ref:`fix_modify AtC command overview ` - :doc:`fix_modify AtC atom_element_map ` - :doc:`fix_modify AtC boundary type ` diff --git a/doc/src/atc_internal_quadrature.rst b/doc/src/atc_internal_quadrature.rst index 7b503bca8e..b171914021 100644 --- a/doc/src/atc_internal_quadrature.rst +++ b/doc/src/atc_internal_quadrature.rst @@ -35,6 +35,11 @@ Optional region tag specifies which finite element nodes will be treated as being within the MD region. This option is only valid with internal_quadrature off. +Related AtC commands +"""""""""""""""""""" + +- :ref:`fix_modify AtC command overview ` + Default """"""" diff --git a/doc/src/atc_mesh_add_to_nodeset.rst b/doc/src/atc_mesh_add_to_nodeset.rst index 56fb55b6cb..f9f6f575fe 100644 --- a/doc/src/atc_mesh_add_to_nodeset.rst +++ b/doc/src/atc_mesh_add_to_nodeset.rst @@ -35,7 +35,8 @@ None Related AtC commands """""""""""""""""""" -:doc:`fix_modify AtC mesh create_nodeset ` +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC mesh create_nodeset ` Default diff --git a/doc/src/atc_mesh_create.rst b/doc/src/atc_mesh_create.rst index 404102ccd9..b17bb8ac0d 100644 --- a/doc/src/atc_mesh_create.rst +++ b/doc/src/atc_mesh_create.rst @@ -36,7 +36,8 @@ Creates only uniform rectangular grids in a rectangular region Related AtC commands """""""""""""""""""" -:doc:`fix_modify AtC mesh quadrature ` +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC mesh quadrature ` Default """"""" diff --git a/doc/src/atc_mesh_create_elementset.rst b/doc/src/atc_mesh_create_elementset.rst index 24408cb830..3cb406e7bc 100644 --- a/doc/src/atc_mesh_create_elementset.rst +++ b/doc/src/atc_mesh_create_elementset.rst @@ -36,6 +36,7 @@ Only viable for rectangular grids. Related AtC commands """""""""""""""""""" +- :ref:`fix_modify AtC command overview ` - :doc:`fix_modify AtC mesh delete_elements ` - :doc:`fix_modify AtC mesh nodeset_to_elementset ` diff --git a/doc/src/atc_mesh_create_faceset_box.rst b/doc/src/atc_mesh_create_faceset_box.rst index 2a80fae0c1..09b099d179 100644 --- a/doc/src/atc_mesh_create_faceset_box.rst +++ b/doc/src/atc_mesh_create_faceset_box.rst @@ -40,7 +40,8 @@ Only viable for rectangular grids. Related AtC commands """""""""""""""""""" -:doc:`fix_modify AtC mesh create_faceset plane ` +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC mesh create_faceset plane ` Default """"""" diff --git a/doc/src/atc_mesh_create_faceset_plane.rst b/doc/src/atc_mesh_create_faceset_plane.rst index 5cf7659ac2..035e584044 100644 --- a/doc/src/atc_mesh_create_faceset_plane.rst +++ b/doc/src/atc_mesh_create_faceset_plane.rst @@ -39,7 +39,8 @@ Only viable for rectangular grids. Related AtC commands """""""""""""""""""" -:doc:`fix_modify AtC mesh create_faceset box ` +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC mesh create_faceset box ` Default """"""" diff --git a/doc/src/atc_mesh_create_nodeset.rst b/doc/src/atc_mesh_create_nodeset.rst index dd7b8630be..a2f9d74d07 100644 --- a/doc/src/atc_mesh_create_nodeset.rst +++ b/doc/src/atc_mesh_create_nodeset.rst @@ -36,7 +36,8 @@ None Related AtC commands """""""""""""""""""" -:doc:`fix_modify AtC mesh add_to_nodeset ` +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC mesh add_to_nodeset ` Default """"""" diff --git a/doc/src/atc_mesh_delete_elements.rst b/doc/src/atc_mesh_delete_elements.rst index dfab9677b7..9785f0adf6 100644 --- a/doc/src/atc_mesh_delete_elements.rst +++ b/doc/src/atc_mesh_delete_elements.rst @@ -34,6 +34,7 @@ None. Related AtC commands """""""""""""""""""" +- :ref:`fix_modify AtC command overview ` - :doc:`fix_modify AtC mesh create_elementset ` - :doc:`fix_modify AtC mesh nodeset_to_elementset ` diff --git a/doc/src/atc_mesh_nodeset_to_elementset.rst b/doc/src/atc_mesh_nodeset_to_elementset.rst index a1ec879787..d8721cc295 100644 --- a/doc/src/atc_mesh_nodeset_to_elementset.rst +++ b/doc/src/atc_mesh_nodeset_to_elementset.rst @@ -40,6 +40,7 @@ None. Related AtC commands """""""""""""""""""" +- :ref:`fix_modify AtC command overview ` - :doc:`fix_modify AtC mesh create_elementset ` - :doc:`fix_modify AtC mesh delete_elements ` diff --git a/doc/src/atc_mesh_quadrature.rst b/doc/src/atc_mesh_quadrature.rst index 4efee0433a..0c9bd4b30f 100644 --- a/doc/src/atc_mesh_quadrature.rst +++ b/doc/src/atc_mesh_quadrature.rst @@ -36,7 +36,8 @@ None. Related AtC commands """""""""""""""""""" -:doc:`fix_modify AtC mesh create ` +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC mesh create ` Default """"""" diff --git a/doc/src/atc_mesh_read.rst b/doc/src/atc_mesh_read.rst index 7ba4431f84..9848e12b07 100644 --- a/doc/src/atc_mesh_read.rst +++ b/doc/src/atc_mesh_read.rst @@ -37,6 +37,7 @@ None Related AtC commands """""""""""""""""""" +- :ref:`fix_modify AtC command overview ` - :doc:`fix_modify AtC mesh create ` - :doc:`fix_modify AtC mesh write ` diff --git a/doc/src/atc_mesh_write.rst b/doc/src/atc_mesh_write.rst index c09ba2b87e..dbb8f9c219 100644 --- a/doc/src/atc_mesh_write.rst +++ b/doc/src/atc_mesh_write.rst @@ -34,6 +34,7 @@ None Related AtC commands """""""""""""""""""" +- :ref:`fix_modify AtC command overview ` - :doc:`fix_modify AtC mesh create ` - :doc:`fix_modify AtC mesh read ` diff --git a/doc/src/atc_remove_source.rst b/doc/src/atc_remove_source.rst index 587d04731b..d98b7933da 100644 --- a/doc/src/atc_remove_source.rst +++ b/doc/src/atc_remove_source.rst @@ -35,7 +35,8 @@ The keyword *all* is reserved and thus not available as element_set name. Related AtC commands """""""""""""""""""" -:doc:`fix_modify AtC source ` +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC source ` Default """"""" diff --git a/doc/src/atc_source.rst b/doc/src/atc_source.rst index 9c3849070f..6df4b67d1c 100644 --- a/doc/src/atc_source.rst +++ b/doc/src/atc_source.rst @@ -39,7 +39,8 @@ The keyword *all* is reserved and thus not available as element_set name. Related AtC commands """""""""""""""""""" -:doc:`fix_modify AtC remove_source ` +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC remove_source ` Default """"""" diff --git a/doc/src/atc_time_integration.rst b/doc/src/atc_time_integration.rst index 0780ece4fb..382f11d459 100644 --- a/doc/src/atc_time_integration.rst +++ b/doc/src/atc_time_integration.rst @@ -66,10 +66,11 @@ Restrictions None. -Related commands -"""""""""""""""" -:doc:`fix atc ` +Related AtC commands +"""""""""""""""""""" + +- :ref:`fix_modify AtC command overview ` Default """"""" diff --git a/doc/src/atc_unfix.rst b/doc/src/atc_unfix.rst index 1241d51bae..12ee37bbde 100644 --- a/doc/src/atc_unfix.rst +++ b/doc/src/atc_unfix.rst @@ -35,7 +35,8 @@ The keyword *all* is reserved and thus not available as nodeset name. Related AtC commands """""""""""""""""""" -:doc:`fix_modify AtC fix ` +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC fix ` Default """"""" diff --git a/doc/src/atc_unfix_flux.rst b/doc/src/atc_unfix_flux.rst index a756f63a75..da9d1b4aba 100644 --- a/doc/src/atc_unfix_flux.rst +++ b/doc/src/atc_unfix_flux.rst @@ -36,7 +36,8 @@ None. Related AtC commands """""""""""""""""""" -:doc:`fix_modify AtC fix_flux ` +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC fix_flux ` Default """"""" diff --git a/doc/src/fix_atc.rst b/doc/src/fix_atc.rst index b22d3359d1..b2d1da9317 100644 --- a/doc/src/fix_atc.rst +++ b/doc/src/fix_atc.rst @@ -139,6 +139,8 @@ one, e.g. nve, nvt, etc. In addition, currently: * the coupling is restricted to thermal physics * the FE computations are done in serial on each processor. +.. _atc_fix_modify: + Related commands """""""""""""""" @@ -181,7 +183,7 @@ conditions. * :doc:`fix_modify AtC control thermal ` * :doc:`fix_modify AtC control momentum ` -* `fix_modify AtC control localized_lambda `_ +* :doc:`fix_modify AtC control localized_lambda ` * `fix_modify AtC control lumped_lambda_solve `_ * `fix_modify AtC control mask_direction `_ control * `fix_modify AtC filter `_ -- GitLab From e368ae9f227d375ff5e186b840234dca2acd0566 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 13 Mar 2020 11:11:27 -0400 Subject: [PATCH 258/689] fix bug in pair styles lubricate and lubricate/poly Closes #1933 --- src/COLLOID/pair_lubricate.cpp | 2 +- src/COLLOID/pair_lubricate_poly.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/COLLOID/pair_lubricate.cpp b/src/COLLOID/pair_lubricate.cpp index a72eaef679..1795edf874 100644 --- a/src/COLLOID/pair_lubricate.cpp +++ b/src/COLLOID/pair_lubricate.cpp @@ -142,7 +142,7 @@ void PairLubricate::compute(int eflag, int vflag) Ef[2][2] = h_rate[2]/domain->zprd; Ef[0][1] = Ef[1][0] = 0.5 * h_rate[5]/domain->yprd; Ef[0][2] = Ef[2][0] = 0.5 * h_rate[4]/domain->zprd; - Ef[1][2] = Ef[2][1] = 0.5 * h_rate[3]/domain->zprd; + Ef[1][2] = Ef[2][1] = 0.5 * h_rate[3]/domain->xprd; // copy updated velocity/omega/angmom to the ghost particles // no need to do this if not shearing since comm->ghost_velocity is set diff --git a/src/COLLOID/pair_lubricate_poly.cpp b/src/COLLOID/pair_lubricate_poly.cpp index e347441cf4..3be7c2e34e 100644 --- a/src/COLLOID/pair_lubricate_poly.cpp +++ b/src/COLLOID/pair_lubricate_poly.cpp @@ -124,7 +124,7 @@ void PairLubricatePoly::compute(int eflag, int vflag) Ef[2][2] = h_rate[2]/domain->zprd; Ef[0][1] = Ef[1][0] = 0.5 * h_rate[5]/domain->yprd; Ef[0][2] = Ef[2][0] = 0.5 * h_rate[4]/domain->zprd; - Ef[1][2] = Ef[2][1] = 0.5 * h_rate[3]/domain->zprd; + Ef[1][2] = Ef[2][1] = 0.5 * h_rate[3]/domain->xprd; // copy updated omega to the ghost particles // no need to do this if not shearing since comm->ghost_velocity is set -- GitLab From 14bade977e8064c9cc5b09f3701940832585d080 Mon Sep 17 00:00:00 2001 From: "Jibril B. Coulibaly" Date: Fri, 13 Mar 2020 10:59:11 -0500 Subject: [PATCH 259/689] implement diameter/disc option for 2d simulations --- src/fix_adapt.cpp | 30 ++++++++++++++++++++---------- src/fix_adapt.h | 1 + 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/fix_adapt.cpp b/src/fix_adapt.cpp index 10ac290d02..ee85d054c8 100644 --- a/src/fix_adapt.cpp +++ b/src/fix_adapt.cpp @@ -15,6 +15,7 @@ #include #include "atom.h" #include "bond.h" +#include "domain.h" #include "update.h" #include "group.h" #include "modify.h" @@ -139,9 +140,11 @@ nadapt(0), id_fix_diam(NULL), id_fix_chg(NULL), adapt(NULL) } else if (strcmp(arg[iarg],"atom") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal fix adapt command"); adapt[nadapt].which = ATOM; - if (strcmp(arg[iarg+1],"diameter") == 0) { + if (strcmp(arg[iarg+1],"diameter") == 0 || strcmp(arg[iarg+1],"diameter/disc") == 0) { adapt[nadapt].aparam = DIAMETER; diamflag = 1; + discflag = 0; + if(strcmp(arg[iarg+1],"diameter/disc") == 0) discflag = 1; } else if (strcmp(arg[iarg+1],"charge") == 0) { adapt[nadapt].aparam = CHARGE; chgflag = 1; @@ -428,6 +431,8 @@ void FixAdapt::init() if (ad->aparam == DIAMETER) { if (!atom->radius_flag) error->all(FLERR,"Fix adapt requires atom attribute diameter"); + if(discflag && domain->dimension!=2) + error->all(FLERR,"Fix adapt requires 2d simulation"); } if (ad->aparam == CHARGE) { if (!atom->q_flag) @@ -568,8 +573,8 @@ void FixAdapt::change_settings() // also scale rmass to new value if (ad->aparam == DIAMETER) { - /* `mflag` unnecessary ? the test if (!atom->radius_flag) in FixAdapt::init() should perevent `atom->rmass_flag == false`. Unless there can be combinations of atoms with `radius` but without `rmass` - It could also be unsafe since rmass_flag could be added using `fix property/atom` even for an atom_style that does not have radius attributes */ + /* `mflag` unnecessary ? the test `if(!atom->radius_flag)` in `FixAdapt::init()` should perevent `atom->rmass_flag == false`. Unless there can be combinations of atom styles with `radius` but without `rmass` + It could also be unsafe since rmass_flag could be added using `fix property/atom` even for an atom_style that does not have radius attribute, although that possibility should be avoided as well with the test `if(!atom->radius_flag)` in `FixAdapt::init()` */ double density; double *vec = fix_diam->vstore; // Get initial radius to use `scale` keyword @@ -581,12 +586,14 @@ void FixAdapt::change_settings() for (i = 0; i < nall; i++) if (mask[i] & groupbit) { - density = rmass[i] / (4.0*MY_PI/3.0 * - radius[i]*radius[i]*radius[i]); + if(discflag) density = rmass[i] / (MY_PI * radius[i]*radius[i]); + else density = rmass[i] / (4.0*MY_PI/3.0 * + radius[i]*radius[i]*radius[i]); if (scaleflag) radius[i] = value * vec[i]; else radius[i] = 0.5*value; - rmass[i] = 4.0*MY_PI/3.0 * - radius[i]*radius[i]*radius[i] * density; + if(discflag) rmass[i] = MY_PI * radius[i]*radius[i] * density; + else rmass[i] = 4.0*MY_PI/3.0 * + radius[i]*radius[i]*radius[i] * density; } } else if (ad->aparam == CHARGE) { @@ -671,10 +678,13 @@ void FixAdapt::restore_settings() for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { - density = rmass[i] / (4.0*MY_PI/3.0 * - radius[i]*radius[i]*radius[i]); + if(discflag) density = rmass[i] / (MY_PI * radius[i]*radius[i]); + else density = rmass[i] / (4.0*MY_PI/3.0 * + radius[i]*radius[i]*radius[i]); radius[i] = vec[i]; - rmass[i] = 4.0*MY_PI/3.0 * radius[i]*radius[i]*radius[i] * density; + if(discflag) rmass[i] = MY_PI * radius[i]*radius[i] * density; + else rmass[i] = 4.0*MY_PI/3.0 * + radius[i]*radius[i]*radius[i] * density; } } if (chgflag) { diff --git a/src/fix_adapt.h b/src/fix_adapt.h index 0bb594b7a4..dbf8f5f792 100644 --- a/src/fix_adapt.h +++ b/src/fix_adapt.h @@ -47,6 +47,7 @@ class FixAdapt : public Fix { int nlevels_respa; char *id_fix_diam,*id_fix_chg; class FixStore *fix_diam,*fix_chg; + int discflag; struct Adapt { int which,ivar; -- GitLab From 8b8f928347812d959d940f9d9e0132e187df16fc Mon Sep 17 00:00:00 2001 From: "Jibril B. Coulibaly" Date: Fri, 13 Mar 2020 12:19:16 -0500 Subject: [PATCH 260/689] update documentation --- doc/src/fix_adapt.rst | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/doc/src/fix_adapt.rst b/doc/src/fix_adapt.rst index 0e57ec98c1..e96a4ed654 100644 --- a/doc/src/fix_adapt.rst +++ b/doc/src/fix_adapt.rst @@ -15,7 +15,7 @@ Syntax * adapt = style name of this fix command * N = adapt simulation settings every this many timesteps * one or more attribute/arg pairs may be appended -* attribute = *pair* or *kspace* or *atom* +* attribute = *pair* or *bond* or *kspace* or *atom* .. parsed-literal:: @@ -90,8 +90,8 @@ the end of a simulation. Even if *reset* is specified as *yes*\ , a restart file written during a simulation will contain the modified settings. -If the *scale* keyword is set to *no*\ , then the value the parameter is -set to will be whatever the variable generates. If the *scale* +If the *scale* keyword is set to *no*\ , then the value of the altered +parameter will be whatever the variable generates. If the *scale* keyword is set to *yes*\ , then the value of the altered parameter will be the initial value of that parameter multiplied by whatever the variable generates. I.e. the variable is now a "scale factor" applied @@ -324,26 +324,23 @@ The *atom* keyword enables various atom properties to be changed. The current list of atom parameters that can be varied by this fix: * charge = charge on particle -* diameter = diameter of particle +* diameter, or, diameter/disc = diameter of particle The *v\_name* argument of the *atom* keyword is the name of an :doc:`equal-style variable ` which will be evaluated each time -this fix is invoked to set the parameter to a new value. It should be -specified as v\_name, where name is the variable name. See the +this fix is invoked to set, or scale, the parameter to a new value. +It should be specified as v\_name, where name is the variable name. See the discussion above describing the formulas associated with equal-style variables. The new value is assigned to the corresponding attribute for all atoms in the fix group. -.. note:: - - The *atom* keyword works this way whether the *scale* keyword is - set to *no* or *yes*\ . I.e. the use of scale yes is not yet supported - by the *atom* keyword. - If the atom parameter is *diameter* and per-atom density and per-atom mass are defined for particles (e.g. :doc:`atom_style granular `), then the mass of each particle is also -changed when the diameter changes (density is assumed to stay -constant). +changed when the diameter changes. The mass is set from the particle volume +for 3d systems (density is assumed to stay constant). For 2d, the default is +for LAMMPS to model particles with a radius attribute as spheres. +However, if the atom parameter is *diameter/disc*, then the mass is +set from the particle area (the density is assumed to be in mass/distance^2 units). For example, these commands would shrink the diameter of all granular particles in the "center" group from 1.0 to 0.1 in a linear fashion -- GitLab From 1554aef454d8874232edc932cfd628b4d95a9100 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Fri, 13 Mar 2020 15:25:11 -0400 Subject: [PATCH 261/689] Avoid syntax highlighting in blocks that don't specify language --- doc/utils/sphinx-config/conf.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/utils/sphinx-config/conf.py b/doc/utils/sphinx-config/conf.py index a9f9cb952a..ffb43e7bff 100644 --- a/doc/utils/sphinx-config/conf.py +++ b/doc/utils/sphinx-config/conf.py @@ -334,3 +334,6 @@ from sphinx.highlighting import lexers lexers['LAMMPS'] = LAMMPSLexer.LAMMPSLexer(startinline=True) sys.path.append(os.path.join(os.path.dirname(__file__), '../../../python')) + +# avoid syntax highlighting in blocks that don't specify language +highlight_language = 'none' -- GitLab From 4e525f1d5668ef11836383bc6c53b279f9395b6f Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 13 Mar 2020 15:29:41 -0400 Subject: [PATCH 262/689] PPPM in USER-INTEL does not support triclinic cells --- doc/src/kspace_style.rst | 4 ++-- src/USER-INTEL/pppm_disp_intel.cpp | 1 + src/USER-INTEL/pppm_intel.cpp | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/src/kspace_style.rst b/doc/src/kspace_style.rst index ce2b988256..76fcd55c76 100644 --- a/doc/src/kspace_style.rst +++ b/doc/src/kspace_style.rst @@ -429,8 +429,8 @@ interactions. Vacuum boundary conditions are not currently supported. The *ewald/disp*\ , *ewald*\ , *pppm*\ , and *msm* styles support non-orthogonal (triclinic symmetry) simulation boxes. However, -triclinic simulation cells may not yet be supported by suffix versions -of these styles. +triclinic simulation cells may not yet be supported by all suffix +versions of these styles. All of the kspace styles are part of the KSPACE package. They are only enabled if LAMMPS was built with that package. See the :doc:`Build package ` doc page for more info. diff --git a/src/USER-INTEL/pppm_disp_intel.cpp b/src/USER-INTEL/pppm_disp_intel.cpp index 9d075c78a1..985be3aa48 100644 --- a/src/USER-INTEL/pppm_disp_intel.cpp +++ b/src/USER-INTEL/pppm_disp_intel.cpp @@ -62,6 +62,7 @@ enum{FORWARD_IK, FORWARD_AD, FORWARD_IK_PERATOM, FORWARD_AD_PERATOM, PPPMDispIntel::PPPMDispIntel(LAMMPS *lmp) : PPPMDisp(lmp) { suffix_flag |= Suffix::INTEL; + triclinic_support = 0; order = 7; order_6 = 7; //sets default stencil sizes to 7 diff --git a/src/USER-INTEL/pppm_intel.cpp b/src/USER-INTEL/pppm_intel.cpp index e3d1e7d4aa..4b233069b1 100644 --- a/src/USER-INTEL/pppm_intel.cpp +++ b/src/USER-INTEL/pppm_intel.cpp @@ -60,6 +60,7 @@ enum{FORWARD_IK,FORWARD_AD,FORWARD_IK_PERATOM,FORWARD_AD_PERATOM}; PPPMIntel::PPPMIntel(LAMMPS *lmp) : PPPM(lmp) { suffix_flag |= Suffix::INTEL; + triclinic_support = 0; order = 7; //sets default stencil size to 7 -- GitLab From 924629538f556b7b009dd2af11e0b95c960732d2 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 13 Mar 2020 16:01:00 -0400 Subject: [PATCH 263/689] restore support for triclinic cells with pppm/intel by calling the corresponding functions in PPPM in that case --- src/USER-INTEL/pppm_intel.cpp | 55 +++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/src/USER-INTEL/pppm_intel.cpp b/src/USER-INTEL/pppm_intel.cpp index 4b233069b1..e3bf779cc1 100644 --- a/src/USER-INTEL/pppm_intel.cpp +++ b/src/USER-INTEL/pppm_intel.cpp @@ -60,7 +60,6 @@ enum{FORWARD_IK,FORWARD_AD,FORWARD_IK_PERATOM,FORWARD_AD_PERATOM}; PPPMIntel::PPPMIntel(LAMMPS *lmp) : PPPM(lmp) { suffix_flag |= Suffix::INTEL; - triclinic_support = 0; order = 7; //sets default stencil size to 7 @@ -209,16 +208,23 @@ void PPPMIntel::compute_first(int eflag, int vflag) // find grid points for all my particles // map my particle charge onto my local 3d density grid + // optimized versions can only be used for orthogonal boxes - if (fix->precision() == FixIntel::PREC_MODE_MIXED) { - particle_map(fix->get_mixed_buffers()); - make_rho(fix->get_mixed_buffers()); - } else if (fix->precision() == FixIntel::PREC_MODE_DOUBLE) { - particle_map(fix->get_double_buffers()); - make_rho(fix->get_double_buffers()); + if (triclinic) { + PPPM::particle_map(); + PPPM::make_rho(); } else { - particle_map(fix->get_single_buffers()); - make_rho(fix->get_single_buffers()); + + if (fix->precision() == FixIntel::PREC_MODE_MIXED) { + particle_map(fix->get_mixed_buffers()); + make_rho(fix->get_mixed_buffers()); + } else if (fix->precision() == FixIntel::PREC_MODE_DOUBLE) { + particle_map(fix->get_double_buffers()); + make_rho(fix->get_double_buffers()); + } else { + particle_map(fix->get_single_buffers()); + make_rho(fix->get_single_buffers()); + } } // all procs communicate density values from their ghost cells @@ -259,21 +265,26 @@ void PPPMIntel::compute_second(int /*eflag*/, int /*vflag*/) int i,j; // calculate the force on my particles + // optimized versions can only be used for orthogonal boxes - if (differentiation_flag == 1) { - if (fix->precision() == FixIntel::PREC_MODE_MIXED) - fieldforce_ad(fix->get_mixed_buffers()); - else if (fix->precision() == FixIntel::PREC_MODE_DOUBLE) - fieldforce_ad(fix->get_double_buffers()); - else - fieldforce_ad(fix->get_single_buffers()); + if (triclinic) { + PPPM::fieldforce(); } else { - if (fix->precision() == FixIntel::PREC_MODE_MIXED) - fieldforce_ik(fix->get_mixed_buffers()); - else if (fix->precision() == FixIntel::PREC_MODE_DOUBLE) - fieldforce_ik(fix->get_double_buffers()); - else - fieldforce_ik(fix->get_single_buffers()); + if (differentiation_flag == 1) { + if (fix->precision() == FixIntel::PREC_MODE_MIXED) + fieldforce_ad(fix->get_mixed_buffers()); + else if (fix->precision() == FixIntel::PREC_MODE_DOUBLE) + fieldforce_ad(fix->get_double_buffers()); + else + fieldforce_ad(fix->get_single_buffers()); + } else { + if (fix->precision() == FixIntel::PREC_MODE_MIXED) + fieldforce_ik(fix->get_mixed_buffers()); + else if (fix->precision() == FixIntel::PREC_MODE_DOUBLE) + fieldforce_ik(fix->get_double_buffers()); + else + fieldforce_ik(fix->get_single_buffers()); + } } // extra per-atom energy/virial communication -- GitLab From 0b88950e03f5150aa4eb7a769875113b2530d415 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 13 Mar 2020 16:34:57 -0400 Subject: [PATCH 264/689] replace '\_' with '_' in plain text where possible --- doc/src/Build_basics.rst | 36 +- doc/src/Build_cmake.rst | 4 +- doc/src/Build_extras.rst | 138 +-- doc/src/Build_link.rst | 10 +- doc/src/Build_make.rst | 2 +- doc/src/Build_settings.rst | 28 +- doc/src/Build_windows.rst | 4 +- doc/src/Commands_input.rst | 2 +- doc/src/Commands_parse.rst | 2 +- doc/src/Errors_common.rst | 4 +- doc/src/Errors_messages.rst | 1080 ++++++++--------- doc/src/Errors_warnings.rst | 102 +- doc/src/Examples.rst | 8 +- doc/src/Howto_2d.rst | 4 +- doc/src/Howto_bash.rst | 12 +- doc/src/Howto_body.rst | 10 +- doc/src/Howto_client_server.rst | 12 +- doc/src/Howto_couple.rst | 6 +- doc/src/Howto_dispersion.rst | 22 +- doc/src/Howto_drude.rst | 2 +- doc/src/Howto_drude2.rst | 46 +- doc/src/Howto_elastic.rst | 14 +- doc/src/Howto_github.rst | 8 +- doc/src/Howto_granular.rst | 2 +- doc/src/Howto_kappa.rst | 2 +- doc/src/Howto_library.rst | 68 +- doc/src/Howto_manifold.rst | 8 +- doc/src/Howto_output.rst | 12 +- doc/src/Howto_restart.rst | 6 +- doc/src/Howto_spherical.rst | 2 +- doc/src/Howto_triclinic.rst | 2 +- doc/src/Install_linux.rst | 8 +- doc/src/Install_mac.rst | 2 +- doc/src/Install_windows.rst | 2 +- doc/src/Manual_build.rst | 4 +- doc/src/Modify_atom.rst | 74 +- doc/src/Modify_body.rst | 12 +- doc/src/Modify_bond.rst | 14 +- doc/src/Modify_command.rst | 4 +- doc/src/Modify_compute.rst | 42 +- doc/src/Modify_contribute.rst | 10 +- doc/src/Modify_dump.rst | 8 +- doc/src/Modify_fix.rst | 114 +- doc/src/Modify_kspace.rst | 2 +- doc/src/Modify_min.rst | 4 +- doc/src/Modify_overview.rst | 14 +- doc/src/Modify_pair.rst | 12 +- doc/src/Modify_region.rst | 8 +- doc/src/Packages_details.rst | 32 +- doc/src/Python_examples.rst | 10 +- doc/src/Python_head.rst | 2 +- doc/src/Python_install.rst | 8 +- doc/src/Python_library.rst | 44 +- doc/src/Python_mpi.rst | 2 +- doc/src/Python_shlib.rst | 14 +- doc/src/Python_test.rst | 4 +- doc/src/Run_basics.rst | 2 +- doc/src/Run_options.rst | 20 +- doc/src/Run_output.rst | 2 +- doc/src/Run_windows.rst | 2 +- doc/src/Speed_compare.rst | 2 +- doc/src/Speed_gpu.rst | 6 +- doc/src/Speed_intel.rst | 46 +- doc/src/Speed_kokkos.rst | 54 +- doc/src/Speed_measure.rst | 4 +- doc/src/Speed_omp.rst | 6 +- doc/src/Speed_packages.rst | 4 +- doc/src/Tools.rst | 22 +- doc/src/angle_charmm.rst | 2 +- doc/src/angle_cross.rst | 2 +- doc/src/angle_fourier.rst | 2 +- doc/src/angle_fourier_simple.rst | 2 +- doc/src/angle_hybrid.rst | 2 +- doc/src/angle_mm3.rst | 2 +- doc/src/angle_quartic.rst | 2 +- doc/src/angle_sdk.rst | 4 +- doc/src/angle_style.rst | 6 +- doc/src/angle_table.rst | 8 +- doc/src/atom_modify.rst | 6 +- doc/src/atom_style.rst | 22 +- doc/src/balance.rst | 8 +- doc/src/bond_coeff.rst | 6 +- doc/src/bond_hybrid.rst | 8 +- doc/src/bond_mm3.rst | 2 +- doc/src/bond_style.rst | 6 +- doc/src/bond_table.rst | 6 +- doc/src/bond_zero.rst | 2 +- doc/src/change_box.rst | 12 +- doc/src/comm_modify.rst | 8 +- doc/src/compute.rst | 14 +- doc/src/compute_adf.rst | 4 +- doc/src/compute_angle.rst | 6 +- doc/src/compute_angle_local.rst | 6 +- doc/src/compute_body_local.rst | 2 +- doc/src/compute_bond.rst | 2 +- doc/src/compute_bond_local.rst | 6 +- doc/src/compute_chunk_atom.rst | 6 +- doc/src/compute_chunk_spread_atom.rst | 2 +- doc/src/compute_cluster_atom.rst | 2 +- doc/src/compute_coord_atom.rst | 4 +- doc/src/compute_dihedral.rst | 2 +- doc/src/compute_dihedral_local.rst | 6 +- doc/src/compute_displace_atom.rst | 8 +- doc/src/compute_fep.rst | 14 +- doc/src/compute_global_atom.rst | 16 +- doc/src/compute_group_group.rst | 2 +- doc/src/compute_hma.rst | 8 +- doc/src/compute_improper.rst | 2 +- doc/src/compute_ke_eff.rst | 2 +- doc/src/compute_meso_t_atom.rst | 4 +- doc/src/compute_msd.rst | 2 +- doc/src/compute_orientorder_atom.rst | 2 +- doc/src/compute_pe.rst | 4 +- doc/src/compute_plasticity_atom.rst | 2 +- doc/src/compute_pressure.rst | 6 +- doc/src/compute_pressure_cylinder.rst | 18 +- doc/src/compute_property_atom.rst | 4 +- doc/src/compute_ptm_atom.rst | 2 +- doc/src/compute_rdf.rst | 4 +- doc/src/compute_reduce.rst | 8 +- doc/src/compute_reduce_chunk.rst | 2 +- doc/src/compute_saed.rst | 12 +- doc/src/compute_slice.rst | 8 +- doc/src/compute_smd_contact_radius.rst | 4 +- doc/src/compute_smd_damage.rst | 2 +- doc/src/compute_smd_hourglass_error.rst | 2 +- doc/src/compute_smd_triangle_vertices.rst | 10 +- doc/src/compute_sna_atom.rst | 26 +- doc/src/compute_spin.rst | 6 +- doc/src/compute_stress_mop.rst | 6 +- doc/src/compute_tally.rst | 4 +- doc/src/compute_temp.rst | 4 +- doc/src/compute_temp_drude.rst | 2 +- doc/src/compute_ti.rst | 6 +- doc/src/compute_voronoi_atom.rst | 22 +- doc/src/compute_xrd.rst | 2 +- doc/src/create_atoms.rst | 18 +- doc/src/create_bonds.rst | 2 +- doc/src/create_box.rst | 6 +- doc/src/delete_bonds.rst | 12 +- doc/src/dihedral_charmm.rst | 10 +- doc/src/dihedral_coeff.rst | 6 +- doc/src/dihedral_fourier.rst | 2 +- doc/src/dihedral_hybrid.rst | 8 +- doc/src/dihedral_nharmonic.rst | 2 +- doc/src/dihedral_quadratic.rst | 2 +- doc/src/dihedral_spherical.rst | 2 +- doc/src/dihedral_style.rst | 8 +- doc/src/dihedral_table.rst | 8 +- doc/src/dihedral_table_cut.rst | 8 +- doc/src/dihedral_zero.rst | 2 +- doc/src/displace_atoms.rst | 2 +- doc/src/dump.rst | 36 +- doc/src/dump_adios.rst | 6 +- doc/src/dump_h5md.rst | 20 +- doc/src/dump_image.rst | 18 +- doc/src/dump_modify.rst | 40 +- doc/src/dump_vtk.rst | 8 +- doc/src/dynamical_matrix.rst | 2 +- doc/src/fix.rst | 10 +- doc/src/fix_adapt.rst | 46 +- doc/src/fix_adapt_fep.rst | 10 +- doc/src/fix_addforce.rst | 6 +- doc/src/fix_addtorque.rst | 4 +- doc/src/fix_append_atoms.rst | 2 +- doc/src/fix_atc.rst | 22 +- doc/src/fix_atom_swap.rst | 2 +- doc/src/fix_ave_atom.rst | 10 +- doc/src/fix_ave_chunk.rst | 12 +- doc/src/fix_ave_correlate.rst | 10 +- doc/src/fix_ave_correlate_long.rst | 6 +- doc/src/fix_ave_histo.rst | 10 +- doc/src/fix_ave_time.rst | 10 +- doc/src/fix_aveforce.rst | 4 +- doc/src/fix_balance.rst | 2 +- doc/src/fix_bocs.rst | 12 +- doc/src/fix_bond_break.rst | 2 +- doc/src/fix_bond_create.rst | 2 +- doc/src/fix_bond_react.rst | 30 +- doc/src/fix_bond_swap.rst | 8 +- doc/src/fix_box_relax.rst | 16 +- doc/src/fix_client_md.rst | 4 +- doc/src/fix_cmap.rst | 6 +- doc/src/fix_colvars.rst | 6 +- doc/src/fix_controller.rst | 12 +- doc/src/fix_deform.rst | 2 +- doc/src/fix_deposit.rst | 4 +- doc/src/fix_dpd_energy.rst | 4 +- doc/src/fix_dpd_source.rst | 2 +- doc/src/fix_drag.rst | 2 +- doc/src/fix_drude_transform.rst | 6 +- doc/src/fix_dt_reset.rst | 2 +- doc/src/fix_efield.rst | 6 +- doc/src/fix_ehex.rst | 4 +- doc/src/fix_electron_stopping.rst | 6 +- doc/src/fix_enforce2d.rst | 2 +- doc/src/fix_eos_table.rst | 4 +- doc/src/fix_evaporate.rst | 2 +- doc/src/fix_external.rst | 8 +- doc/src/fix_ffl.rst | 4 +- doc/src/fix_filter_corotate.rst | 2 +- doc/src/fix_flow_gauss.rst | 12 +- doc/src/fix_freeze.rst | 2 +- doc/src/fix_gcmc.rst | 48 +- doc/src/fix_gld.rst | 6 +- doc/src/fix_gle.rst | 2 +- doc/src/fix_gravity.rst | 4 +- doc/src/fix_grem.rst | 2 +- doc/src/fix_halt.rst | 8 +- doc/src/fix_heat.rst | 6 +- doc/src/fix_hyper_global.rst | 6 +- doc/src/fix_hyper_local.rst | 8 +- doc/src/fix_imd.rst | 4 +- doc/src/fix_indent.rst | 8 +- doc/src/fix_ipi.rst | 2 +- doc/src/fix_langevin.rst | 10 +- doc/src/fix_langevin_drude.rst | 30 +- doc/src/fix_langevin_eff.rst | 2 +- doc/src/fix_langevin_spin.rst | 2 +- doc/src/fix_latte.rst | 2 +- doc/src/fix_lb_fluid.rst | 20 +- doc/src/fix_lb_momentum.rst | 2 +- doc/src/fix_lb_pc.rst | 2 +- doc/src/fix_lb_rigid_pc_sphere.rst | 2 +- doc/src/fix_lb_viscous.rst | 4 +- doc/src/fix_lineforce.rst | 2 +- doc/src/fix_manifoldforce.rst | 6 +- doc/src/fix_meso.rst | 2 +- doc/src/fix_meso_move.rst | 8 +- doc/src/fix_meso_stationary.rst | 2 +- doc/src/fix_modify.rst | 8 +- doc/src/fix_momentum.rst | 2 +- doc/src/fix_move.rst | 8 +- doc/src/fix_msst.rst | 12 +- doc/src/fix_mvv_dpd.rst | 2 +- doc/src/fix_neb.rst | 6 +- doc/src/fix_neb_spin.rst | 2 +- doc/src/fix_nh.rst | 38 +- doc/src/fix_nh_eff.rst | 6 +- doc/src/fix_nh_uef.rst | 14 +- doc/src/fix_nph_asphere.rst | 14 +- doc/src/fix_nph_body.rst | 14 +- doc/src/fix_nph_sphere.rst | 14 +- doc/src/fix_nphug.rst | 14 +- doc/src/fix_npt_asphere.rst | 14 +- doc/src/fix_npt_body.rst | 14 +- doc/src/fix_npt_cauchy.rst | 40 +- doc/src/fix_npt_sphere.rst | 14 +- doc/src/fix_nve.rst | 2 +- doc/src/fix_nve_asphere.rst | 2 +- doc/src/fix_nve_asphere_noforce.rst | 2 +- doc/src/fix_nve_awpmd.rst | 2 +- doc/src/fix_nve_body.rst | 2 +- doc/src/fix_nve_eff.rst | 2 +- doc/src/fix_nve_limit.rst | 2 +- doc/src/fix_nve_line.rst | 2 +- doc/src/fix_nve_manifold_rattle.rst | 4 +- doc/src/fix_nve_noforce.rst | 2 +- doc/src/fix_nve_sphere.rst | 2 +- doc/src/fix_nve_spin.rst | 2 +- doc/src/fix_nve_tri.rst | 2 +- doc/src/fix_nvk.rst | 2 +- doc/src/fix_nvt_asphere.rst | 8 +- doc/src/fix_nvt_body.rst | 8 +- doc/src/fix_nvt_manifold_rattle.rst | 2 +- doc/src/fix_nvt_sllod.rst | 6 +- doc/src/fix_nvt_sllod_eff.rst | 2 +- doc/src/fix_nvt_sphere.rst | 8 +- doc/src/fix_oneway.rst | 2 +- doc/src/fix_orient.rst | 2 +- doc/src/fix_phonon.rst | 10 +- doc/src/fix_planeforce.rst | 2 +- doc/src/fix_plumed.rst | 2 +- doc/src/fix_poems.rst | 4 +- doc/src/fix_pour.rst | 4 +- doc/src/fix_precession_spin.rst | 4 +- doc/src/fix_press_berendsen.rst | 12 +- doc/src/fix_print.rst | 4 +- doc/src/fix_propel_self.rst | 6 +- doc/src/fix_property_atom.rst | 8 +- doc/src/fix_python_invoke.rst | 2 +- doc/src/fix_python_move.rst | 2 +- doc/src/fix_qbmsst.rst | 32 +- doc/src/fix_qeq.rst | 2 +- doc/src/fix_qeq_comb.rst | 24 +- doc/src/fix_qeq_reax.rst | 2 +- doc/src/fix_qmmm.rst | 2 +- doc/src/fix_qtb.rst | 28 +- doc/src/fix_reaxc_bonds.rst | 12 +- doc/src/fix_reaxc_species.rst | 8 +- doc/src/fix_recenter.rst | 2 +- doc/src/fix_restrain.rst | 2 +- doc/src/fix_rigid.rst | 4 +- doc/src/fix_rigid_meso.rst | 2 +- doc/src/fix_rx.rst | 16 +- doc/src/fix_saed_vtk.rst | 12 +- doc/src/fix_setforce.rst | 4 +- doc/src/fix_shake.rst | 6 +- doc/src/fix_shardlow.rst | 8 +- doc/src/fix_smd.rst | 2 +- doc/src/fix_smd_adjust_dt.rst | 10 +- doc/src/fix_smd_integrate_tlsph.rst | 12 +- doc/src/fix_smd_integrate_ulsph.rst | 32 +- doc/src/fix_smd_move_triangulated_surface.rst | 12 +- doc/src/fix_smd_setvel.rst | 4 +- doc/src/fix_smd_wall_surface.rst | 16 +- doc/src/fix_spring.rst | 2 +- doc/src/fix_spring_chunk.rst | 2 +- doc/src/fix_spring_rg.rst | 2 +- doc/src/fix_spring_self.rst | 2 +- doc/src/fix_srd.rst | 4 +- doc/src/fix_store_force.rst | 4 +- doc/src/fix_store_state.rst | 2 +- doc/src/fix_temp_berendsen.rst | 8 +- doc/src/fix_temp_csvr.rst | 8 +- doc/src/fix_temp_rescale.rst | 8 +- doc/src/fix_temp_rescale_eff.rst | 2 +- doc/src/fix_tfmc.rst | 2 +- doc/src/fix_thermal_conductivity.rst | 2 +- doc/src/fix_ti_spring.rst | 18 +- doc/src/fix_tmd.rst | 14 +- doc/src/fix_ttm.rst | 54 +- doc/src/fix_tune_kspace.rst | 2 +- doc/src/fix_vector.rst | 10 +- doc/src/fix_viscosity.rst | 2 +- doc/src/fix_viscous.rst | 2 +- doc/src/fix_wall.rst | 6 +- doc/src/fix_wall_body_polygon.rst | 10 +- doc/src/fix_wall_body_polyhedron.rst | 10 +- doc/src/fix_wall_gran.rst | 22 +- doc/src/fix_wall_gran_region.rst | 20 +- doc/src/fix_wall_piston.rst | 2 +- doc/src/fix_wall_reflect.rst | 4 +- doc/src/fix_wall_region.rst | 4 +- doc/src/fix_wall_srd.rst | 4 +- doc/src/improper_coeff.rst | 6 +- doc/src/improper_distance.rst | 4 +- doc/src/improper_distharm.rst | 6 +- doc/src/improper_fourier.rst | 2 +- doc/src/improper_hybrid.rst | 8 +- doc/src/improper_ring.rst | 4 +- doc/src/improper_sqdistharm.rst | 6 +- doc/src/improper_style.rst | 8 +- doc/src/improper_zero.rst | 2 +- doc/src/kim_commands.rst | 212 ++-- doc/src/kspace_modify.rst | 26 +- doc/src/kspace_style.rst | 10 +- doc/src/min_modify.rst | 22 +- doc/src/min_spin.rst | 16 +- doc/src/molecule.rst | 2 +- doc/src/neb.rst | 8 +- doc/src/neb_spin.rst | 4 +- doc/src/neigh_modify.rst | 2 +- doc/src/package.rst | 48 +- doc/src/pair_adp.rst | 10 +- doc/src/pair_agni.rst | 6 +- doc/src/pair_airebo.rst | 12 +- doc/src/pair_atm.rst | 2 +- doc/src/pair_awpmd.rst | 12 +- doc/src/pair_beck.rst | 2 +- doc/src/pair_body_rounded_polygon.rst | 6 +- doc/src/pair_body_rounded_polyhedron.rst | 4 +- doc/src/pair_bop.rst | 184 +-- doc/src/pair_born.rst | 8 +- doc/src/pair_brownian.rst | 14 +- doc/src/pair_buck.rst | 6 +- doc/src/pair_buck6d_coul_gauss.rst | 2 +- doc/src/pair_buck_long.rst | 28 +- doc/src/pair_charmm.rst | 18 +- doc/src/pair_class2.rst | 12 +- doc/src/pair_coeff.rst | 14 +- doc/src/pair_colloid.rst | 14 +- doc/src/pair_comb.rst | 12 +- doc/src/pair_cosine_squared.rst | 6 +- doc/src/pair_coul.rst | 12 +- doc/src/pair_coul_diel.rst | 8 +- doc/src/pair_coul_shield.rst | 6 +- doc/src/pair_cs.rst | 2 +- doc/src/pair_dipole.rst | 32 +- doc/src/pair_dpd.rst | 4 +- doc/src/pair_drip.rst | 12 +- doc/src/pair_dsmc.rst | 16 +- doc/src/pair_e3b.rst | 16 +- doc/src/pair_eam.rst | 24 +- doc/src/pair_edip.rst | 8 +- doc/src/pair_eff.rst | 28 +- doc/src/pair_eim.rst | 20 +- doc/src/pair_exp6_rx.rst | 2 +- doc/src/pair_extep.rst | 2 +- doc/src/pair_fep_soft.rst | 4 +- doc/src/pair_gauss.rst | 12 +- doc/src/pair_gayberne.rst | 22 +- doc/src/pair_gran.rst | 22 +- doc/src/pair_granular.rst | 56 +- doc/src/pair_gromacs.rst | 10 +- doc/src/pair_gw.rst | 8 +- doc/src/pair_hbond_dreiding.rst | 22 +- doc/src/pair_hybrid.rst | 36 +- doc/src/pair_ilp_graphene_hbn.rst | 22 +- doc/src/pair_kim.rst | 14 +- doc/src/pair_kolmogorov_crespi_full.rst | 20 +- doc/src/pair_kolmogorov_crespi_z.rst | 2 +- doc/src/pair_lcbop.rst | 8 +- doc/src/pair_lebedeva_z.rst | 2 +- doc/src/pair_line_lj.rst | 10 +- doc/src/pair_list.rst | 4 +- doc/src/pair_lj.rst | 14 +- doc/src/pair_lj96.rst | 6 +- doc/src/pair_lj_cubic.rst | 4 +- doc/src/pair_lj_expand.rst | 8 +- doc/src/pair_lj_long.rst | 30 +- doc/src/pair_lj_smooth.rst | 6 +- doc/src/pair_lj_smooth_linear.rst | 6 +- doc/src/pair_lj_switch3_coulgauss_long.rst | 2 +- doc/src/pair_local_density.rst | 20 +- doc/src/pair_lubricate.rst | 18 +- doc/src/pair_lubricateU.rst | 18 +- doc/src/pair_mdf.rst | 16 +- doc/src/pair_meam_spline.rst | 12 +- doc/src/pair_meam_sw_spline.rst | 16 +- doc/src/pair_meamc.rst | 32 +- doc/src/pair_mesocnt.rst | 2 +- doc/src/pair_mesodpd.rst | 58 +- doc/src/pair_mgpt.rst | 36 +- doc/src/pair_mie.rst | 6 +- doc/src/pair_mm3_switch3_coulgauss_long.rst | 2 +- doc/src/pair_modify.rst | 2 +- doc/src/pair_morse.rst | 4 +- doc/src/pair_multi_lucy.rst | 10 +- doc/src/pair_multi_lucy_rx.rst | 10 +- doc/src/pair_nb3b_harmonic.rst | 14 +- doc/src/pair_nm.rst | 8 +- doc/src/pair_peri.rst | 20 +- doc/src/pair_polymorphic.rst | 20 +- doc/src/pair_python.rst | 22 +- doc/src/pair_quip.rst | 14 +- doc/src/pair_reaxc.rst | 54 +- doc/src/pair_resquared.rst | 18 +- doc/src/pair_sdk.rst | 10 +- doc/src/pair_sdpd_taitwater_isothermal.rst | 6 +- doc/src/pair_smd_hertz.rst | 6 +- doc/src/pair_smd_triangulated_surface.rst | 12 +- doc/src/pair_smd_ulsph.rst | 6 +- doc/src/pair_smtbq.rst | 42 +- doc/src/pair_snap.rst | 10 +- doc/src/pair_soft.rst | 8 +- doc/src/pair_sph_heatconduction.rst | 6 +- doc/src/pair_sph_idealgas.rst | 6 +- doc/src/pair_sph_lj.rst | 6 +- doc/src/pair_sph_rhosum.rst | 6 +- doc/src/pair_sph_taitwater.rst | 6 +- doc/src/pair_sph_taitwater_morris.rst | 6 +- doc/src/pair_spin_dipole.rst | 2 +- doc/src/pair_spin_dmi.rst | 2 +- doc/src/pair_spin_exchange.rst | 4 +- doc/src/pair_spin_magelec.rst | 2 +- doc/src/pair_spin_neel.rst | 4 +- doc/src/pair_srp.rst | 2 +- doc/src/pair_style.rst | 12 +- doc/src/pair_sw.rst | 10 +- doc/src/pair_table.rst | 20 +- doc/src/pair_table_rx.rst | 18 +- doc/src/pair_tersoff.rst | 36 +- doc/src/pair_tersoff_mod.rst | 24 +- doc/src/pair_tersoff_zbl.rst | 32 +- doc/src/pair_thole.rst | 10 +- doc/src/pair_tri_lj.rst | 14 +- doc/src/pair_ufm.rst | 8 +- doc/src/pair_vashishta.rst | 10 +- doc/src/pair_write.rst | 2 +- doc/src/pair_yukawa.rst | 4 +- doc/src/pair_yukawa_colloid.rst | 6 +- doc/src/pair_zbl.rst | 8 +- doc/src/pair_zero.rst | 10 +- doc/src/partition.rst | 2 +- doc/src/prd.rst | 36 +- doc/src/processors.rst | 10 +- doc/src/python.rst | 16 +- doc/src/read_data.rst | 52 +- doc/src/read_dump.rst | 10 +- doc/src/read_restart.rst | 14 +- doc/src/region.rst | 6 +- doc/src/rerun.rst | 2 +- doc/src/reset_ids.rst | 8 +- doc/src/restart.rst | 2 +- doc/src/run_style.rst | 6 +- doc/src/server_mc.rst | 6 +- doc/src/server_md.rst | 6 +- doc/src/set.rst | 10 +- doc/src/shell.rst | 2 +- doc/src/special_bonds.rst | 4 +- doc/src/suffix.rst | 8 +- doc/src/tad.rst | 38 +- doc/src/temper.rst | 2 +- doc/src/thermo.rst | 2 +- doc/src/thermo_modify.rst | 16 +- doc/src/thermo_style.rst | 46 +- doc/src/third_order.rst | 4 +- doc/src/variable.rst | 112 +- doc/src/velocity.rst | 2 +- doc/src/write_coeff.rst | 2 +- doc/src/write_data.rst | 2 +- doc/src/write_dump.rst | 4 +- doc/src/write_restart.rst | 2 +- 504 files changed, 3426 insertions(+), 3424 deletions(-) diff --git a/doc/src/Build_basics.rst b/doc/src/Build_basics.rst index c50af2ca78..892bcebaea 100644 --- a/doc/src/Build_basics.rst +++ b/doc/src/Build_basics.rst @@ -41,8 +41,8 @@ is below. # no default value The executable created by CMake (after running make) is named *lmp* unless -the LAMMPS\_MACHINE option is set. When setting `LAMMPS_MACHINE=name` -the executable will be named *lmp\_name*\. Using `BUILD\_MPI=no` will +the LAMMPS_MACHINE option is set. When setting `LAMMPS_MACHINE=name` +the executable will be named *lmp_name*\. Using `BUILD_MPI=no` will enforce building a serial executable using the MPI STUBS library. **Traditional make**\ : @@ -56,13 +56,13 @@ The build with traditional makefiles has to be done inside the source folder `sr make mybox # uses Makefile.mybox to produce lmp_mybox Any "make machine" command will look up the make settings from a file -Makefile.machine, create a folder Obj\_machine with all objects and -generated files and an executable called *lmp\_machine*\ . The standard +Makefile.machine, create a folder Obj_machine with all objects and +generated files and an executable called *lmp_machine*\ . The standard parallel build with `make mpi` assumes a standard MPI installation with MPI compiler wrappers where all necessary compiler and linker flags to get access and link with the suitable MPI headers and libraries are set by the wrapper programs. For other cases or the serial build, you have -to adjust the make file variables MPI\_INC, MPI\_PATH, MPI\_LIB as well +to adjust the make file variables MPI_INC, MPI_PATH, MPI_LIB as well as CC and LINK. To enable OpenMP threading usually a compiler specific flag needs to be added to the compile and link commands. For the GNU compilers, this is *-fopenmp*\ , which can be added to the CC and LINK @@ -89,7 +89,7 @@ and thus is not compatible with those packages. .. note:: The file STUBS/mpi.c provides a CPU timer function called - MPI\_Wtime() that calls gettimeofday() . If your operating system + MPI_Wtime() that calls gettimeofday() . If your operating system does not support gettimeofday() , you will need to insert code to call another timer. Note that the ANSI-standard function clock() rolls over after an hour or so, and is therefore insufficient for @@ -126,9 +126,9 @@ to: e.g. LATTE and USER-COLVARS. See the :doc:`Packages details ` doc page for more info on these packages and the doc pages for their respective commands for OpenMP threading info. -For CMake, if you use BUILD\_OMP=yes, you can use these packages and +For CMake, if you use BUILD_OMP=yes, you can use these packages and turn on their native OpenMP support and turn on their native OpenMP -support at run time, by setting the OMP\_NUM\_THREADS environment +support at run time, by setting the OMP_NUM_THREADS environment variable before you launch LAMMPS. For building via conventional make, the CCFLAGS and LINKFLAGS @@ -148,7 +148,7 @@ in LAMMPS (for maximal compatibility with compiler versions in use). In those case, all 'default(none)' directives (which aid in detecting incorrect and unwanted sharing) can be replaced with 'default(shared)' while dropping all 'shared()' directives. The script -'src/USER-OMP/hack\_openmp\_for\_pgi\_gcc9.sh' can be used to automate +'src/USER-OMP/hack_openmp_for_pgi_gcc9.sh' can be used to automate this conversion. ---------- @@ -300,12 +300,12 @@ are set, defaults are applied. -D LAMMPS_LIB_SUFFIX=name # name = mpi, serial, mybox, titan, laptop, etc # no default value -Setting BUILD\_EXE=no will not produce an executable. Setting -BUILD\_LIB=yes will produce a static library named *liblammps.a*\ . -Setting both BUILD\_LIB=yes and BUILD\_SHARED\_LIBS=yes will produce a -shared library named *liblammps.so* instead. If LAMMPS\_LIB\_SUFFIX is +Setting BUILD_EXE=no will not produce an executable. Setting +BUILD_LIB=yes will produce a static library named *liblammps.a*\ . +Setting both BUILD_LIB=yes and BUILD_SHARED_LIBS=yes will produce a +shared library named *liblammps.so* instead. If LAMMPS_LIB_SUFFIX is set to *name* in addition, the name of the generated libraries will be -changed to either *liblammps\_name.a* or *liblammps\_name.so*\ , +changed to either *liblammps_name.a* or *liblammps_name.so*\ , respectively. **Traditional make**\ : @@ -322,11 +322,11 @@ Several options are available and "mode=exe" is the default. make mode=shlib machine # build LAMMPS shared lib liblammps_machine.so make mode=shexe machine # same as "mode=exe" but uses objects from "mode=shlib" -The two "exe" builds will generate and executable *lmp\_machine*\ , -while the two library builds will create a file *liblammps\_machine.a* -or *liblammps\_machine.so*\ . They will also create generic soft links, +The two "exe" builds will generate and executable *lmp_machine*\ , +while the two library builds will create a file *liblammps_machine.a* +or *liblammps_machine.so*\ . They will also create generic soft links, named *liblammps.a* and *liblammps.so*\ , which point to the specific -*liblammps\_machine.a/so* files. +*liblammps_machine.a/so* files. **CMake and make info**\ : diff --git a/doc/src/Build_cmake.rst b/doc/src/Build_cmake.rst index a0b33c792c..ea4880aaa3 100644 --- a/doc/src/Build_cmake.rst +++ b/doc/src/Build_cmake.rst @@ -55,7 +55,7 @@ your system with: This will install the lammps executable and library (if requested), some tools (if configured) and additional files like library API headers, manpages, potential and force field files. The location of the installation -tree is set by the CMake variable "CMAKE\_INSTALL\_PREFIX" which defaults +tree is set by the CMake variable "CMAKE_INSTALL_PREFIX" which defaults to ${HOME}/.local ---------- @@ -127,7 +127,7 @@ command-line options. Several useful ones are: All the LAMMPS-specific -D variables that a LAMMPS build supports are described on the pages linked to from the :doc:`Build ` doc page. All of these variable names are upper-case and their values are -lower-case, e.g. -D LAMMPS\_SIZES=smallbig. For boolean values, any of +lower-case, e.g. -D LAMMPS_SIZES=smallbig. For boolean values, any of these forms can be used: yes/no, on/off, 1/0. On Unix/Linux machines, CMake generates a Makefile by default to diff --git a/doc/src/Build_extras.rst b/doc/src/Build_extras.rst index 32e1bbb2c8..1e7275b366 100644 --- a/doc/src/Build_extras.rst +++ b/doc/src/Build_extras.rst @@ -14,7 +14,7 @@ or $ make yes-name -as described on the :doc:`Build\_package ` doc page. +as described on the :doc:`Build_package ` doc page. For a CMake build there may be additional optional or required variables to set. For a build with make, a provided library under the @@ -107,22 +107,22 @@ which GPU hardware to build for. -D CUDA_MPS_SUPPORT=value # enables some tweaks required to run with active nvidia-cuda-mps daemon # value = yes or no (default) -GPU\_ARCH settings for different GPU hardware is as follows: +GPU_ARCH settings for different GPU hardware is as follows: -* sm\_12 or sm\_13 for GT200 (supported by CUDA 3.2 until CUDA 6.5) -* sm\_20 or sm\_21 for Fermi (supported by CUDA 3.2 until CUDA 7.5) -* sm\_30 or sm\_35 or sm\_37 for Kepler (supported since CUDA 5) -* sm\_50 or sm\_52 for Maxwell (supported since CUDA 6) -* sm\_60 or sm\_61 for Pascal (supported since CUDA 8) -* sm\_70 for Volta (supported since CUDA 9) -* sm\_75 for Turing (supported since CUDA 10) +* sm_12 or sm_13 for GT200 (supported by CUDA 3.2 until CUDA 6.5) +* sm_20 or sm_21 for Fermi (supported by CUDA 3.2 until CUDA 7.5) +* sm_30 or sm_35 or sm_37 for Kepler (supported since CUDA 5) +* sm_50 or sm_52 for Maxwell (supported since CUDA 6) +* sm_60 or sm_61 for Pascal (supported since CUDA 8) +* sm_70 for Volta (supported since CUDA 9) +* sm_75 for Turing (supported since CUDA 10) A more detailed list can be found, for example, at `Wikipedia's CUDA article `_ CMake can detect which version of the CUDA toolkit is used and thus can include support for **all** major GPU architectures supported by this toolkit. -Thus the GPU\_ARCH setting is merely an optimization, to have code for +Thus the GPU_ARCH setting is merely an optimization, to have code for the preferred GPU architecture directly included rather than having to wait for the JIT compiler of the CUDA driver to translate it. @@ -132,8 +132,8 @@ Before building LAMMPS, you must build the GPU library in lib/gpu. You can do this manually if you prefer; follow the instructions in lib/gpu/README. Note that the GPU library uses MPI calls, so you must use the same MPI library (or the STUBS library) settings as the main -LAMMPS code. This also applies to the -DLAMMPS\_BIGBIG, --DLAMMPS\_SMALLBIG, or -DLAMMPS\_SMALLSMALL settings in whichever +LAMMPS code. This also applies to the -DLAMMPS_BIGBIG, +-DLAMMPS_SMALLBIG, or -DLAMMPS_SMALLSMALL settings in whichever Makefile you use. You can also build the library in one step from the lammps/src dir, @@ -156,18 +156,18 @@ Makefile.machine you start from via the corresponding -c, -a, -p, -e switches (as in the examples above), and also save a copy of the new Makefile if desired: -* CUDA\_HOME = where NVIDIA CUDA software is installed on your system -* CUDA\_ARCH = sm\_XX, what GPU hardware you have, same as CMake GPU\_ARCH above -* CUDA\_PRECISION = precision (double, mixed, single) +* CUDA_HOME = where NVIDIA CUDA software is installed on your system +* CUDA_ARCH = sm_XX, what GPU hardware you have, same as CMake GPU_ARCH above +* CUDA_PRECISION = precision (double, mixed, single) * EXTRAMAKE = which Makefile.lammps.\* file to copy to Makefile.lammps -The file Makefile.linux\_multi is set up to include support for multiple +The file Makefile.linux_multi is set up to include support for multiple GPU architectures as supported by the CUDA toolkit in use. This is done through using the "--gencode " flag, which can be used multiple times and thus support all GPU architectures supported by your CUDA compiler. If the library build is successful, 3 files should be created: -lib/gpu/libgpu.a, lib/gpu/nvc\_get\_devices, and +lib/gpu/libgpu.a, lib/gpu/nvc_get_devices, and lib/gpu/Makefile.lammps. The latter has settings that enable LAMMPS to link with CUDA libraries. If the settings in Makefile.lammps for your machine are not correct, the LAMMPS build will fail, and @@ -211,14 +211,14 @@ minutes to hours) to build. Of course you only need to do that once.) -D LMP_DEBUG_CURL=value # set libcurl verbose mode on/off, value = off (default) or on -D LMP_NO_SSL_CHECK=value # tell libcurl to not verify the peer, value = no (default) or yes -If DOWNLOAD\_KIM is set, the KIM library will be downloaded and built +If DOWNLOAD_KIM is set, the KIM library will be downloaded and built inside the CMake build directory. If the KIM library is already on -your system (in a location CMake cannot find it), set the PKG\_CONFIG\_PATH +your system (in a location CMake cannot find it), set the PKG_CONFIG_PATH environment variable so that libkim-api can be found. *For using OpenKIM web queries in LAMMPS*\ : -If LMP\_DEBUG\_CURL is set, the libcurl verbose mode will be on, and any +If LMP_DEBUG_CURL is set, the libcurl verbose mode will be on, and any libcurl calls within the KIM web query display a lot of information about libcurl operations. You hardly ever want this set in production use, you will almost always want this when you debug/report problems. @@ -227,11 +227,11 @@ The libcurl performs peer SSL certificate verification by default. This verification is done using a CA certificate store that the SSL library can use to make sure the peer's server certificate is valid. If SSL reports an error ("certificate verify failed") during the handshake and thus refuses -further communication with that server, you can set LMP\_NO\_SSL\_CHECK. -If LMP\_NO\_SSL\_CHECK is set, libcurl does not verify the peer and connection +further communication with that server, you can set LMP_NO_SSL_CHECK. +If LMP_NO_SSL_CHECK is set, libcurl does not verify the peer and connection succeeds regardless of the names in the certificate. This option is insecure. As an alternative, you can specify your own CA cert path by setting the -environment variable CURL\_CA\_BUNDLE to the path of your choice. A call to the +environment variable CURL_CA_BUNDLE to the path of your choice. A call to the KIM web query would get this value from the environmental variable. **Traditional make**\ : @@ -252,7 +252,7 @@ invoke the lib/kim/Install.py script with the specified args. $ make lib-kim args="-p /usr/local -a EAM_Dynamo_Ackland_W__MO_141627196590_002" # ditto but add one model or driver Settings for OpenKIM web queries discussed above need to be applied by adding -them to the LMP\_INC variable through editing the Makefile.machine you are +them to the LMP_INC variable through editing the Makefile.machine you are using. For example: .. code-block:: make @@ -271,7 +271,7 @@ build for, either CPUs (multi-threading via OpenMP) or KNLs (OpenMP) or GPUs (NVIDIA Cuda). For a CMake or make build, these are the possible choices for the -KOKKOS\_ARCH settings described below. Note that for CMake, these are +KOKKOS_ARCH settings described below. Note that for CMake, these are really Kokkos variables, not LAMMPS variables. Hence you must use case-sensitive values, e.g. BDW, not bdw. @@ -334,7 +334,7 @@ For NVIDIA GPUs using CUDA, set these 4 variables: -D CMAKE_CXX_COMPILER=wrapper # wrapper = full path to Cuda nvcc wrapper The wrapper value is the Cuda nvcc compiler wrapper provided in the -Kokkos library: lib/kokkos/bin/nvcc\_wrapper. The setting should +Kokkos library: lib/kokkos/bin/nvcc_wrapper. The setting should include the full path name to the wrapper, e.g. .. code-block:: bash @@ -344,7 +344,7 @@ include the full path name to the wrapper, e.g. **Traditional make**\ : Choose which hardware to support in Makefile.machine via -KOKKOS\_DEVICES and KOKKOS\_ARCH settings. See the +KOKKOS_DEVICES and KOKKOS_ARCH settings. See the src/MAKE/OPTIONS/Makefile.kokkos\* files for examples. For multicore CPUs using OpenMP: @@ -400,10 +400,10 @@ library. -D DOWNLOAD_LATTE=value # download LATTE for build, value = no (default) or yes -D LATTE_LIBRARY=path # LATTE library file (only needed if a custom location) -If DOWNLOAD\_LATTE is set, the LATTE library will be downloaded and +If DOWNLOAD_LATTE is set, the LATTE library will be downloaded and built inside the CMake build directory. If the LATTE library is already on your system (in a location CMake cannot find it), -LATTE\_LIBRARY is the filename (plus path) of the LATTE library file, +LATTE_LIBRARY is the filename (plus path) of the LATTE library file, not the directory the library file is in. **Traditional make**\ : @@ -487,11 +487,11 @@ lib/mscg/README and MSCG/Install files for more details. -D MSCG_LIBRARY=path # MSCG library file (only needed if a custom location) -D MSCG_INCLUDE_DIR=path # MSCG include directory (only needed if a custom location) -If DOWNLOAD\_MSCG is set, the MSCG library will be downloaded and built +If DOWNLOAD_MSCG is set, the MSCG library will be downloaded and built inside the CMake build directory. If the MSCG library is already on -your system (in a location CMake cannot find it), MSCG\_LIBRARY is the +your system (in a location CMake cannot find it), MSCG_LIBRARY is the filename (plus path) of the MSCG library file, not the directory the -library file is in. MSCG\_INCLUDE\_DIR is the directory the MSCG +library file is in. MSCG_INCLUDE_DIR is the directory the MSCG include file is in. **Traditional make**\ : @@ -524,7 +524,7 @@ OPT package **CMake build**\ : -No additional settings are needed besides "-D PKG\_OPT=yes". +No additional settings are needed besides "-D PKG_OPT=yes". **Traditional make**\ : @@ -542,7 +542,7 @@ POEMS package **CMake build**\ : -No additional settings are needed besides "-D PKG\_OPT=yes". +No additional settings are needed besides "-D PKG_OPT=yes". **Traditional make**\ : @@ -588,7 +588,7 @@ lib/python/README for more details. Without this setting, CMake will guess the default Python on your system. To use a different Python version, you can either create a virtualenv, activate it and then run cmake. Or you can set the -PYTHON\_EXECUTABLE variable to specify which Python interpreter should +PYTHON_EXECUTABLE variable to specify which Python interpreter should be used. Note note that you will also need to have the development headers installed for this version, e.g. python2-devel. @@ -618,11 +618,11 @@ To build with this package, you must download and build the `Voro++ library ` command initializes the system by setting up the simulation box and assigning atoms to processors. If default values are not desired, the :doc:`processors ` and -:doc:`boundary ` commands need to be used before read\_data to +:doc:`boundary ` commands need to be used before read_data to tell LAMMPS how to map processors to the simulation box. Many input script errors are detected by LAMMPS and an ERROR or diff --git a/doc/src/Commands_parse.rst b/doc/src/Commands_parse.rst index 86d28bafbd..37283823d7 100644 --- a/doc/src/Commands_parse.rst +++ b/doc/src/Commands_parse.rst @@ -101,7 +101,7 @@ LAMMPS: print "B2 = ${b$a}" Nor can you specify an expression like "$($x-1.0)" for an immediate - variable, but you could use $(v\_x-1.0), since the latter is valid + variable, but you could use $(v_x-1.0), since the latter is valid syntax for an :doc:`equal-style variable `. See the :doc:`variable ` command for more details of how diff --git a/doc/src/Errors_common.rst b/doc/src/Errors_common.rst index d74d5f7f35..603952a29d 100644 --- a/doc/src/Errors_common.rst +++ b/doc/src/Errors_common.rst @@ -69,14 +69,14 @@ but a floating-point number 1.0 is provided): Some commands allow for using variable references in place of numeric constants so that the value can be evaluated and may change over the -course of a run. This is typically done with the syntax *v\_name* for a +course of a run. This is typically done with the syntax *v_name* for a parameter, where name is the name of the variable. On the other hand, immediate variable expansion with the syntax ${name} is performed while reading the input and before parsing commands, .. note:: - Using a variable reference (i.e. *v\_name*) is only allowed if + Using a variable reference (i.e. *v_name*) is only allowed if the documentation of the corresponding command explicitly says it is. Otherwise, you will receive an error message of this kind: diff --git a/doc/src/Errors_messages.rst b/doc/src/Errors_messages.rst index da36f18d82..6e52573b3e 100644 --- a/doc/src/Errors_messages.rst +++ b/doc/src/Errors_messages.rst @@ -39,9 +39,9 @@ Doc page with :doc:`WARNING messages ` *All angle coeffs are not set* All angle coefficients must be set in the data file or by the - angle\_coeff command before running a simulation. + angle_coeff command before running a simulation. -*All atom IDs = 0 but atom\_modify id = yes* +*All atom IDs = 0 but atom_modify id = yes* Self-explanatory. *All atoms of a swapped type must have same charge.* @@ -52,15 +52,15 @@ Doc page with :doc:`WARNING messages ` *All bond coeffs are not set* All bond coefficients must be set in the data file or by the - bond\_coeff command before running a simulation. + bond_coeff command before running a simulation. *All dihedral coeffs are not set* All dihedral coefficients must be set in the data file or by the - dihedral\_coeff command before running a simulation. + dihedral_coeff command before running a simulation. *All improper coeffs are not set* All improper coefficients must be set in the data file or by the - improper\_coeff command before running a simulation. + improper_coeff command before running a simulation. *All masses are not set* For atom styles that define masses for each atom type, all masses must @@ -76,9 +76,9 @@ Doc page with :doc:`WARNING messages ` *All pair coeffs are not set* All pair coefficients must be set in the data file or by the - pair\_coeff command before running a simulation. + pair_coeff command before running a simulation. -*All read\_dump x,y,z fields must be specified for scaled, triclinic coords* +*All read_dump x,y,z fields must be specified for scaled, triclinic coords* For triclinic boxes and scaled coordinates you must specify all 3 of the x,y,z fields, else LAMMPS cannot reconstruct the unscaled coordinates. @@ -89,8 +89,8 @@ Doc page with :doc:`WARNING messages ` *All variables in next command must be same style* Self-explanatory. -*Angle atom missing in delete\_bonds* - The delete\_bonds command cannot find one or more atoms in a particular +*Angle atom missing in delete_bonds* + The delete_bonds command cannot find one or more atoms in a particular angle on a particular processor. The pairwise cutoff is too short or the atoms are too far apart to make a valid angle. @@ -113,20 +113,20 @@ Doc page with :doc:`WARNING messages ` *Angle coeff for hybrid has invalid style* Angle style hybrid uses another angle style as one of its - coefficients. The angle style used in the angle\_coeff command or read + coefficients. The angle style used in the angle_coeff command or read from a restart file is not recognized. *Angle coeffs are not set* No angle coefficients have been assigned in the data file or via the - angle\_coeff command. + angle_coeff command. *Angle extent > half of periodic box length* - This error was detected by the neigh\_modify check yes setting. It is + This error was detected by the neigh_modify check yes setting. It is an error because the angle atoms are so far apart it is ambiguous how it should be defined. *Angle potential must be defined for SHAKE* - When shaking angles, an angle\_style potential must be used. + When shaking angles, an angle_style potential must be used. *Angle style hybrid cannot have hybrid as an argument* Self-explanatory. @@ -143,18 +143,18 @@ Doc page with :doc:`WARNING messages ` *Angle table parameters did not set N* List of angle table parameters must include N setting. -*Angle\_coeff command before angle\_style is defined* - Coefficients cannot be set in the data file or via the angle\_coeff - command until an angle\_style has been assigned. +*Angle_coeff command before angle_style is defined* + Coefficients cannot be set in the data file or via the angle_coeff + command until an angle_style has been assigned. -*Angle\_coeff command before simulation box is defined* - The angle\_coeff command cannot be used before a read\_data, - read\_restart, or create\_box command. +*Angle_coeff command before simulation box is defined* + The angle_coeff command cannot be used before a read_data, + read_restart, or create_box command. -*Angle\_coeff command when no angles allowed* +*Angle_coeff command when no angles allowed* The chosen atom style does not allow for angles to be defined. -*Angle\_style command when no angles allowed* +*Angle_style command when no angles allowed* The chosen atom style does not allow for angles to be defined. *Angles assigned incorrectly* @@ -211,7 +211,7 @@ Doc page with :doc:`WARNING messages ` This is probably because you have lost some atoms. *Atom in too many rigid bodies - boost MAXBODY* - Fix poems has a parameter MAXBODY (in fix\_poems.cpp) which determines + Fix poems has a parameter MAXBODY (in fix_poems.cpp) which determines the maximum number of rigid bodies a single atom can belong to (i.e. a multibody joint). The bodies you have defined exceed this limit. @@ -242,25 +242,25 @@ Doc page with :doc:`WARNING messages ` Atom-style variables generate one value per atom which is not allowed in an equal-style variable. -*Atom\_modify id command after simulation box is defined* - The atom\_modify id command cannot be used after a read\_data, - read\_restart, or create\_box command. +*Atom_modify id command after simulation box is defined* + The atom_modify id command cannot be used after a read_data, + read_restart, or create_box command. -*Atom\_modify map command after simulation box is defined* - The atom\_modify map command cannot be used after a read\_data, - read\_restart, or create\_box command. +*Atom_modify map command after simulation box is defined* + The atom_modify map command cannot be used after a read_data, + read_restart, or create_box command. -*Atom\_modify sort and first options cannot be used together* +*Atom_modify sort and first options cannot be used together* Self-explanatory. -*Atom\_style command after simulation box is defined* - The atom\_style command cannot be used after a read\_data, - read\_restart, or create\_box command. +*Atom_style command after simulation box is defined* + The atom_style command cannot be used after a read_data, + read_restart, or create_box command. -*Atom\_style line can only be used in 2d simulations* +*Atom_style line can only be used in 2d simulations* Self-explanatory. -*Atom\_style tri can only be used in 3d simulations* +*Atom_style tri can only be used in 3d simulations* Self-explanatory. *Atomfile variable could not read values* @@ -301,17 +301,17 @@ Doc page with :doc:`WARNING messages ` Specified bond type is not valid. *Bad fix ID in fix append/atoms command* - The value of the fix\_id for keyword spatial must start with 'f\_'. + The value of the fix_id for keyword spatial must start with 'f_'. *Bad grid of processors* The 3d grid of processors defined by the processors command does not match the number of processors LAMMPS is being run on. -*Bad kspace\_modify kmax/ewald parameter* - Kspace\_modify values for the kmax/ewald keyword must be integers > 0 +*Bad kspace_modify kmax/ewald parameter* + Kspace_modify values for the kmax/ewald keyword must be integers > 0 -*Bad kspace\_modify slab parameter* - Kspace\_modify value for the slab/volume keyword must be >= 2.0. +*Bad kspace_modify slab parameter* + Kspace_modify value for the slab/volume keyword must be >= 2.0. *Bad matrix inversion in mldivide3* This error should not occur unless the matrix is badly formed. @@ -331,16 +331,16 @@ Doc page with :doc:`WARNING messages ` the Newton-Rhaphson method, but found a non-positive or NaN cutoff *Balance command before simulation box is defined* - The balance command cannot be used before a read\_data, read\_restart, - or create\_box command. + The balance command cannot be used before a read_data, read_restart, + or create_box command. *Balance produced bad splits* This should not occur. It means two or more cutting plane locations are on top of each other or out of order. Report the problem to the developers. -*Balance rcb cannot be used with comm\_style brick* - Comm\_style tiled must be used instead. +*Balance rcb cannot be used with comm_style brick* + Comm_style tiled must be used instead. *Balance shift string is invalid* The string can only contain the characters "x", "y", or "z". @@ -367,10 +367,10 @@ Doc page with :doc:`WARNING messages ` *Bitmapped lookup tables require int/float be same size* Cannot use pair tables on this machine, because of word sizes. Use - the pair\_modify command with table 0 instead. + the pair_modify command with table 0 instead. *Bitmapped table in file does not match requested table* - Setting for bitmapped table in pair\_coeff command must match table + Setting for bitmapped table in pair_coeff command must match table in file exactly. *Bitmapped table is incorrect length in table file* @@ -385,8 +385,8 @@ Doc page with :doc:`WARNING messages ` processor. Typically this is because the pairwise cutoff is set too short or the bond has blown apart and an atom is too far away. -*Bond atom missing in delete\_bonds* - The delete\_bonds command cannot find one or more atoms in a particular +*Bond atom missing in delete_bonds* + The delete_bonds command cannot find one or more atoms in a particular bond on a particular processor. The pairwise cutoff is too short or the atoms are too far apart to make a valid bond. @@ -412,15 +412,15 @@ Doc page with :doc:`WARNING messages ` *Bond coeff for hybrid has invalid style* Bond style hybrid uses another bond style as one of its coefficients. - The bond style used in the bond\_coeff command or read from a restart + The bond style used in the bond_coeff command or read from a restart file is not recognized. *Bond coeffs are not set* No bond coefficients have been assigned in the data file or via the - bond\_coeff command. + bond_coeff command. *Bond extent > half of periodic box length* - This error was detected by the neigh\_modify check yes setting. It is + This error was detected by the neigh_modify check yes setting. It is an error because the bond atoms are so far apart it is ambiguous how it should be defined. @@ -444,7 +444,7 @@ Doc page with :doc:`WARNING messages ` This bond style can change the bond topology which is not allowed with this atom style. -*Bond style quartic requires special\_bonds = 1,1,1* +*Bond style quartic requires special_bonds = 1,1,1* This is a restriction of the current bond quartic implementation. *Bond table parameters did not set N* @@ -459,18 +459,18 @@ Doc page with :doc:`WARNING messages ` *BondBond coeff for hybrid angle has invalid format* No "bb" field should appear in data file entry. -*Bond\_coeff command before bond\_style is defined* - Coefficients cannot be set in the data file or via the bond\_coeff - command until an bond\_style has been assigned. +*Bond_coeff command before bond_style is defined* + Coefficients cannot be set in the data file or via the bond_coeff + command until an bond_style has been assigned. -*Bond\_coeff command before simulation box is defined* - The bond\_coeff command cannot be used before a read\_data, - read\_restart, or create\_box command. +*Bond_coeff command before simulation box is defined* + The bond_coeff command cannot be used before a read_data, + read_restart, or create_box command. -*Bond\_coeff command when no bonds allowed* +*Bond_coeff command when no bonds allowed* The chosen atom style does not allow for bonds to be defined. -*Bond\_style command when no bonds allowed* +*Bond_style command when no bonds allowed* The chosen atom style does not allow for bonds to be defined. *Bonds assigned incorrectly* @@ -481,7 +481,7 @@ Doc page with :doc:`WARNING messages ` The data file header lists bonds but no bond types. *Bond/react: Cannot use fix bond/react with non-molecular systems* - Only systems with bonds that can be changed can be used. Atom\_style + Only systems with bonds that can be changed can be used. Atom_style template does not qualify. *Bond/react: Invalid template atom ID in map file* @@ -513,7 +513,7 @@ Doc page with :doc:`WARNING messages ` *Bond/react: Fix bond/react needs ghost atoms from farther away* This is because a processor needs to map the entire unreacted molecule template onto simulation atoms it knows about. The - comm\_modify cutoff command can be used to extend the communication + comm_modify cutoff command can be used to extend the communication range. *Bond/react: A deleted atom cannot remain bonded to an atom that is not deleted* @@ -531,12 +531,12 @@ Doc page with :doc:`WARNING messages ` *Bond/react special bond generation overflow* The number of special bonds per-atom created by a reaction exceeds the - system setting. See the read\_data or create\_box command for how to + system setting. See the read_data or create_box command for how to specify this value. *Bond/react topology/atom exceed system topology/atom* The number of bonds, angles etc per-atom created by a reaction exceeds - the system setting. See the read\_data or create\_box command for how to + the system setting. See the read_data or create_box command for how to specify this value. *Both restart files must use % or neither* @@ -550,16 +550,16 @@ Doc page with :doc:`WARNING messages ` be periodic on both sides. *Boundary command after simulation box is defined* - The boundary command cannot be used after a read\_data, read\_restart, - or create\_box command. + The boundary command cannot be used after a read_data, read_restart, + or create_box command. *Box bounds are invalid* - The box boundaries specified in the read\_data file are invalid. The + The box boundaries specified in the read_data file are invalid. The lo value must be less than the hi value for all 3 dimensions. *Box command after simulation box is defined* - The box command cannot be used after a read\_data, read\_restart, or - create\_box command. + The box command cannot be used after a read_data, read_restart, or + create_box command. *CPU neighbor lists must be used for ellipsoid/sphere mix.* When using Gay-Berne or RE-squared pair styles with both ellipsoidal and @@ -609,7 +609,7 @@ Doc page with :doc:`WARNING messages ` *Cannot (yet) use PPPM with triclinic box and TIP4P* This feature is not yet supported. -*Cannot (yet) use PPPM with triclinic box and kspace\_modify diff ad* +*Cannot (yet) use PPPM with triclinic box and kspace_modify diff ad* This feature is not yet supported. *Cannot (yet) use PPPM with triclinic box and slab correction* @@ -618,10 +618,10 @@ Doc page with :doc:`WARNING messages ` *Cannot (yet) use kspace slab correction with long-range dipoles and non-neutral systems or per-atom energy* This feature is not yet supported. -*Cannot (yet) use kspace\_modify diff ad with compute group/group* +*Cannot (yet) use kspace_modify diff ad with compute group/group* This option is not yet supported. -*Cannot (yet) use kspace\_style pppm/stagger with triclinic systems* +*Cannot (yet) use kspace_style pppm/stagger with triclinic systems* This feature is not yet supported. *Cannot (yet) use molecular templates with Kokkos* @@ -636,7 +636,7 @@ Doc page with :doc:`WARNING messages ` *Cannot (yet) use rigid bodies with fix nh and Kokkos* Self-explanatory. -*Cannot (yet) use single precision with MSM (remove -DFFT\_SINGLE from Makefile and re-compile)* +*Cannot (yet) use single precision with MSM (remove -DFFT_SINGLE from Makefile and re-compile)* Single precision cannot be used with MSM. *Cannot add atoms to fix move variable* @@ -668,10 +668,10 @@ Doc page with :doc:`WARNING messages ` *Cannot change box z boundary to non-periodic for a 2d simulation* Self-explanatory. -*Cannot change dump\_modify every for dump dcd* +*Cannot change dump_modify every for dump dcd* The frequency of writing dump dcd snapshots cannot be changed. -*Cannot change dump\_modify every for dump xtc* +*Cannot change dump_modify every for dump xtc* The frequency of writing dump xtc snapshots cannot be changed. *Cannot change timestep once fix srd is setup* @@ -682,18 +682,18 @@ Doc page with :doc:`WARNING messages ` This is because fix pour pre-computes the time delay for particles to fall out of the insertion volume due to gravity. -*Cannot change to comm\_style brick from tiled layout* +*Cannot change to comm_style brick from tiled layout* Self-explanatory. -*Cannot change\_box after reading restart file with per-atom info* +*Cannot change_box after reading restart file with per-atom info* This is because the restart file info cannot be migrated with the atoms. You can get around this by performing a 0-timestep run which will assign the restart file info to actual atoms. -*Cannot change\_box in xz or yz for 2d simulation* +*Cannot change_box in xz or yz for 2d simulation* Self-explanatory. -*Cannot change\_box in z dimension for 2d simulation* +*Cannot change_box in z dimension for 2d simulation* Self-explanatory. *Cannot clear group all* @@ -703,8 +703,8 @@ Doc page with :doc:`WARNING messages ` This error was generated by MPI when reading/writing an MPI-IO restart file. -*Cannot compute initial g\_ewald\_disp* - LAMMPS failed to compute an initial guess for the PPPM\_disp g\_ewald\_6 +*Cannot compute initial g_ewald_disp* + LAMMPS failed to compute an initial guess for the PPPM_disp g_ewald_6 factor that partitions the computation between real space and k-space for Dispersion interactions. @@ -713,19 +713,19 @@ Doc page with :doc:`WARNING messages ` but the atoms that have been defined have no IDs. *Cannot create atoms with undefined lattice* - Must use the lattice command before using the create\_atoms + Must use the lattice command before using the create_atoms command. *Cannot create/grow a vector/array of pointers for %s* LAMMPS code is making an illegal call to the templated memory allocaters, to create a vector or array of pointers. -*Cannot create\_atoms after reading restart file with per-atom info* +*Cannot create_atoms after reading restart file with per-atom info* The per-atom info was stored to be used when by a fix that you may re-define. If you add atoms before re-defining the fix, then there will not be a correct amount of per-atom info. -*Cannot create\_box after simulation box is defined* +*Cannot create_box after simulation box is defined* A simulation box can only be defined once. *Cannot currently use pair reax with pair hybrid* @@ -746,24 +746,24 @@ Doc page with :doc:`WARNING messages ` *Cannot delete group currently used by a fix* Self-explanatory. -*Cannot delete group currently used by atom\_modify first* +*Cannot delete group currently used by atom_modify first* Self-explanatory. -*Cannot delete\_atoms bond yes for non-molecular systems* +*Cannot delete_atoms bond yes for non-molecular systems* Self-explanatory. -*Cannot displace\_atoms after reading restart file with per-atom info* +*Cannot displace_atoms after reading restart file with per-atom info* This is because the restart file info cannot be migrated with the atoms. You can get around this by performing a 0-timestep run which will assign the restart file info to actual atoms. -*Cannot do GCMC on atoms in atom\_modify first group* +*Cannot do GCMC on atoms in atom_modify first group* This is a restriction due to the way atoms are organized in a list to - enable the atom\_modify first command. + enable the atom_modify first command. -*Cannot do atom/swap on atoms in atom\_modify first group* +*Cannot do atom/swap on atoms in atom_modify first group* This is a restriction due to the way atoms are organized in a list to - enable the atom\_modify first command. + enable the atom_modify first command. *Cannot dump sort on atom IDs with no atom IDs defined* Self-explanatory. @@ -776,15 +776,15 @@ Doc page with :doc:`WARNING messages ` When running LAMMPS via Python through the LAMMPS library interface you cannot also user the input script python command. -*Cannot evaporate atoms in atom\_modify first group* +*Cannot evaporate atoms in atom_modify first group* This is a restriction due to the way atoms are organized in - a list to enable the atom\_modify first command. + a list to enable the atom_modify first command. -*Cannot find create\_bonds group ID* +*Cannot find create_bonds group ID* Self-explanatory. -*Cannot find delete\_bonds group ID* - Group ID used in the delete\_bonds command does not exist. +*Cannot find delete_bonds group ID* + Group ID used in the delete_bonds command does not exist. *Cannot find specified group ID for core particles* Self-explanatory. @@ -792,7 +792,7 @@ Doc page with :doc:`WARNING messages ` *Cannot find specified group ID for shell particles* Self-explanatory. -*Cannot have both pair\_modify shift and tail set to yes* +*Cannot have both pair_modify shift and tail set to yes* These 2 options are contradictory. *Cannot intersect groups using a dynamic group* @@ -958,7 +958,7 @@ Doc page with :doc:`WARNING messages ` *Cannot open gzipped file* LAMMPS was compiled without support for reading and writing gzipped - files through a pipeline to the gzip program with -DLAMMPS\_GZIP. + files through a pipeline to the gzip program with -DLAMMPS_GZIP. *Cannot open input script %s* Self-explanatory. @@ -989,7 +989,7 @@ Doc page with :doc:`WARNING messages ` The specified potential file cannot be opened. Check that the path and name are correct. -*Cannot open pair\_write file* +*Cannot open pair_write file* The specified output file for pair energies and forces cannot be opened. Check that the path and name are correct. @@ -1036,12 +1036,12 @@ Doc page with :doc:`WARNING messages ` This error was generated by MPI when reading/writing an MPI-IO restart file. -*Cannot read\_data without add keyword after simulation box is defined* +*Cannot read_data without add keyword after simulation box is defined* Self-explanatory. -*Cannot read\_restart after simulation box is defined* - The read\_restart command cannot be used after a read\_data, - read\_restart, or create\_box command. +*Cannot read_restart after simulation box is defined* + The read_restart command cannot be used after a read_data, + read_restart, or create_box command. *Cannot redefine variable as a different style* An equal-style variable can be re-defined but only if it was @@ -1086,7 +1086,7 @@ Doc page with :doc:`WARNING messages ` *Cannot set dpd/theta for this atom style* Self-explanatory. -*Cannot set dump\_modify flush for dump xtc* +*Cannot set dump_modify flush for dump xtc* Self-explanatory. *Cannot set mass for this atom style* @@ -1162,7 +1162,7 @@ Doc page with :doc:`WARNING messages ` *Cannot use Ewald with 2d simulation* The kspace style ewald cannot be used in 2d simulations. You can use - 2d Ewald in a 3d simulation; see the kspace\_modify command. + 2d Ewald in a 3d simulation; see the kspace_modify command. *Cannot use Ewald/disp solver on system with no charge, dipole, or LJ particles* No atoms in system have a non-zero charge or dipole, or are LJ @@ -1176,21 +1176,21 @@ Doc page with :doc:`WARNING messages ` Self-explanatory. *Cannot use NEB unless atom map exists* - Use the atom\_modify command to create an atom map. + Use the atom_modify command to create an atom map. *Cannot use NEB with a single replica* Self-explanatory. -*Cannot use NEB with atom\_modify sort enabled* +*Cannot use NEB with atom_modify sort enabled* This is current restriction for NEB implemented in LAMMPS. *Cannot use PPPM with 2d simulation* The kspace style pppm cannot be used in 2d simulations. You can use - 2d PPPM in a 3d simulation; see the kspace\_modify command. + 2d PPPM in a 3d simulation; see the kspace_modify command. *Cannot use PPPMDisp with 2d simulation* The kspace style pppm/disp cannot be used in 2d simulations. You can - use 2d pppm/disp in a 3d simulation; see the kspace\_modify command. + use 2d pppm/disp in a 3d simulation; see the kspace_modify command. *Cannot use PRD with a changing box* The current box dimensions are not copied between replicas @@ -1201,20 +1201,20 @@ Doc page with :doc:`WARNING messages ` *Cannot use PRD with a time-dependent region defined* PRD alters the timestep in ways that will mess up these regions. -*Cannot use PRD with atom\_modify sort enabled* +*Cannot use PRD with atom_modify sort enabled* This is a current restriction of PRD. You must turn off sorting, - which is enabled by default, via the atom\_modify command. + which is enabled by default, via the atom_modify command. *Cannot use PRD with multi-processor replicas unless atom map exists* - Use the atom\_modify command to create an atom map. + Use the atom_modify command to create an atom map. *Cannot use TAD unless atom map exists for NEB* - See atom\_modify map command to set this. + See atom_modify map command to set this. *Cannot use TAD with a single replica for NEB* NEB requires multiple replicas. -*Cannot use TAD with atom\_modify sort enabled for NEB* +*Cannot use TAD with atom_modify sort enabled for NEB* This is a current restriction of NEB. *Cannot use a damped dynamics min style with fix box/relax* @@ -1230,7 +1230,7 @@ Doc page with :doc:`WARNING messages ` type p (periodic). *Cannot use atomfile-style variable unless atom map exists* - Self-explanatory. See the atom\_modify command to create a map. + Self-explanatory. See the atom_modify command to create a map. *Cannot use both com and bias with compute temp/chunk* Self-explanatory. @@ -1322,34 +1322,34 @@ Doc page with :doc:`WARNING messages ` *Cannot use compute cluster/atom unless atoms have IDs* Atom IDs are used to identify clusters. -*Cannot use create\_atoms rotate unless single style* +*Cannot use create_atoms rotate unless single style* Self-explanatory. -*Cannot use create\_bonds unless atoms have IDs* +*Cannot use create_bonds unless atoms have IDs* This command requires a mapping from global atom IDs to local atoms, but the atoms that have been defined have no IDs. -*Cannot use create\_bonds with non-molecular system* +*Cannot use create_bonds with non-molecular system* Self-explanatory. *Cannot use cwiggle in variable formula between runs* This is a function of elapsed time. -*Cannot use delete\_atoms bond yes with atom\_style template* +*Cannot use delete_atoms bond yes with atom_style template* This is because the bonds for that atom style are hardwired in the molecule template. -*Cannot use delete\_atoms unless atoms have IDs* - Your atoms do not have IDs, so the delete\_atoms command cannot be +*Cannot use delete_atoms unless atoms have IDs* + Your atoms do not have IDs, so the delete_atoms command cannot be used. -*Cannot use delete\_bonds with non-molecular system* +*Cannot use delete_bonds with non-molecular system* Your choice of atom style does not have bonds. -*Cannot use dump\_modify fileper without % in dump file name* +*Cannot use dump_modify fileper without % in dump file name* Self-explanatory. -*Cannot use dump\_modify nfile without % in dump file name* +*Cannot use dump_modify nfile without % in dump file name* Self-explanatory. *Cannot use dynamic group with fix adapt atom* @@ -1358,19 +1358,19 @@ Doc page with :doc:`WARNING messages ` *Cannot use fix TMD unless atom map exists* Using this fix requires the ability to lookup an atom index, which is provided by an atom map. An atom map does not exist (by default) for - non-molecular problems. Using the atom\_modify map command will force + non-molecular problems. Using the atom_modify map command will force an atom map to be created. *Cannot use fix bond/break with non-molecular systems* - Only systems with bonds that can be changed can be used. Atom\_style + Only systems with bonds that can be changed can be used. Atom_style template does not qualify. *Cannot use fix bond/create with non-molecular systems* - Only systems with bonds that can be changed can be used. Atom\_style + Only systems with bonds that can be changed can be used. Atom_style template does not qualify. *Cannot use fix bond/swap with non-molecular systems* - Only systems with bonds that can be changed can be used. Atom\_style + Only systems with bonds that can be changed can be used. Atom_style template does not qualify. *Cannot use fix box/relax on a 2nd non-periodic dimension* @@ -1477,7 +1477,7 @@ Doc page with :doc:`WARNING messages ` *Cannot use fix press/berendsen with triclinic box* Self-explanatory. -*Cannot use fix reax/bonds without pair\_style reax* +*Cannot use fix reax/bonds without pair_style reax* Self-explanatory. *Cannot use fix rigid npt/nph and fix deform on same component of stress tensor* @@ -1531,10 +1531,10 @@ Doc page with :doc:`WARNING messages ` *Cannot use fix wall/srd zlo/zhi for a 2d simulation* Self-explanatory. -*Cannot use fix\_deposit unless atoms have IDs* +*Cannot use fix_deposit unless atoms have IDs* Self-explanatory. -*Cannot use fix\_pour unless atoms have IDs* +*Cannot use fix_pour unless atoms have IDs* Self-explanatory. *Cannot use include command within an if command* @@ -1555,7 +1555,7 @@ Doc page with :doc:`WARNING messages ` *Cannot use multiple fix wall commands with pair lubricateU* Self-explanatory. -*Cannot use neigh\_modify exclude with GPU neighbor builds* +*Cannot use neigh_modify exclude with GPU neighbor builds* This is a current limitation of the GPU implementation in LAMMPS. @@ -1705,22 +1705,22 @@ Doc page with :doc:`WARNING messages ` *Cannot use non-periodic boundaries with Ewald* For kspace style ewald, all 3 dimensions must have periodic boundaries - unless you use the kspace\_modify command to define a 2d slab with a + unless you use the kspace_modify command to define a 2d slab with a non-periodic z dimension. *Cannot use non-periodic boundaries with EwaldDisp* For kspace style ewald/disp, all 3 dimensions must have periodic - boundaries unless you use the kspace\_modify command to define a 2d + boundaries unless you use the kspace_modify command to define a 2d slab with a non-periodic z dimension. *Cannot use non-periodic boundaries with PPPM* For kspace style pppm, all 3 dimensions must have periodic boundaries - unless you use the kspace\_modify command to define a 2d slab with a + unless you use the kspace_modify command to define a 2d slab with a non-periodic z dimension. *Cannot use non-periodic boundaries with PPPMDisp* For kspace style pppm/disp, all 3 dimensions must have periodic - boundaries unless you use the kspace\_modify command to define a 2d + boundaries unless you use the kspace_modify command to define a 2d slab with a non-periodic z dimension. *Cannot use order greater than 8 with pppm/gpu.* @@ -1738,21 +1738,21 @@ Doc page with :doc:`WARNING messages ` *Cannot use ramp in variable formula between runs* This is because the ramp() function is time dependent. -*Cannot use read\_data add before simulation box is defined* +*Cannot use read_data add before simulation box is defined* Self-explanatory. -*Cannot use read\_data extra with add flag* +*Cannot use read_data extra with add flag* Self-explanatory. -*Cannot use read\_data offset without add flag* +*Cannot use read_data offset without add flag* Self-explanatory. -*Cannot use read\_data shift without add flag* +*Cannot use read_data shift without add flag* Self-explanatory. *Cannot use region INF or EDGE when box does not exist* Regions that extend to the box boundaries can only be used after the - create\_box command has been used. + create_box command has been used. *Cannot use set atom with no atom IDs defined* Atom IDs are not defined, so they cannot be used to identify an atom. @@ -1793,10 +1793,10 @@ Doc page with :doc:`WARNING messages ` *Cannot use wall in periodic dimension* Self-explanatory. -*Cannot use write\_restart fileper without % in restart file name* +*Cannot use write_restart fileper without % in restart file name* Self-explanatory. -*Cannot use write\_restart nfile without % in restart file name* +*Cannot use write_restart nfile without % in restart file name* Self-explanatory. *Cannot wiggle and shear fix wall/gran* @@ -1809,10 +1809,10 @@ Doc page with :doc:`WARNING messages ` *Cannot yet use KSpace solver with grid with comm style tiled* This is current restriction in LAMMPS. -*Cannot yet use comm\_style tiled with multi-mode comm* +*Cannot yet use comm_style tiled with multi-mode comm* Self-explanatory. -*Cannot yet use comm\_style tiled with triclinic box* +*Cannot yet use comm_style tiled with triclinic box* Self-explanatory. *Cannot yet use compute tally with Kokkos* @@ -1840,10 +1840,10 @@ Doc page with :doc:`WARNING messages ` *Cannot zero momentum of no atoms* Self-explanatory. -*Change\_box command before simulation box is defined* +*Change_box command before simulation box is defined* Self-explanatory. -*Change\_box volume used incorrectly* +*Change_box volume used incorrectly* The "dim volume" option must be used immediately following one or two settings for "dim1 ..." (and optionally "dim2 ...") and must be for a different dimension, i.e. dim != dim1 and dim != dim2. @@ -1882,23 +1882,23 @@ Doc page with :doc:`WARNING messages ` Self-explanatory. *Comm tiled invalid index in box drop brick* - Internal error check in comm\_style tiled which should not occur. + Internal error check in comm_style tiled which should not occur. Contact the developers. *Comm tiled mis-match in box drop brick* - Internal error check in comm\_style tiled which should not occur. + Internal error check in comm_style tiled which should not occur. Contact the developers. -*Comm\_modify group != atom\_modify first group* +*Comm_modify group != atom_modify first group* Self-explanatory. -*Communication cutoff for comm\_style tiled cannot exceed periodic box length* +*Communication cutoff for comm_style tiled cannot exceed periodic box length* Self-explanatory. *Communication cutoff too small for SNAP micro load balancing* - This can happen if you change the neighbor skin after your pair\_style + This can happen if you change the neighbor skin after your pair_style command or if your box dimensions grow during a run. You can set the - cutoff explicitly via the comm\_modify cutoff command. + cutoff explicitly via the comm_modify cutoff command. *Compute %s does not allow use of dynamic group* Dynamic groups have not yet been enabled for this compute. @@ -2188,7 +2188,7 @@ Doc page with :doc:`WARNING messages ` Only inputs that generate the same number of datums can be used together. E.g. bond and angle quantities cannot be mixed. -*Compute property/local does not (yet) work with atom\_style template* +*Compute property/local does not (yet) work with atom_style template* Self-explanatory. *Compute property/local for property that isn't allocated* @@ -2306,7 +2306,7 @@ Doc page with :doc:`WARNING messages ` The style of the specified compute is not chunk/atom. *Compute temp/cs requires ghost atoms store velocity* - Use the comm\_modify vel yes command to enable this. + Use the comm_modify vel yes command to enable this. *Compute temp/cs used when bonds are not allowed* This compute only works on pairs of bonded particles. @@ -2368,14 +2368,14 @@ Doc page with :doc:`WARNING messages ` *Core/shell partners were not all found* Could not find or more atoms in the bond pairs. -*Could not adjust g\_ewald\_6* +*Could not adjust g_ewald_6* The Newton-Raphson solver failed to converge to a good value for - g\_ewald. This error should not occur for typical problems. Please + g_ewald. This error should not occur for typical problems. Please send an email to the developers. -*Could not compute g\_ewald* +*Could not compute g_ewald* The Newton-Raphson solver failed to converge to a good value for - g\_ewald. This error should not occur for typical problems. Please + g_ewald. This error should not occur for typical problems. Please send an email to the developers. *Could not compute grid size* @@ -2426,11 +2426,11 @@ Doc page with :doc:`WARNING messages ` The provided Python code was run successfully, but it not define a callable function with the required name. -*Could not find atom\_modify first group ID* +*Could not find atom_modify first group ID* Self-explanatory. -*Could not find change\_box group ID* - Group ID used in the change\_box command does not exist. +*Could not find change_box group ID* + Group ID used in the change_box command does not exist. *Could not find compute ID for PRD* Self-explanatory. @@ -2474,20 +2474,20 @@ Doc page with :doc:`WARNING messages ` *Could not find compute/voronoi surface group ID* Self-explanatory. -*Could not find compute\_modify ID* +*Could not find compute_modify ID* Self-explanatory. *Could not find custom per-atom property ID* Self-explanatory. -*Could not find delete\_atoms group ID* - Group ID used in the delete\_atoms command does not exist. +*Could not find delete_atoms group ID* + Group ID used in the delete_atoms command does not exist. -*Could not find delete\_atoms region ID* - Region ID used in the delete\_atoms command does not exist. +*Could not find delete_atoms region ID* + Region ID used in the delete_atoms command does not exist. -*Could not find displace\_atoms group ID* - Group ID used in the displace\_atoms command does not exist. +*Could not find displace_atoms group ID* + Group ID used in the displace_atoms command does not exist. *Could not find dump custom compute ID* Self-explanatory. @@ -2553,13 +2553,13 @@ Doc page with :doc:`WARNING messages ` *Could not find fix srd group ID* Self-explanatory. -*Could not find fix\_modify ID* - A fix ID used in the fix\_modify command does not exist. +*Could not find fix_modify ID* + A fix ID used in the fix_modify command does not exist. -*Could not find fix\_modify pressure ID* +*Could not find fix_modify pressure ID* The compute ID for computing pressure does not exist. -*Could not find fix\_modify temperature ID* +*Could not find fix_modify temperature ID* The compute ID for computing temperature does not exist. *Could not find group clear group ID* @@ -2579,7 +2579,7 @@ Doc page with :doc:`WARNING messages ` Self-explanatory. *Could not find thermo compute ID* - Compute ID specified in thermo\_style command does not exist. + Compute ID specified in thermo_style command does not exist. *Could not find thermo custom compute ID* The compute ID needed by thermo style custom to compute a requested @@ -2593,16 +2593,16 @@ Doc page with :doc:`WARNING messages ` Self-explanatory. *Could not find thermo fix ID* - Fix ID specified in thermo\_style command does not exist. + Fix ID specified in thermo_style command does not exist. *Could not find thermo variable name* Self-explanatory. -*Could not find thermo\_modify pressure ID* +*Could not find thermo_modify pressure ID* The compute ID needed by thermo style custom to compute pressure does not exist. -*Could not find thermo\_modify temperature ID* +*Could not find thermo_modify temperature ID* The compute ID needed by thermo style custom to compute temperature does not exist. @@ -2646,66 +2646,66 @@ Doc page with :doc:`WARNING messages ` *Coulomb PPPMDisp order has been reduced below minorder* The default minimum order is 2. This can be reset by the - kspace\_modify minorder command. + kspace_modify minorder command. -*Coulombic cutoff not supported in pair\_style buck/long/coul/coul* +*Coulombic cutoff not supported in pair_style buck/long/coul/coul* Must use long-range Coulombic interactions. -*Coulombic cutoff not supported in pair\_style lj/long/coul/long* +*Coulombic cutoff not supported in pair_style lj/long/coul/long* Must use long-range Coulombic interactions. -*Coulombic cutoff not supported in pair\_style lj/long/tip4p/long* +*Coulombic cutoff not supported in pair_style lj/long/tip4p/long* Must use long-range Coulombic interactions. *Coulombic cutoffs of pair hybrid sub-styles do not match* If using a Kspace solver, all Coulombic cutoffs of long pair styles must be the same. -*Coulombic cut not supported in pair\_style lj/long/dipole/long* +*Coulombic cut not supported in pair_style lj/long/dipole/long* Must use long-range Coulombic interactions. -*Cound not find dump\_modify ID* +*Cound not find dump_modify ID* Self-explanatory. -*Create\_atoms command before simulation box is defined* - The create\_atoms command cannot be used before a read\_data, - read\_restart, or create\_box command. +*Create_atoms command before simulation box is defined* + The create_atoms command cannot be used before a read_data, + read_restart, or create_box command. -*Create\_atoms molecule has atom IDs, but system does not* - The atom\_style id command can be used to force atom IDs to be stored. +*Create_atoms molecule has atom IDs, but system does not* + The atom_style id command can be used to force atom IDs to be stored. -*Create\_atoms molecule must have atom types* +*Create_atoms molecule must have atom types* The defined molecule does not specify atom types. -*Create\_atoms molecule must have coordinates* +*Create_atoms molecule must have coordinates* The defined molecule does not specify coordinates. -*Create\_atoms region ID does not exist* - A region ID used in the create\_atoms command does not exist. +*Create_atoms region ID does not exist* + A region ID used in the create_atoms command does not exist. -*Create\_bonds command before simulation box is defined* +*Create_bonds command before simulation box is defined* Self-explanatory. -*Create\_bonds command requires no kspace\_style be defined* +*Create_bonds command requires no kspace_style be defined* This is so that atom pairs that are already bonded to not appear in the neighbor list. -*Create\_bonds command requires special\_bonds 1-2 weights be 0.0* +*Create_bonds command requires special_bonds 1-2 weights be 0.0* This is so that atom pairs that are already bonded to not appear in the neighbor list. -*Create\_bonds max distance > neighbor cutoff* +*Create_bonds max distance > neighbor cutoff* Can only create bonds for atom pairs that will be in neighbor list. -*Create\_bonds requires a pair style be defined* +*Create_bonds requires a pair style be defined* Self-explanatory. -*Create\_box region ID does not exist* +*Create_box region ID does not exist* Self-explanatory. -*Create\_box region does not support a bounding box* +*Create_box region does not support a bounding box* Not all regions represent bounded volumes. You cannot use - such a region with the create\_box command. + such a region with the create_box command. *Custom floating point vector for fix store/state does not exist* The command is accessing a vector added by the fix property/atom @@ -2721,13 +2721,13 @@ Doc page with :doc:`WARNING messages ` *Custom per-atom property ID is not integer* Self-explanatory. -*Cut-offs missing in pair\_style lj/long/dipole/long* +*Cut-offs missing in pair_style lj/long/dipole/long* Self-explanatory. -*Cutoffs missing in pair\_style buck/long/coul/long* +*Cutoffs missing in pair_style buck/long/coul/long* Self-explanatory. -*Cutoffs missing in pair\_style lj/long/coul/long* +*Cutoffs missing in pair_style lj/long/coul/long* Self-explanatory. *Cyclic loop in joint connections* @@ -2740,26 +2740,26 @@ Doc page with :doc:`WARNING messages ` *Delete region ID does not exist* Self-explanatory. -*Delete\_atoms command before simulation box is defined* - The delete\_atoms command cannot be used before a read\_data, - read\_restart, or create\_box command. +*Delete_atoms command before simulation box is defined* + The delete_atoms command cannot be used before a read_data, + read_restart, or create_box command. -*Delete\_atoms cutoff > max neighbor cutoff* +*Delete_atoms cutoff > max neighbor cutoff* Can only delete atoms in atom pairs that will be in neighbor list. -*Delete\_atoms mol yes requires atom attribute molecule* +*Delete_atoms mol yes requires atom attribute molecule* Cannot use this option with a non-molecular system. -*Delete\_atoms requires a pair style be defined* +*Delete_atoms requires a pair style be defined* This is because atom deletion within a cutoff uses a pairwise neighbor list. -*Delete\_bonds command before simulation box is defined* - The delete\_bonds command cannot be used before a read\_data, - read\_restart, or create\_box command. +*Delete_bonds command before simulation box is defined* + The delete_bonds command cannot be used before a read_data, + read_restart, or create_box command. -*Delete\_bonds command with no atoms existing* - No atoms are yet defined so the delete\_bonds command cannot be used. +*Delete_bonds command with no atoms existing* + No atoms are yet defined so the delete_bonds command cannot be used. *Deposition region extends outside simulation box* Self-explanatory. @@ -2773,7 +2773,7 @@ Doc page with :doc:`WARNING messages ` Atoms read in from the restart file were not assigned correctly to processors. This is likely due to some atom coordinates being outside a non-periodic simulation box. Normally this should not happen. You - may wish to use the "remap" option on the read\_restart command to see + may wish to use the "remap" option on the read_restart command to see if this helps. *Did not find all elements in MEAM library file* @@ -2781,12 +2781,12 @@ Doc page with :doc:`WARNING messages ` *Did not find fix shake partner info* Could not find bond partners implied by fix shake command. This error - can be triggered if the delete\_bonds command was used before fix + can be triggered if the delete_bonds command was used before fix shake, and it removed bonds without resetting the 1-2, 1-3, 1-4 weighting list via the special keyword. *Did not find keyword in table file* - Keyword used in pair\_coeff command was not found in table file. + Keyword used in pair_coeff command was not found in table file. *Did not set pressure for fix rigid/nph* The press keyword must be specified. @@ -2803,8 +2803,8 @@ Doc page with :doc:`WARNING messages ` *Did not set temperature or pressure for fix rigid/npt* The temp and press keywords must be specified. -*Dihedral atom missing in delete\_bonds* - The delete\_bonds command cannot find one or more atoms in a particular +*Dihedral atom missing in delete_bonds* + The delete_bonds command cannot find one or more atoms in a particular dihedral on a particular processor. The pairwise cutoff is too short or the atoms are too far apart to make a valid dihedral. @@ -2831,12 +2831,12 @@ Doc page with :doc:`WARNING messages ` *Dihedral coeff for hybrid has invalid style* Dihedral style hybrid uses another dihedral style as one of its - coefficients. The dihedral style used in the dihedral\_coeff command + coefficients. The dihedral style used in the dihedral_coeff command or read from a restart file is not recognized. *Dihedral coeffs are not set* No dihedral coefficients have been assigned in the data file or via - the dihedral\_coeff command. + the dihedral_coeff command. *Dihedral style hybrid cannot have hybrid as an argument* Self-explanatory. @@ -2848,22 +2848,22 @@ Doc page with :doc:`WARNING messages ` Self-explanatory. *Dihedral/improper extent > half of periodic box length* - This error was detected by the neigh\_modify check yes setting. It is + This error was detected by the neigh_modify check yes setting. It is an error because the dihedral atoms are so far apart it is ambiguous how it should be defined. -*Dihedral\_coeff command before dihedral\_style is defined* - Coefficients cannot be set in the data file or via the dihedral\_coeff - command until an dihedral\_style has been assigned. +*Dihedral_coeff command before dihedral_style is defined* + Coefficients cannot be set in the data file or via the dihedral_coeff + command until an dihedral_style has been assigned. -*Dihedral\_coeff command before simulation box is defined* - The dihedral\_coeff command cannot be used before a read\_data, - read\_restart, or create\_box command. +*Dihedral_coeff command before simulation box is defined* + The dihedral_coeff command cannot be used before a read_data, + read_restart, or create_box command. -*Dihedral\_coeff command when no dihedrals allowed* +*Dihedral_coeff command when no dihedrals allowed* The chosen atom style does not allow for dihedrals to be defined. -*Dihedral\_style command when no dihedrals allowed* +*Dihedral_style command when no dihedrals allowed* The chosen atom style does not allow for dihedrals to be defined. *Dihedrals assigned incorrectly* @@ -2875,16 +2875,16 @@ Doc page with :doc:`WARNING messages ` The data file header lists dihedrals but no dihedral types. *Dimension command after simulation box is defined* - The dimension command cannot be used after a read\_data, - read\_restart, or create\_box command. + The dimension command cannot be used after a read_data, + read_restart, or create_box command. *Dispersion PPPMDisp order has been reduced below minorder* The default minimum order is 2. This can be reset by the - kspace\_modify minorder command. + kspace_modify minorder command. -*Displace\_atoms command before simulation box is defined* - The displace\_atoms command cannot be used before a read\_data, - read\_restart, or create\_box command. +*Displace_atoms command before simulation box is defined* + The displace_atoms command cannot be used before a read_data, + read_restart, or create_box command. *Distance must be > 0 for compute event/displace* Self-explanatory. @@ -2963,7 +2963,7 @@ Doc page with :doc:`WARNING messages ` Every snapshot written by dump dcd must contain the same # of atoms. *Dump dcd requires sorting by atom ID* - Use the dump\_modify sort command to enable this. + Use the dump_modify sort command to enable this. *Dump every variable returned a bad timestep* The variable must return a timestep greater than the current timestep. @@ -3076,19 +3076,19 @@ Doc page with :doc:`WARNING messages ` Self-explanatory. *Dump xtc requires sorting by atom ID* - Use the dump\_modify sort command to enable this. + Use the dump_modify sort command to enable this. *Dump xyz/gz only writes compressed files* The dump xyz/gz output file name must have a .gz suffix. -*Dump\_modify buffer yes not allowed for this style* +*Dump_modify buffer yes not allowed for this style* Self-explanatory. -*Dump\_modify format string is too short* +*Dump_modify format string is too short* There are more fields to be dumped in a line of output than your format string specifies. -*Dump\_modify region ID does not exist* +*Dump_modify region ID does not exist* Self-explanatory. *Dumping an atom property that isn't allocated* @@ -3098,7 +3098,7 @@ Doc page with :doc:`WARNING messages ` *Duplicate atom IDs exist* Self-explanatory. -*Duplicate fields in read\_dump command* +*Duplicate fields in read_dump command* Self-explanatory. *Duplicate particle in PeriDynamic bond - simulation box is too small* @@ -3205,7 +3205,7 @@ Doc page with :doc:`WARNING messages ` *Fix ID for fix vector does not exist* Self-explanatory. -*Fix ID for read\_data does not exist* +*Fix ID for read_data does not exist* Self-explanatory. *Fix ID for velocity does not exist* @@ -3227,7 +3227,7 @@ Doc page with :doc:`WARNING messages ` conservative settings. *Fix SRD: too many big particles in bin* - Reset the ATOMPERBIN parameter at the top of fix\_srd.cpp + Reset the ATOMPERBIN parameter at the top of fix_srd.cpp to a larger value, and re-compile the code. *Fix SRD: too many walls in bin* @@ -3473,15 +3473,15 @@ Doc page with :doc:`WARNING messages ` *Fix ave/time variable is not equal-style variable* Self-explanatory. -*Fix balance rcb cannot be used with comm\_style brick* - Comm\_style tiled must be used instead. +*Fix balance rcb cannot be used with comm_style brick* + Comm_style tiled must be used instead. *Fix balance shift string is invalid* The string can only contain the characters "x", "y", or "z". *Fix bond/break needs ghost atoms from further away* This is because the fix needs to walk bonds to a certain distance to - acquire needed info, The comm\_modify cutoff command can be used to + acquire needed info, The comm_modify cutoff command can be used to extend the communication range. *Fix bond/create angle type is invalid* @@ -3498,13 +3498,13 @@ Doc page with :doc:`WARNING messages ` Self-explanatory. *Fix bond/create induced too many angles/dihedrals/impropers per atom* - See the read\_data command for info on using the "extra/angle/per/atom", + See the read_data command for info on using the "extra/angle/per/atom", (or dihedral, improper) keywords to allow for additional angles, dihedrals, and impropers to be formed. *Fix bond/create needs ghost atoms from further away* This is because the fix needs to walk bonds to a certain distance to - acquire needed info, The comm\_modify cutoff command can be used to + acquire needed info, The comm_modify cutoff command can be used to extend the communication range. *Fix bond/swap cannot use dihedral or improper styles* @@ -3513,7 +3513,7 @@ Doc page with :doc:`WARNING messages ` *Fix bond/swap requires pair and bond styles* Self-explanatory. -*Fix bond/swap requires special\_bonds = 0,1,1* +*Fix bond/swap requires special_bonds = 0,1,1* Self-explanatory. *Fix box/relax generated negative box length* @@ -3521,8 +3521,8 @@ Doc page with :doc:`WARNING messages ` it incrementally, to build to the high pressure. *Fix command before simulation box is defined* - The fix command cannot be used before a read\_data, read\_restart, or - create\_box command. + The fix command cannot be used before a read_data, read_restart, or + create_box command. *Fix deform cannot use yz variable with xy* The yz setting cannot be a variable if xy deformation is also @@ -3553,8 +3553,8 @@ Doc page with :doc:`WARNING messages ` *Fix deposit molecule must have coordinates* The defined molecule does not specify coordinates. -*Fix deposit molecule template ID must be same as atom\_style template ID* - When using atom\_style template, you cannot deposit molecules that are +*Fix deposit molecule template ID must be same as atom_style template ID* + When using atom_style template, you cannot deposit molecules that are not in that template. *Fix deposit region cannot be dynamic* @@ -3625,7 +3625,7 @@ Doc page with :doc:`WARNING messages ` molecule. The user has specified atomic (non-molecular) gas exchanges, but an atom belonging to a molecule could be deleted. -*Fix gcmc does not (yet) work with atom\_style template* +*Fix gcmc does not (yet) work with atom_style template* Self-explanatory. *Fix gcmc molecule command requires that atoms have molecule attributes* @@ -3642,8 +3642,8 @@ Doc page with :doc:`WARNING messages ` *Fix gcmc molecule must have coordinates* The defined molecule does not specify coordinates. -*Fix gcmc molecule template ID must be same as atom\_style template ID* - When using atom\_style template, you cannot insert molecules that are +*Fix gcmc molecule template ID must be same as atom_style template ID* + When using atom_style template, you cannot insert molecules that are not in that template. *Fix gcmc put atom outside box* @@ -3866,7 +3866,7 @@ Doc page with :doc:`WARNING messages ` The defined molecule does not specify coordinates. *Fix pour molecule template ID must be same as atom style template ID* - When using atom\_style template, you cannot pour molecules that are + When using atom_style template, you cannot pour molecules that are not in that template. *Fix pour polydisperse fractions do not sum to 1.0* @@ -3900,10 +3900,10 @@ Doc page with :doc:`WARNING messages ` *Fix property/atom cannot specify q twice* Self-explanatory. -*Fix property/atom mol when atom\_style already has molecule attribute* +*Fix property/atom mol when atom_style already has molecule attribute* Self-explanatory. -*Fix property/atom q when atom\_style already has charge attribute* +*Fix property/atom q when atom_style already has charge attribute* Self-explanatory. *Fix property/atom vector name already exists* @@ -3935,7 +3935,7 @@ Doc page with :doc:`WARNING messages ` *Fix qeq/point has insufficient QEq matrix size* Occurs when number of neighbor atoms for an atom increased too much - during a run. Increase SAFE\_ZONE and MIN\_CAP in fix\_qeq.h and + during a run. Increase SAFE_ZONE and MIN_CAP in fix_qeq.h and re-compile. *Fix qeq/point requires atom attribute q* @@ -3946,7 +3946,7 @@ Doc page with :doc:`WARNING messages ` *Fix qeq/shielded has insufficient QEq matrix size* Occurs when number of neighbor atoms for an atom increased too much - during a run. Increase SAFE\_ZONE and MIN\_CAP in fix\_qeq.h and + during a run. Increase SAFE_ZONE and MIN_CAP in fix_qeq.h and re-compile. *Fix qeq/shielded requires atom attribute q* @@ -3960,20 +3960,20 @@ Doc page with :doc:`WARNING messages ` *Fix qeq/slater has insufficient QEq matrix size* Occurs when number of neighbor atoms for an atom increased too much - during a run. Increase SAFE\_ZONE and MIN\_CAP in fix\_qeq.h and + during a run. Increase SAFE_ZONE and MIN_CAP in fix_qeq.h and re-compile. *Fix qeq/slater requires atom attribute q* Self-explanatory. -*Fix reax/bonds numbonds > nsbmax\_most* +*Fix reax/bonds numbonds > nsbmax_most* The limit of the number of bonds expected by the ReaxFF force field was exceeded. *Fix recenter group has no atoms* Self-explanatory. -*Fix restrain requires an atom map, see atom\_modify* +*Fix restrain requires an atom map, see atom_modify* Self-explanatory. *Fix rigid atom has non-zero image flag in a non-periodic dimension* @@ -3997,22 +3997,22 @@ Doc page with :doc:`WARNING messages ` *Fix rigid npt/nph period must be > 0.0* Self-explanatory. -*Fix rigid npt/small t\_chain should not be less than 1* +*Fix rigid npt/small t_chain should not be less than 1* Self-explanatory. -*Fix rigid npt/small t\_order must be 3 or 5* +*Fix rigid npt/small t_order must be 3 or 5* Self-explanatory. *Fix rigid nvt/npt/nph damping parameters must be > 0.0* Self-explanatory. -*Fix rigid nvt/small t\_chain should not be less than 1* +*Fix rigid nvt/small t_chain should not be less than 1* Self-explanatory. -*Fix rigid nvt/small t\_iter should not be less than 1* +*Fix rigid nvt/small t_iter should not be less than 1* Self-explanatory. -*Fix rigid nvt/small t\_order must be 3 or 5* +*Fix rigid nvt/small t_order must be 3 or 5* Self-explanatory. *Fix rigid xy torque cannot be on for 2d simulation* @@ -4060,7 +4060,7 @@ Doc page with :doc:`WARNING messages ` *Fix rigid/small nvt/npt/nph dilate group ID does not exist* Self-explanatory. -*Fix rigid/small requires an atom map, see atom\_modify* +*Fix rigid/small requires an atom map, see atom_modify* Self-explanatory. *Fix rigid/small requires atom attribute molecule* @@ -4080,7 +4080,7 @@ Doc page with :doc:`WARNING messages ` *Fix spring couple group ID does not exist* Self-explanatory. -*Fix srd can only currently be used with comm\_style brick* +*Fix srd can only currently be used with comm_style brick* This is a current restriction in LAMMPS. *Fix srd lamda must be >= 0.6 of SRD grid size* @@ -4094,7 +4094,7 @@ Doc page with :doc:`WARNING messages ` Self-explanatory. *Fix srd requires ghost atoms store velocity* - Use the comm\_modify vel yes command to enable this. + Use the comm_modify vel yes command to enable this. *Fix srd requires newton pair on* Self-explanatory. @@ -4169,25 +4169,25 @@ Doc page with :doc:`WARNING messages ` *Fix ttm electron temperatures must be > 0.0* Self-explanatory. -*Fix ttm electronic\_density must be > 0.0* +*Fix ttm electronic_density must be > 0.0* Self-explanatory. -*Fix ttm electronic\_specific\_heat must be > 0.0* +*Fix ttm electronic_specific_heat must be > 0.0* Self-explanatory. -*Fix ttm electronic\_thermal\_conductivity must be >= 0.0* +*Fix ttm electronic_thermal_conductivity must be >= 0.0* Self-explanatory. -*Fix ttm gamma\_p must be > 0.0* +*Fix ttm gamma_p must be > 0.0* Self-explanatory. -*Fix ttm gamma\_s must be >= 0.0* +*Fix ttm gamma_s must be >= 0.0* Self-explanatory. *Fix ttm number of nodes must be > 0* Self-explanatory. -*Fix ttm v\_0 must be >= 0.0* +*Fix ttm v_0 must be >= 0.0* Self-explanatory. *Fix used in compute chunk/atom not computed at compatible time* @@ -4261,10 +4261,10 @@ Doc page with :doc:`WARNING messages ` *Fix wall/region cutoff <= 0.0* Self-explanatory. -*Fix\_modify pressure ID does not compute pressure* +*Fix_modify pressure ID does not compute pressure* The compute ID assigned to the fix must compute pressure. -*Fix\_modify temperature ID does not compute temperature* +*Fix_modify temperature ID does not compute temperature* The compute ID assigned to the fix must compute temperature. *For triclinic deformation, specified target stress must be hydrostatic* @@ -4277,7 +4277,7 @@ Doc page with :doc:`WARNING messages ` *GPU library not compiled for this accelerator* Self-explanatory. -*GPU package does not (yet) work with atom\_style template* +*GPU package does not (yet) work with atom_style template* Self-explanatory. *GPU particle split must be set to 1 for this pair style.* @@ -4315,8 +4315,8 @@ Doc page with :doc:`WARNING messages ` This operation is not allowed. *Group command before simulation box is defined* - The group command cannot be used before a read\_data, read\_restart, or - create\_box command. + The group command cannot be used before a read_data, read_restart, or + create_box command. *Group dynamic cannot reference itself* Self-explanatory. @@ -4330,8 +4330,8 @@ Doc page with :doc:`WARNING messages ` *Group region ID does not exist* A region ID used in the group command does not exist. -*If read\_dump purges it cannot replace or trim* - These operations are not compatible. See the read\_dump doc +*If read_dump purges it cannot replace or trim* + These operations are not compatible. See the read_dump doc page for details. *Illegal ... command* @@ -4366,10 +4366,10 @@ Doc page with :doc:`WARNING messages ` One or more of the coefficients defined in the potential file is invalid. -*Illegal dump\_modify sfactor value (must be > 0.0)* +*Illegal dump_modify sfactor value (must be > 0.0)* Self-explanatory. -*Illegal dump\_modify tfactor value (must be > 0.0)* +*Illegal dump_modify tfactor value (must be > 0.0)* Self-explanatory. *Illegal fix gcmc gas mass <= 0* @@ -4423,8 +4423,8 @@ Doc page with :doc:`WARNING messages ` Format of imageint stored in restart file is not consistent with LAMMPS version you are running. See the settings in src/lmptype.h -*Improper atom missing in delete\_bonds* - The delete\_bonds command cannot find one or more atoms in a particular +*Improper atom missing in delete_bonds* + The delete_bonds command cannot find one or more atoms in a particular improper on a particular processor. The pairwise cutoff is too short or the atoms are too far apart to make a valid improper. @@ -4447,12 +4447,12 @@ Doc page with :doc:`WARNING messages ` *Improper coeff for hybrid has invalid style* Improper style hybrid uses another improper style as one of its - coefficients. The improper style used in the improper\_coeff command + coefficients. The improper style used in the improper_coeff command or read from a restart file is not recognized. *Improper coeffs are not set* No improper coefficients have been assigned in the data file or via - the improper\_coeff command. + the improper_coeff command. *Improper style hybrid cannot have hybrid as an argument* Self-explanatory. @@ -4463,18 +4463,18 @@ Doc page with :doc:`WARNING messages ` *Improper style hybrid cannot use same improper style twice* Self-explanatory. -*Improper\_coeff command before improper\_style is defined* - Coefficients cannot be set in the data file or via the improper\_coeff - command until an improper\_style has been assigned. +*Improper_coeff command before improper_style is defined* + Coefficients cannot be set in the data file or via the improper_coeff + command until an improper_style has been assigned. -*Improper\_coeff command before simulation box is defined* - The improper\_coeff command cannot be used before a read\_data, - read\_restart, or create\_box command. +*Improper_coeff command before simulation box is defined* + The improper_coeff command cannot be used before a read_data, + read_restart, or create_box command. -*Improper\_coeff command when no impropers allowed* +*Improper_coeff command when no impropers allowed* The chosen atom style does not allow for impropers to be defined. -*Improper\_style command when no impropers allowed* +*Improper_style command when no impropers allowed* The chosen atom style does not allow for impropers to be defined. *Impropers assigned incorrectly* @@ -4493,7 +4493,7 @@ Doc page with :doc:`WARNING messages ` The selected unit style is not compatible with the requested KIM Simulator Model. -*Incomplete use of variables in create\_atoms command* +*Incomplete use of variables in create_atoms command* The var and set options must be used together. *Inconsistent iparam/jparam values in fix bond/create command* @@ -4540,7 +4540,7 @@ Doc page with :doc:`WARNING messages ` *Incorrect args for pair coefficients* Self-explanatory. Check the input script or data file. -*Incorrect args in pair\_style command* +*Incorrect args in pair_style command* Self-explanatory. *Incorrect atom format in data file* @@ -4551,7 +4551,7 @@ Doc page with :doc:`WARNING messages ` The number of fields per line is not what expected. *Incorrect bonus data format in data file* - See the read\_data doc page for a description of how various kinds of + See the read_data doc page for a description of how various kinds of bonus data must be formatted for certain atom styles. *Incorrect boundaries with slab Ewald* @@ -4652,7 +4652,7 @@ Doc page with :doc:`WARNING messages ` *Indexed per-atom vector in variable formula without atom map* Accessing a value from an atom vector requires the ability to lookup an atom index, which is provided by an atom map. An atom map does not - exist (by default) for non-molecular problems. Using the atom\_modify + exist (by default) for non-molecular problems. Using the atom_modify map command will force an atom map to be created. *Initial temperatures not all set in fix ttm* @@ -4684,7 +4684,7 @@ Doc page with :doc:`WARNING messages ` There is insufficient memory on one of the devices specified for the gpu package -*Internal error in atom\_style body* +*Internal error in atom_style body* This error should not occur. Contact the developers. *Invalid -reorder N value* @@ -4751,7 +4751,7 @@ Doc page with :doc:`WARNING messages ` Self-explanatory. *Invalid args for non-hybrid pair coefficients* - "NULL" is only supported in pair\_coeff calls when using pair hybrid + "NULL" is only supported in pair_coeff calls when using pair hybrid *Invalid argument to factorial %d* N must be >= 0 and <= 167, otherwise the factorial result is too @@ -4822,13 +4822,13 @@ Doc page with :doc:`WARNING messages ` *Invalid atom type in Atoms section of data file* Atom types must range from 1 to specified # of types. -*Invalid atom type in create\_atoms command* - The create\_box command specified the range of valid atom types. +*Invalid atom type in create_atoms command* + The create_box command specified the range of valid atom types. An invalid type is being requested. -*Invalid atom type in create\_atoms mol command* +*Invalid atom type in create_atoms mol command* The atom types in the defined molecule are added to the value - specified in the create\_atoms command, as an offset. The final value + specified in the create_atoms command, as an offset. The final value for each atom must be between 1 to N, where N is the number of atom types. @@ -4843,7 +4843,7 @@ Doc page with :doc:`WARNING messages ` *Invalid atom type in fix deposit mol command* The atom types in the defined molecule are added to the value - specified in the create\_atoms command, as an offset. The final value + specified in the create_atoms command, as an offset. The final value for each atom must be between 1 to N, where N is the number of atom types. @@ -4855,7 +4855,7 @@ Doc page with :doc:`WARNING messages ` *Invalid atom type in fix pour mol command* The atom types in the defined molecule are added to the value - specified in the create\_atoms command, as an offset. The final value + specified in the create_atoms command, as an offset. The final value for each atom must be between 1 to N, where N is the number of atom types. @@ -4868,16 +4868,16 @@ Doc page with :doc:`WARNING messages ` *Invalid atom type index for fix shake* Atom types must range from 1 to Ntypes inclusive. -*Invalid atom types in pair\_write command* +*Invalid atom types in pair_write command* Atom types must range from 1 to Ntypes inclusive. *Invalid atom vector in variable formula* The atom vector is not recognized. -*Invalid atom\_style body command* +*Invalid atom_style body command* No body style argument was provided. -*Invalid atom\_style command* +*Invalid atom_style command* Self-explanatory. *Invalid attribute in dump custom command* @@ -4889,7 +4889,7 @@ Doc page with :doc:`WARNING messages ` *Invalid attribute in dump modify command* Self-explanatory. -*Invalid basis setting in create\_atoms command* +*Invalid basis setting in create_atoms command* The basis index must be between 1 to N where N is the number of basis atoms in the lattice. The type index must be between 1 to N where N is the number of atom types. @@ -4921,7 +4921,7 @@ Doc page with :doc:`WARNING messages ` *Invalid bond type in Bonds section of molecule file* Self-explanatory. -*Invalid bond type in create\_bonds command* +*Invalid bond type in create_bonds command* Self-explanatory. *Invalid bond type in fix bond/break command* @@ -4936,9 +4936,9 @@ Doc page with :doc:`WARNING messages ` *Invalid coeffs for this dihedral style* Cannot set class 2 coeffs in data file for this dihedral style. -*Invalid color in dump\_modify command* +*Invalid color in dump_modify command* The specified color name was not in the list of recognized colors. - See the dump\_modify doc page. + See the dump_modify doc page. *Invalid color map min/max values* The min/max values are not consistent with either each other or @@ -4951,17 +4951,17 @@ Doc page with :doc:`WARNING messages ` *Invalid compute ID in variable formula* The compute is not recognized. -*Invalid create\_atoms rotation vector for 2d model* +*Invalid create_atoms rotation vector for 2d model* The rotation vector can only have a z component. *Invalid custom OpenCL parameter string.* There are not enough or too many parameters in the custom string for package GPU. -*Invalid cutoff in comm\_modify command* +*Invalid cutoff in comm_modify command* Specified cutoff must be >= 0.0. -*Invalid cutoffs in pair\_write command* +*Invalid cutoffs in pair_write command* Inner cutoff must be larger than 0.0 and less than outer cutoff. *Invalid d1 or d2 value for pair colloid coeff* @@ -5027,7 +5027,7 @@ Doc page with :doc:`WARNING messages ` *Invalid data file section: Triangles* Atom style does not allow triangles. -*Invalid delta\_conf in tad command* +*Invalid delta_conf in tad command* The value must be between 0 and 1 inclusive. *Invalid density in Atoms section of data file* @@ -5052,7 +5052,7 @@ Doc page with :doc:`WARNING messages ` *Invalid dipole length in set command* Self-explanatory. -*Invalid displace\_atoms rotate axis for 2d* +*Invalid displace_atoms rotate axis for 2d* Axis must be in z direction. *Invalid dump dcd filename* @@ -5064,7 +5064,7 @@ Doc page with :doc:`WARNING messages ` *Invalid dump image element name* The specified element name was not in the standard list of elements. - See the dump\_modify doc page. + See the dump_modify doc page. *Invalid dump image filename* The file produced by dump image cannot be binary and must @@ -5091,7 +5091,7 @@ Doc page with :doc:`WARNING messages ` Filenames used with the dump xyz style cannot be binary or cause files to be written by each processor. -*Invalid dump\_modify threshold operator* +*Invalid dump_modify threshold operator* Operator keyword used for threshold specification in not recognized. *Invalid entry in -reorder file* @@ -5161,13 +5161,13 @@ Doc page with :doc:`WARNING messages ` *Invalid frequency in temper command* Nevery must be > 0. -*Invalid group ID in neigh\_modify command* - A group ID used in the neigh\_modify command does not exist. +*Invalid group ID in neigh_modify command* + A group ID used in the neigh_modify command does not exist. *Invalid group function in variable formula* Group function is not recognized. -*Invalid group in comm\_modify command* +*Invalid group in comm_modify command* Self-explanatory. *Invalid image up vector* @@ -5192,13 +5192,13 @@ Doc page with :doc:`WARNING messages ` *Invalid index in compute body/local command* Self-explanatory. -*Invalid is\_active() function in variable formula* +*Invalid is_active() function in variable formula* Self-explanatory. -*Invalid is\_available() function in variable formula* +*Invalid is_available() function in variable formula* Self-explanatory. -*Invalid is\_defined() function in variable formula* +*Invalid is_defined() function in variable formula* Self-explanatory. *Invalid keyword in angle table parameters* @@ -5266,7 +5266,7 @@ Doc page with :doc:`WARNING messages ` kspace, etc. *Invalid pair table cutoff* - Cutoffs in pair\_coeff command are not valid with read-in pair table. + Cutoffs in pair_coeff command are not valid with read-in pair table. *Invalid pair table length* Length of read-in pair table is invalid @@ -5354,16 +5354,16 @@ Doc page with :doc:`WARNING messages ` *Invalid special function in variable formula* Self-explanatory. -*Invalid style in pair\_write command* +*Invalid style in pair_write command* Self-explanatory. Check the input script. *Invalid syntax in variable formula* Self-explanatory. -*Invalid t\_event in prd command* +*Invalid t_event in prd command* Self-explanatory. -*Invalid t\_event in tad command* +*Invalid t_event in tad command* The value must be greater than 0. *Invalid template atom in Atoms section of data file* @@ -5377,8 +5377,8 @@ Doc page with :doc:`WARNING messages ` *Invalid thermo keyword in variable formula* The keyword is not recognized. -*Invalid threads\_per\_atom specified.* - For 3-body potentials on the GPU, the threads\_per\_atom setting cannot be +*Invalid threads_per_atom specified.* + For 3-body potentials on the GPU, the threads_per_atom setting cannot be greater than 4 for NVIDIA GPUs. *Invalid timestep reset for fix ave/atom* @@ -5473,10 +5473,10 @@ Doc page with :doc:`WARNING messages ` Model. Please contact the OpenKIM database maintainers to verify and potentially correct this. -*KOKKOS package does not yet support comm\_style tiled* +*KOKKOS package does not yet support comm_style tiled* Self-explanatory. -*KOKKOS package requires a kokkos enabled atom\_style* +*KOKKOS package requires a kokkos enabled atom_style* Self-explanatory. *KSpace accuracy must be > 0* @@ -5484,7 +5484,7 @@ Doc page with :doc:`WARNING messages ` *KSpace accuracy too large to estimate G vector* Reduce the accuracy request or specify gewald explicitly - via the kspace\_modify command. + via the kspace_modify command. *KSpace accuracy too low* Requested accuracy must be less than 1.0. @@ -5497,7 +5497,7 @@ Doc page with :doc:`WARNING messages ` simulation boxes. *KSpace style has not yet been set* - Cannot use kspace\_modify command until a kspace style is set. + Cannot use kspace_modify command until a kspace style is set. *KSpace style is incompatible with Pair style* Setting a kspace style requires that a pair style with matching @@ -5509,11 +5509,11 @@ Doc page with :doc:`WARNING messages ` *Kokkos has been compiled for CUDA but no GPUs are requested* One or more GPUs must be used when Kokkos is compiled for CUDA. -*Kspace\_modify mesh parameter must be all zero or all positive* +*Kspace_modify mesh parameter must be all zero or all positive* Valid kspace mesh parameters are >0. The code will try to auto-detect suitable values when all three mesh sizes are set to zero (the default). -*Kspace\_modify mesh/disp parameter must be all zero or all positive* +*Kspace_modify mesh/disp parameter must be all zero or all positive* Valid kspace mesh/disp parameters are >0. The code will try to auto-detect suitable values when all three mesh sizes are set to zero **and** the required accuracy via *force/disp/real* as well as @@ -5531,17 +5531,17 @@ Doc page with :doc:`WARNING messages ` *Kspace style requires atom attribute q* The atom style defined does not have these attributes. -*Kspace\_modify eigtol must be smaller than one* +*Kspace_modify eigtol must be smaller than one* Self-explanatory. *LAMMPS is not built with Python embedded* This is done by including the PYTHON package before LAMMPS is built. This is required to use python-style variables. -*LAMMPS unit\_style lj not supported by KIM models* +*LAMMPS unit_style lj not supported by KIM models* Self-explanatory. Check the input script or data file. -*LJ6 off not supported in pair\_style buck/long/coul/long* +*LJ6 off not supported in pair_style buck/long/coul/long* Self-explanatory. *Label wasn't found in input script* @@ -5578,7 +5578,7 @@ Doc page with :doc:`WARNING messages ` *Lost atoms: original %ld current %ld* Lost atoms are checked for each time thermo output is done. See the - thermo\_modify lost command for options. Lost atoms usually indicate + thermo_modify lost command for options. Lost atoms usually indicate bad dynamics, e.g. atoms have been blown far out of the simulation box, or moved further than one processor's sub-domain away before reneighboring. @@ -5586,13 +5586,13 @@ Doc page with :doc:`WARNING messages ` *MEAM library error %d* A call to the MEAM Fortran library returned an error. -*MPI\_LMP\_BIGINT and bigint in lmptype.h are not compatible* +*MPI_LMP_BIGINT and bigint in lmptype.h are not compatible* The size of the MPI datatype does not match the size of a bigint. -*MPI\_LMP\_TAGINT and tagint in lmptype.h are not compatible* +*MPI_LMP_TAGINT and tagint in lmptype.h are not compatible* The size of the MPI datatype does not match the size of a tagint. -*MSM can only currently be used with comm\_style brick* +*MSM can only currently be used with comm_style brick* This is a current restriction in LAMMPS. *MSM grid is too large* @@ -5605,23 +5605,23 @@ Doc page with :doc:`WARNING messages ` the MSM order can only be 4, 6, 8, or 10. *Mass command before simulation box is defined* - The mass command cannot be used before a read\_data, read\_restart, or - create\_box command. + The mass command cannot be used before a read_data, read_restart, or + create_box command. *Matrix factorization to split dispersion coefficients failed* This should not normally happen. Contact the developers. -*Min\_style command before simulation box is defined* - The min\_style command cannot be used before a read\_data, read\_restart, - or create\_box command. +*Min_style command before simulation box is defined* + The min_style command cannot be used before a read_data, read_restart, + or create_box command. -*Minimization could not find thermo\_pe compute* +*Minimization could not find thermo_pe compute* This compute is created by the thermo command. It must have been explicitly deleted by a uncompute command. *Minimize command before simulation box is defined* - The minimize command cannot be used before a read\_data, read\_restart, - or create\_box command. + The minimize command cannot be used before a read_data, read_restart, + or create_box command. *Mismatched brackets in variable* Self-explanatory. @@ -5703,10 +5703,10 @@ Doc page with :doc:`WARNING messages ` *Molecule sizescale must be 1.0 for body particle* Self-explanatory. -*Molecule template ID for atom\_style template does not exist* +*Molecule template ID for atom_style template does not exist* Self-explanatory. -*Molecule template ID for create\_atoms does not exist* +*Molecule template ID for create_atoms does not exist* Self-explanatory. *Molecule template ID for fix deposit does not exist* @@ -5729,12 +5729,12 @@ Doc page with :doc:`WARNING messages ` *Molecule topology/atom exceeds system topology/atom* The number of bonds, angles, etc per-atom in the molecule exceeds the - system setting. See the create\_box command for how to specify these + system setting. See the create_box command for how to specify these values. *Molecule topology type exceeds system topology type* The number of bond, angle, etc types in the molecule exceeds the - system setting. See the create\_box command for how to specify these + system setting. See the create_box command for how to specify these values. *More than one fix deform* @@ -5750,60 +5750,60 @@ Doc page with :doc:`WARNING messages ` *Mu not allowed when not using semi-grand in fix atom/swap command* Self-explanatory. -*Must define angle\_style before Angle Coeffs* - Must use an angle\_style command before reading a data file that +*Must define angle_style before Angle Coeffs* + Must use an angle_style command before reading a data file that defines Angle Coeffs. -*Must define angle\_style before BondAngle Coeffs* - Must use an angle\_style command before reading a data file that +*Must define angle_style before BondAngle Coeffs* + Must use an angle_style command before reading a data file that defines Angle Coeffs. -*Must define angle\_style before BondBond Coeffs* - Must use an angle\_style command before reading a data file that +*Must define angle_style before BondBond Coeffs* + Must use an angle_style command before reading a data file that defines Angle Coeffs. -*Must define bond\_style before Bond Coeffs* - Must use a bond\_style command before reading a data file that +*Must define bond_style before Bond Coeffs* + Must use a bond_style command before reading a data file that defines Bond Coeffs. -*Must define dihedral\_style before AngleAngleTorsion Coeffs* - Must use a dihedral\_style command before reading a data file that +*Must define dihedral_style before AngleAngleTorsion Coeffs* + Must use a dihedral_style command before reading a data file that defines AngleAngleTorsion Coeffs. -*Must define dihedral\_style before AngleTorsion Coeffs* - Must use a dihedral\_style command before reading a data file that +*Must define dihedral_style before AngleTorsion Coeffs* + Must use a dihedral_style command before reading a data file that defines AngleTorsion Coeffs. -*Must define dihedral\_style before BondBond13 Coeffs* - Must use a dihedral\_style command before reading a data file that +*Must define dihedral_style before BondBond13 Coeffs* + Must use a dihedral_style command before reading a data file that defines BondBond13 Coeffs. -*Must define dihedral\_style before Dihedral Coeffs* - Must use a dihedral\_style command before reading a data file that +*Must define dihedral_style before Dihedral Coeffs* + Must use a dihedral_style command before reading a data file that defines Dihedral Coeffs. -*Must define dihedral\_style before EndBondTorsion Coeffs* - Must use a dihedral\_style command before reading a data file that +*Must define dihedral_style before EndBondTorsion Coeffs* + Must use a dihedral_style command before reading a data file that defines EndBondTorsion Coeffs. -*Must define dihedral\_style before MiddleBondTorsion Coeffs* - Must use a dihedral\_style command before reading a data file that +*Must define dihedral_style before MiddleBondTorsion Coeffs* + Must use a dihedral_style command before reading a data file that defines MiddleBondTorsion Coeffs. -*Must define improper\_style before AngleAngle Coeffs* - Must use an improper\_style command before reading a data file that +*Must define improper_style before AngleAngle Coeffs* + Must use an improper_style command before reading a data file that defines AngleAngle Coeffs. -*Must define improper\_style before Improper Coeffs* - Must use an improper\_style command before reading a data file that +*Must define improper_style before Improper Coeffs* + Must use an improper_style command before reading a data file that defines Improper Coeffs. -*Must define pair\_style before Pair Coeffs* - Must use a pair\_style command before reading a data file that defines +*Must define pair_style before Pair Coeffs* + Must use a pair_style command before reading a data file that defines Pair Coeffs. -*Must define pair\_style before PairIJ Coeffs* - Must use a pair\_style command before reading a data file that defines +*Must define pair_style before PairIJ Coeffs* + Must use a pair_style command before reading a data file that defines PairIJ Coeffs. *Must have more than one processor partition to temper* @@ -5840,9 +5840,9 @@ Doc page with :doc:`WARNING messages ` The Atoms section of a data file must come before a Velocities section. -*Must re-specify non-restarted pair style (xxx) after read\_restart* +*Must re-specify non-restarted pair style (xxx) after read_restart* For pair styles, that do not store their settings in a restart file, - it must be defined with a new 'pair\_style' command after read\_restart. + it must be defined with a new 'pair_style' command after read_restart. *Must set both respa inner and outer* Cannot use just the inner or outer option with respa without using the @@ -5850,7 +5850,7 @@ Doc page with :doc:`WARNING messages ` *Must set number of threads via package omp command* Because you are using the USER-OMP package, set the number of threads - via its settings, not by the pair\_style snap nthreads setting. + via its settings, not by the pair_style snap nthreads setting. *Must shrink-wrap piston boundary* The boundary style of the face where the piston is applied must be of @@ -5865,30 +5865,30 @@ Doc page with :doc:`WARNING messages ` *Must specify at least 2 types in fix atom/swap command* Self-explanatory. -*Must use 'kim\_style init' command before simulation box is defined* +*Must use 'kim_style init' command before simulation box is defined* Self-explanatory. -*Must use 'kim\_style define' command after simulation box is defined* +*Must use 'kim_style define' command after simulation box is defined* Self-explanatory. -*Must use 'kim\_style init' command before 'kim\_style define'* +*Must use 'kim_style init' command before 'kim_style define'* Self-explanatory. -*Must use 'kspace\_modify pressure/scalar no' for rRESPA with kspace\_style MSM* +*Must use 'kspace_modify pressure/scalar no' for rRESPA with kspace_style MSM* The kspace scalar pressure option cannot (yet) be used with rRESPA. -*Must use 'kspace\_modify pressure/scalar no' for tensor components with kspace\_style msm* - Otherwise MSM will compute only a scalar pressure. See the kspace\_modify +*Must use 'kspace_modify pressure/scalar no' for tensor components with kspace_style msm* + Otherwise MSM will compute only a scalar pressure. See the kspace_modify command for details on this setting. -*Must use 'kspace\_modify pressure/scalar no' to obtain per-atom virial with kspace\_style MSM* +*Must use 'kspace_modify pressure/scalar no' to obtain per-atom virial with kspace_style MSM* The kspace scalar pressure option cannot be used to obtain per-atom virial. -*Must use 'kspace\_modify pressure/scalar no' with GPU MSM Pair styles* +*Must use 'kspace_modify pressure/scalar no' with GPU MSM Pair styles* The kspace scalar pressure option is not (yet) compatible with GPU MSM Pair styles. -*Must use 'kspace\_modify pressure/scalar no' with kspace\_style msm/cg* - The kspace scalar pressure option is not compatible with kspace\_style msm/cg. +*Must use 'kspace_modify pressure/scalar no' with kspace_style msm/cg* + The kspace scalar pressure option is not compatible with kspace_style msm/cg. *Must use -in switch with multiple partitions* A multi-partition simulation cannot read the input script from stdin. @@ -5918,12 +5918,12 @@ Doc page with :doc:`WARNING messages ` command. *Must use atom map style array with Kokkos* - See the atom\_modify map command. + See the atom_modify map command. *Must use atom style with molecule IDs with fix bond/swap* Self-explanatory. -*Must use pair\_style comb or comb3 with fix qeq/comb* +*Must use pair_style comb or comb3 with fix qeq/comb* Self-explanatory. *Must use variable energy with fix addforce* @@ -5950,29 +5950,29 @@ Doc page with :doc:`WARNING messages ` Self-explanatory. *Needed bonus data not in data file* - Some atom styles require bonus data. See the read\_data doc page for + Some atom styles require bonus data. See the read_data doc page for details. *Needed molecular topology not in data file* The header of the data file indicated bonds, angles, etc would be included, but they are not present. -*Neigh\_modify exclude molecule requires atom attribute molecule* +*Neigh_modify exclude molecule requires atom attribute molecule* Self-explanatory. -*Neigh\_modify include group != atom\_modify first group* +*Neigh_modify include group != atom_modify first group* Self-explanatory. *Neighbor delay must be 0 or multiple of every setting* - The delay and every parameters set via the neigh\_modify command are + The delay and every parameters set via the neigh_modify command are inconsistent. If the delay setting is non-zero, then it must be a multiple of the every setting. *Neighbor include group not allowed with ghost neighbors* This is a current restriction within LAMMPS. -*Neighbor list overflow, boost neigh\_modify one* - There are too many neighbors of a single atom. Use the neigh\_modify +*Neighbor list overflow, boost neigh_modify one* + There are too many neighbors of a single atom. Use the neigh_modify command to increase the max number of neighbors allowed for one atom. You may also want to boost the page size. @@ -5991,23 +5991,23 @@ Doc page with :doc:`WARNING messages ` *New atom IDs exceed maximum allowed ID* See the setting for tagint in the src/lmptype.h file. -*New bond exceeded bonds per atom in create\_bonds* -See the read\_data command for info on using the "extra/bond/per/atom" +*New bond exceeded bonds per atom in create_bonds* +See the read_data command for info on using the "extra/bond/per/atom" keyword to allow for additional bonds to be formed *New bond exceeded bonds per atom in fix bond/create* - See the read\_data command for info on using the "extra/bond/per/atom" + See the read_data command for info on using the "extra/bond/per/atom" keyword to allow for additional bonds to be formed *New bond exceeded special list size in fix bond/create* - See the "read\_data extra/special/per/atom" command - (or the "create\_box extra/special/per/atom" command) + See the "read_data extra/special/per/atom" command + (or the "create_box extra/special/per/atom" command) for info on how to leave space in the special bonds list to allow for additional bonds to be formed. *Newton bond change after simulation box is defined* The newton command cannot be used to change the newton bond value - after a read\_data, read\_restart, or create\_box command. + after a read_data, read_restart, or create_box command. *Next command must list all universe and uloop variables* This is to insure they stay in sync. @@ -6090,7 +6090,7 @@ keyword to allow for additional bonds to be formed The data file cannot specify the number of bonds, angles, etc, because this info if inferred from the molecule templates. -*No overlap of box and region for create\_atoms* +*No overlap of box and region for create_atoms* Self-explanatory. *No pair coul/streitz for fix qeq/slater* @@ -6130,10 +6130,10 @@ keyword to allow for additional bonds to be formed *Non-numeric box dimensions - simulation unstable* The box size has apparently blown up. -*Non-zero atom IDs with atom\_modify id = no* +*Non-zero atom IDs with atom_modify id = no* Self-explanatory. -*Non-zero read\_data shift z value for 2d simulation* +*Non-zero read_data shift z value for 2d simulation* Self-explanatory. *Nprocs not a multiple of N for -reorder* @@ -6239,7 +6239,7 @@ keyword to allow for additional bonds to be formed NPT/NPH fix must be defined in input script after all poems fixes, else the fix contribution to the pressure virial is incorrect. -*PPPM can only currently be used with comm\_style brick* +*PPPM can only currently be used with comm_style brick* This is a current restriction in LAMMPS. *PPPM grid is too large* @@ -6248,11 +6248,11 @@ keyword to allow for additional bonds to be formed requested accuracy. *PPPM grid stencil extends beyond nearest neighbor processor* - This is not allowed if the kspace\_modify overlap setting is no. + This is not allowed if the kspace_modify overlap setting is no. *PPPM order < minimum allowed order* The default minimum order is 2. This can be reset by the - kspace\_modify minorder command. + kspace_modify minorder command. *PPPM order cannot be < 2 or > than %d* This is a limitation of the PPPM implementation in LAMMPS. @@ -6267,28 +6267,28 @@ keyword to allow for additional bonds to be formed OFFSET is currently set to 4096. You likely need to decrease the requested accuracy. -*PPPMDisp can only currently be used with comm\_style brick* +*PPPMDisp can only currently be used with comm_style brick* This is a current restriction in LAMMPS. *PPPMDisp coulomb order cannot be greater than %d* This is a limitation of the PPPM implementation in LAMMPS. *PPPMDisp used but no parameters set, for further information please see the pppm/disp documentation* - An efficient and accurate usage of the pppm/disp requires settings via the kspace\_modify command. Please see the pppm/disp documentation for further instructions. + An efficient and accurate usage of the pppm/disp requires settings via the kspace_modify command. Please see the pppm/disp documentation for further instructions. *PRD command before simulation box is defined* - The prd command cannot be used before a read\_data, - read\_restart, or create\_box command. + The prd command cannot be used before a read_data, + read_restart, or create_box command. -*PRD nsteps must be multiple of t\_event* +*PRD nsteps must be multiple of t_event* Self-explanatory. -*PRD t\_corr must be multiple of t\_event* +*PRD t_corr must be multiple of t_event* Self-explanatory. *Package command after simulation box is defined* - The package command cannot be used after a read\_data, read\_restart, or - create\_box command. + The package command cannot be used after a read_data, read_restart, or + create_box command. *Package gpu command without GPU package installed* The GPU package must be installed via "make yes-gpu" before LAMMPS is @@ -6331,7 +6331,7 @@ keyword to allow for additional bonds to be formed Self-explanatory. *Pair coeff for hybrid has invalid style* - Style in pair coeff must have been listed in pair\_style command. + Style in pair coeff must have been listed in pair_style command. *Pair coul/wolf requires atom attribute q* The atom style defined does not have this attribute. @@ -6359,10 +6359,10 @@ keyword to allow for additional bonds to be formed Two atoms are further apart than the pairwise table allows. *Pair dpd requires ghost atoms store velocity* - Use the comm\_modify vel yes command to enable this. + Use the comm_modify vel yes command to enable this. *Pair gayberne epsilon a,b,c coeffs are not all set* - Each atom type involved in pair\_style gayberne must + Each atom type involved in pair_style gayberne must have these 3 coefficients set at least once. *Pair gayberne requires atom style ellipsoid* @@ -6381,7 +6381,7 @@ keyword to allow for additional bonds to be formed The atom style defined does not have these attributes. *Pair granular requires ghost atoms store velocity* - Use the comm\_modify vel yes command to enable this. + Use the comm_modify vel yes command to enable this. *Pair granular with shear history requires newton pair off* This is a current restriction of the implementation of pair @@ -6395,7 +6395,7 @@ keyword to allow for additional bonds to be formed that doesn't support it. *Pair hybrid sub-style is not used* - No pair\_coeff command used a sub-style specified in the pair\_style + No pair_coeff command used a sub-style specified in the pair_style command. *Pair inner cutoff < Respa interior cutoff* @@ -6415,7 +6415,7 @@ keyword to allow for additional bonds to be formed Self-explanatory. *Pair lubricate requires ghost atoms store velocity* - Use the comm\_modify vel yes command to enable this. + Use the comm_modify vel yes command to enable this. *Pair lubricate requires monodisperse particles* All particles must be the same finite size. @@ -6427,7 +6427,7 @@ keyword to allow for additional bonds to be formed One of the particles has radius 0.0. *Pair lubricate/poly requires ghost atoms store velocity* - Use the comm\_modify vel yes command to enable this. + Use the comm_modify vel yes command to enable this. *Pair lubricate/poly requires newton pair off* Self-explanatory. @@ -6436,13 +6436,13 @@ keyword to allow for additional bonds to be formed Self-explanatory. *Pair lubricateU requires ghost atoms store velocity* - Use the comm\_modify vel yes command to enable this. + Use the comm_modify vel yes command to enable this. *Pair lubricateU requires monodisperse particles* All particles must be the same finite size. *Pair lubricateU/poly requires ghost atoms store velocity* - Use the comm\_modify vel yes command to enable this. + Use the comm_modify vel yes command to enable this. *Pair lubricateU/poly requires newton pair off* Self-explanatory. @@ -6453,9 +6453,9 @@ keyword to allow for additional bonds to be formed *Pair peri requires a lattice be defined* Use the lattice command for this purpose. -*Pair peri requires an atom map, see atom\_modify* +*Pair peri requires an atom map, see atom_modify* Even for atomic systems, an atom map is required to find Peridynamic - bonds. Use the atom\_modify command to define one. + bonds. Use the atom_modify command to define one. *Pair resquared epsilon a,b,c coeffs are not all set* Self-explanatory. @@ -6595,12 +6595,12 @@ keyword to allow for additional bonds to be formed The pair style does not support the pN value requested by the compute pair/local command. -*Pair style does not support bond\_style quartic* +*Pair style does not support bond_style quartic* The pair style does not have a single() function, so it can - not be invoked by bond\_style quartic. + not be invoked by bond_style quartic. *Pair style does not support compute group/group* - The pair\_style does not have a single() function, so it cannot be + The pair_style does not have a single() function, so it cannot be invoked by the compute group/group command. *Pair style does not support compute pair/local* @@ -6615,7 +6615,7 @@ keyword to allow for additional bonds to be formed The pair style does not have a single() function, so it can not be invoked by fix bond/swap. -*Pair style does not support pair\_write* +*Pair style does not support pair_write* The pair style does not have a single() function, so it can not be invoked by pair write. @@ -6627,7 +6627,7 @@ keyword to allow for additional bonds to be formed Atoms in the simulation do not have IDs, so history effects cannot be tracked by the granular pair potential. -*Pair style hbond/dreiding requires an atom map, see atom\_modify* +*Pair style hbond/dreiding requires an atom map, see atom_modify* Self-explanatory. *Pair style hbond/dreiding requires atom IDs* @@ -6713,7 +6713,7 @@ keyword to allow for additional bonds to be formed molecule adds forces to atoms owned by other processors. *Pair style lj/gromacs/coul/gromacs requires atom attribute q* - An atom\_style with this attribute is needed. + An atom_style with this attribute is needed. *Pair style lj/long/dipole/long does not currently support respa* This feature is not yet supported. @@ -6766,7 +6766,7 @@ keyword to allow for additional bonds to be formed *Pair style requires a KSpace style* No kspace style is defined. -*Pair style requires use of kspace\_style ewald/disp* +*Pair style requires use of kspace_style ewald/disp* Self-explanatory. *Pair style sw/gpu requires atom IDs* @@ -6836,21 +6836,21 @@ keyword to allow for additional bonds to be formed *PairKIM only works with 3D problems* This is a current limitation. -*Pair\_coeff command before pair\_style is defined* +*Pair_coeff command before pair_style is defined* Self-explanatory. -*Pair\_coeff command before simulation box is defined* - The pair\_coeff command cannot be used before a read\_data, - read\_restart, or create\_box command. +*Pair_coeff command before simulation box is defined* + The pair_coeff command cannot be used before a read_data, + read_restart, or create_box command. -*Pair\_modify command before pair\_style is defined* +*Pair_modify command before pair_style is defined* Self-explanatory. -*Pair\_modify special setting for pair hybrid incompatible with global special\_bonds setting* +*Pair_modify special setting for pair hybrid incompatible with global special_bonds setting* Cannot override a setting of 0.0 or 1.0 or change a setting between 0.0 and 1.0. -*Pair\_write command before pair\_style is defined* +*Pair_write command before pair_style is defined* Self-explanatory. *Particle on or inside fix wall surface* @@ -6971,8 +6971,8 @@ keyword to allow for additional bonds to be formed of processors LAMMPS is running on. *Processors command after simulation box is defined* - The processors command cannot be used after a read\_data, read\_restart, - or create\_box command. + The processors command cannot be used after a read_data, read_restart, + or create_box command. *Processors custom grid file is inconsistent* The vales in the custom file are not consistent with the number of @@ -7045,35 +7045,35 @@ keyword to allow for additional bonds to be formed This is because a % signifies one file per processor and MPI-IO creates one large file for all processors. -*Read\_data shrink wrap did not assign all atoms correctly* +*Read_data shrink wrap did not assign all atoms correctly* This is typically because the box-size specified in the data file is large compared to the actual extent of atoms in a shrink-wrapped dimension. When LAMMPS shrink-wraps the box atoms will be lost if the processor they are re-assigned to is too far away. Choose a box size closer to the actual extent of the atoms. -*Read\_dump command before simulation box is defined* - The read\_dump command cannot be used before a read\_data, read\_restart, - or create\_box command. +*Read_dump command before simulation box is defined* + The read_dump command cannot be used before a read_data, read_restart, + or create_box command. -*Read\_dump field not found in dump file* +*Read_dump field not found in dump file* Self-explanatory. -*Read\_dump triclinic status does not match simulation* +*Read_dump triclinic status does not match simulation* Both the dump snapshot and the current LAMMPS simulation must be using either an orthogonal or triclinic box. -*Read\_dump xyz fields do not have consistent scaling/wrapping* +*Read_dump xyz fields do not have consistent scaling/wrapping* Self-explanatory. *Reading from MPI-IO filename when MPIIO package is not installed* Self-explanatory. -*Reax\_defs.h setting for NATDEF is too small* +*Reax_defs.h setting for NATDEF is too small* Edit the setting in the ReaxFF library and re-compile the library and re-build LAMMPS. -*Reax\_defs.h setting for NNEIGHMAXDEF is too small* +*Reax_defs.h setting for NNEIGHMAXDEF is too small* Edit the setting in the ReaxFF library and re-compile the library and re-build LAMMPS. @@ -7154,8 +7154,8 @@ keyword to allow for additional bonds to be formed when you do not intend to. *Replicate command before simulation box is defined* - The replicate command cannot be used before a read\_data, read\_restart, - or create\_box command. + The replicate command cannot be used before a read_data, read_restart, + or create_box command. *Replicate did not assign all atoms correctly* Atoms replicated by the replicate command were not assigned correctly @@ -7173,8 +7173,8 @@ keyword to allow for additional bonds to be formed by Kokkos. *Rerun command before simulation box is defined* - The rerun command cannot be used before a read\_data, read\_restart, or - create\_box command. + The rerun command cannot be used before a read_data, read_restart, or + create_box command. *Rerun dump file does not contain requested snapshot* Self-explanatory. @@ -7273,8 +7273,8 @@ keyword to allow for additional bonds to be formed Rmask is per-atom operation. *Run command before simulation box is defined* - The run command cannot be used before a read\_data, read\_restart, or - create\_box command. + The run command cannot be used before a read_data, read_restart, or + create_box command. *Run command start value is after start of run* Self-explanatory. @@ -7282,9 +7282,9 @@ keyword to allow for additional bonds to be formed *Run command stop value is before end of run* Self-explanatory. -*Run\_style command before simulation box is defined* - The run\_style command cannot be used before a read\_data, - read\_restart, or create\_box command. +*Run_style command before simulation box is defined* + The run_style command cannot be used before a read_data, + read_restart, or create_box command. *SRD bin size for fix srd differs from user request* Fix SRD had to adjust the bin size to fit the simulation box. See the @@ -7309,8 +7309,8 @@ keyword to allow for additional bonds to be formed Cannot specify a partition to be a sender twice. *Set command before simulation box is defined* - The set command cannot be used before a read\_data, read\_restart, - or create\_box command. + The set command cannot be used before a read_data, read_restart, + or create_box command. *Set command floating point vector does not exist* Self-explanatory. @@ -7360,8 +7360,8 @@ keyword to allow for additional bonds to be formed NPT fix must be defined in input script after SHAKE fix, else the SHAKE fix contribution to the pressure virial is incorrect. -*Shear history overflow, boost neigh\_modify one* - There are too many neighbors of a single atom. Use the neigh\_modify +*Shear history overflow, boost neigh_modify one* + There are too many neighbors of a single atom. Use the neigh_modify command to increase the max number of neighbors allowed for one atom. You may also want to boost the page size. @@ -7378,13 +7378,13 @@ keyword to allow for additional bonds to be formed you are running. *Special list size exceeded in fix bond/create* - See the "read\_data extra/special/per/atom" command - (or the "create\_box extra/special/per/atom" command) + See the "read_data extra/special/per/atom" command + (or the "create_box extra/special/per/atom" command) for info on how to leave space in the special bonds list to allow for additional bonds to be formed. *Species XXX is not supported by this KIM Simulator Model* - The kim\_style define command was referencing a species that is not + The kim_style define command was referencing a species that is not present in the requested KIM Simulator Model. *Specified processors != physical processors* @@ -7398,33 +7398,33 @@ keyword to allow for additional bonds to be formed Self-explanatory. *Subsequent read data induced too many angles per atom* - See the extra/angle/per/atom keyword for the create\_box - or the read\_data command to set this limit larger + See the extra/angle/per/atom keyword for the create_box + or the read_data command to set this limit larger *Subsequent read data induced too many bonds per atom* - See the extra/bond/per/atom keyword for the create\_box - or the read\_data command to set this limit larger + See the extra/bond/per/atom keyword for the create_box + or the read_data command to set this limit larger *Subsequent read data induced too many dihedrals per atom* - See the extra/dihedral/per/atom keyword for the create\_box - or the read\_data command to set this limit larger + See the extra/dihedral/per/atom keyword for the create_box + or the read_data command to set this limit larger *Subsequent read data induced too many impropers per atom* - See the extra/improper/per/atom keyword for the create\_box - or the read\_data command to set this limit larger + See the extra/improper/per/atom keyword for the create_box + or the read_data command to set this limit larger *Substitution for illegal variable* Input script line contained a variable that could not be substituted for. *Support for writing images in JPEG format not included* - LAMMPS was not built with the -DLAMMPS\_JPEG switch in the Makefile. + LAMMPS was not built with the -DLAMMPS_JPEG switch in the Makefile. *Support for writing images in PNG format not included* - LAMMPS was not built with the -DLAMMPS\_PNG switch in the Makefile. + LAMMPS was not built with the -DLAMMPS_PNG switch in the Makefile. *Support for writing movies not included* - LAMMPS was not built with the -DLAMMPS\_FFMPEG switch in the Makefile + LAMMPS was not built with the -DLAMMPS_FFMPEG switch in the Makefile *System in data file is too big* See the setting for bigint in the src/lmptype.h file. @@ -7433,7 +7433,7 @@ keyword to allow for additional bonds to be formed The total charge on all atoms on the system is not 0.0. For some KSpace solvers this is an error. -*TAD nsteps must be multiple of t\_event* +*TAD nsteps must be multiple of t_event* Self-explanatory. *TIP4P hydrogen has incorrect atom type* @@ -7480,8 +7480,8 @@ keyword to allow for additional bonds to be formed Self-explanatory. *Temper command before simulation box is defined* - The temper command cannot be used before a read\_data, read\_restart, or - create\_box command. + The temper command cannot be used before a read_data, read_restart, or + create_box command. *Temperature ID for fix bond/swap does not exist* Self-explanatory. @@ -7562,7 +7562,7 @@ keyword to allow for additional bonds to be formed *Temperature for fix nvt/sllod does not have a bias* The specified compute must compute temperature with a bias. -*Tempering could not find thermo\_pe compute* +*Tempering could not find thermo_pe compute* This compute is created by the thermo command. It must have been explicitly deleted by a uncompute command. @@ -7573,7 +7573,7 @@ keyword to allow for additional bonds to be formed The fix specified by the temper command is not one that controls temperature (nvt or langevin). -*Test\_descriptor\_string already allocated* +*Test_descriptor_string already allocated* This is an internal error. Contact the developers. *The package gpu command is required for gpu styles* @@ -7639,28 +7639,28 @@ keyword to allow for additional bonds to be formed your thermo output. *Thermo style does not use press* - Cannot use thermo\_modify to set this parameter since the thermo\_style + Cannot use thermo_modify to set this parameter since the thermo_style is not computing this quantity. *Thermo style does not use temp* - Cannot use thermo\_modify to set this parameter since the thermo\_style + Cannot use thermo_modify to set this parameter since the thermo_style is not computing this quantity. -*Thermo\_modify every variable returned a bad timestep* +*Thermo_modify every variable returned a bad timestep* The returned timestep is less than or equal to the current timestep. -*Thermo\_modify int format does not contain d character* +*Thermo_modify int format does not contain d character* Self-explanatory. -*Thermo\_modify pressure ID does not compute pressure* +*Thermo_modify pressure ID does not compute pressure* The specified compute ID does not compute pressure. -*Thermo\_modify temperature ID does not compute temperature* +*Thermo_modify temperature ID does not compute temperature* The specified compute ID does not compute temperature. -*Thermo\_style command before simulation box is defined* - The thermo\_style command cannot be used before a read\_data, - read\_restart, or create\_box command. +*Thermo_style command before simulation box is defined* + The thermo_style command cannot be used before a read_data, + read_restart, or create_box command. *This variable thermo keyword cannot be used between runs* Keywords that refer to time (such as cpu, elapsed) do not @@ -7683,7 +7683,7 @@ keyword to allow for additional bonds to be formed The timestep must fit in a 32-bit integer to use this dump style. *Too few bits for lookup table* - Table size specified via pair\_modify command does not work with your + Table size specified via pair_modify command does not work with your machine's floating point representation. *Too few lines in %s section of data file* @@ -7730,19 +7730,19 @@ keyword to allow for additional bonds to be formed Cannot sort when running with more than 2\^31 atoms. *Too many exponent bits for lookup table* - Table size specified via pair\_modify command does not work with your + Table size specified via pair_modify command does not work with your machine's floating point representation. *Too many groups* The maximum number of atom groups (including the "all" group) is - given by MAX\_GROUP in group.cpp and is 32. + given by MAX_GROUP in group.cpp and is 32. *Too many iterations* You must use a number of iterations that fit in a 32-bit integer for minimization. *Too many lines in one body in data file - boost MAXBODY* - MAXBODY is a setting at the top of the src/read\_data.cpp file. + MAXBODY is a setting at the top of the src/read_data.cpp file. Set it larger and re-compile the code. *Too many local+ghost atoms for neighbor list* @@ -7751,7 +7751,7 @@ keyword to allow for additional bonds to be formed removed for masking 1-2, 1-3, 1-4 neighbors. *Too many mantissa bits for lookup table* - Table size specified via pair\_modify command does not work with your + Table size specified via pair_modify command does not work with your machine's floating point representation. *Too many masses for fix shake* @@ -7779,7 +7779,7 @@ keyword to allow for additional bonds to be formed See the setting for bigint in the src/lmptype.h file. *Too many total bits for bitmapped lookup table* - Table size specified via pair\_modify command is too large. Note that + Table size specified via pair_modify command is too large. Note that a value of N generates a 2\^N size table. *Too many values in body lines in data file* @@ -7806,7 +7806,7 @@ keyword to allow for additional bonds to be formed +half of the x box length. This constraint can be relaxed by using the box tilt command. -*Tried to convert a double to int, but input\_double > INT\_MAX* +*Tried to convert a double to int, but input_double > INT_MAX* Self-explanatory. *Trying to build an occasional neighbor list before initialization completed* @@ -7868,8 +7868,8 @@ keyword to allow for additional bonds to be formed A read operation from the file failed. *Units command after simulation box is defined* - The units command cannot be used after a read\_data, read\_restart, or - create\_box command. + The units command cannot be used after a read_data, read_restart, or + create_box command. *Universe/uloop variable count < # of partitions* A universe or uloop style variable must specify a number of values >= to the @@ -7887,13 +7887,13 @@ keyword to allow for additional bonds to be formed *Unrecognized bond style* The choice of bond style is unknown. -*Unknown category for info is\_active()* +*Unknown category for info is_active()* Self-explanatory. -*Unknown category for info is\_available()* +*Unknown category for info is_available()* Self-explanatory. -*Unknown category for info is\_defined()* +*Unknown category for info is_defined()* Self-explanatory. *Unrecognized command: %s* @@ -7923,7 +7923,7 @@ keyword to allow for additional bonds to be formed *Unrecognized improper style* The choice of improper style is unknown. -*Unknown keyword in thermo\_style custom command* +*Unknown keyword in thermo_style custom command* One or more specified keywords are not recognized. *Unrecognized kspace style* @@ -7941,7 +7941,7 @@ keyword to allow for additional bonds to be formed *Unrecognized pair style* The choice of pair style is unknown. -*Unknown pair\_modify hybrid sub-style* +*Unknown pair_modify hybrid sub-style* The choice of sub-style is unknown. *Unrecognized region style* @@ -7956,10 +7956,10 @@ keyword to allow for additional bonds to be formed *Unknown table style in bond style table* Self-explanatory. -*Unknown table style in pair\_style command* - Style of table is invalid for use with pair\_style table command. +*Unknown table style in pair_style command* + Style of table is invalid for use with pair_style table command. -*Unknown unit\_style* +*Unknown unit_style* Self-explanatory. Check the input script or data file. *Unrecognized lattice type in MEAM file 1* @@ -7973,13 +7973,13 @@ keyword to allow for additional bonds to be formed *Unrecognized pair style in compute pair command* Self-explanatory. -*Unsupported mixing rule in kspace\_style ewald/disp* +*Unsupported mixing rule in kspace_style ewald/disp* Only geometric mixing is supported. -*Unsupported order in kspace\_style ewald/disp* +*Unsupported order in kspace_style ewald/disp* Only 1/r\^6 dispersion or dipole terms are supported. -*Unsupported order in kspace\_style pppm/disp, pair\_style %s* +*Unsupported order in kspace_style pppm/disp, pair_style %s* Only pair styles with 1/r and 1/r\^6 dependence are currently supported. *Use cutoff keyword to set cutoff in single mode* @@ -8042,10 +8042,10 @@ keyword to allow for additional bonds to be formed *Variable for compute ti is invalid style* Self-explanatory. -*Variable for create\_atoms is invalid style* +*Variable for create_atoms is invalid style* The variables must be equal-style variables. -*Variable for displace\_atoms is invalid style* +*Variable for displace_atoms is invalid style* It must be an equal-style or atom-style variable. *Variable for dump every is invalid style* @@ -8185,10 +8185,10 @@ keyword to allow for additional bonds to be formed *Variable name for compute ti does not exist* Self-explanatory. -*Variable name for create\_atoms does not exist* +*Variable name for create_atoms does not exist* Self-explanatory. -*Variable name for displace\_atoms does not exist* +*Variable name for displace_atoms does not exist* Self-explanatory. *Variable name for dump every does not exist* @@ -8324,8 +8324,8 @@ keyword to allow for additional bonds to be formed Self-explanatory. *Velocity command before simulation box is defined* - The velocity command cannot be used before a read\_data, read\_restart, - or create\_box command. + The velocity command cannot be used before a read_data, read_restart, + or create_box command. *Velocity command with no atoms existing* A velocity command has been used, but no atoms yet exist. @@ -8343,7 +8343,7 @@ keyword to allow for additional bonds to be formed The compute ID given to the velocity command must compute temperature. -*Verlet/split can only currently be used with comm\_style brick* +*Verlet/split can only currently be used with comm_style brick* This is a current restriction in LAMMPS. *Verlet/split does not yet support TIP4P* @@ -8392,17 +8392,17 @@ keyword to allow for additional bonds to be formed A world-style variable must specify a number of values equal to the number of processor partitions. -*Write\_data command before simulation box is defined* +*Write_data command before simulation box is defined* Self-explanatory. -*Write\_restart command before simulation box is defined* - The write\_restart command cannot be used before a read\_data, - read\_restart, or create\_box command. +*Write_restart command before simulation box is defined* + The write_restart command cannot be used before a read_data, + read_restart, or create_box command. *Writing to MPI-IO filename when MPIIO package is not installed* Self-explanatory. -*Zero length rotation vector with displace\_atoms* +*Zero length rotation vector with displace_atoms* Self-explanatory. *Zero length rotation vector with fix move* diff --git a/doc/src/Errors_warnings.rst b/doc/src/Errors_warnings.rst index 76bdad7adb..a4738a811c 100644 --- a/doc/src/Errors_warnings.rst +++ b/doc/src/Errors_warnings.rst @@ -37,7 +37,7 @@ Doc page with :doc:`ERROR messages ` *Angles are defined but no angle style is set* The topology contains angles, but there are no angle forces computed - since there was no angle\_style command. + since there was no angle_style command. *Atom style in data file differs from currently defined atom style* Self-explanatory. @@ -62,7 +62,7 @@ Doc page with :doc:`ERROR messages ` *Bonds are defined but no bond style is set* The topology contains bonds, but there are no bond forces computed - since there was no bond\_style command. + since there was no bond_style command. *Bond/angle/dihedral extent > half of periodic box length* This is a restriction because LAMMPS can be confused about which image @@ -83,8 +83,8 @@ Doc page with :doc:`ERROR messages ` *Both groups in compute group/group have a net charge; the Kspace boundary correction to energy will be non-zero* Self-explanatory. -*Calling write\_dump before a full system init.* - The write\_dump command is used before the system has been fully +*Calling write_dump before a full system init.* + The write_dump command is used before the system has been fully initialized as part of a 'run' or 'minimize' command. Not all dump styles and features are fully supported at this point and thus the command may fail or produce incomplete or incorrect output. Insert @@ -131,11 +131,11 @@ Doc page with :doc:`ERROR messages ` degrees-of-freedom for the atoms in those partial rigid bodies will not be accounted for. -*Create\_bonds max distance > minimum neighbor cutoff* +*Create_bonds max distance > minimum neighbor cutoff* This means atom pairs for some atom types may not be in the neighbor list and thus no bond can be created between them. -*Delete\_atoms cutoff > minimum neighbor cutoff* +*Delete_atoms cutoff > minimum neighbor cutoff* This means atom pairs for some atom types may not be in the neighbor list and thus an atom in that pair cannot be deleted. @@ -158,7 +158,7 @@ Doc page with :doc:`ERROR messages ` *Dihedrals are defined but no dihedral style is set* The topology contains dihedrals, but there are no dihedral forces computed - since there was no dihedral\_style command. + since there was no dihedral_style command. *Dump dcd/xtc timestamp may be wrong with fix dt/reset* If the fix changes the timestep, the dump dcd file will not @@ -172,7 +172,7 @@ Doc page with :doc:`ERROR messages ` *Estimated error in splitting of dispersion coeffs is %g* Error is greater than 0.0001 percent. -*Ewald/disp Newton solver failed, using old method to estimate g\_ewald* +*Ewald/disp Newton solver failed, using old method to estimate g_ewald* Self-explanatory. Choosing a different cutoff value may help. *FENE bond too long* @@ -209,8 +209,8 @@ Doc page with :doc:`ERROR messages ` This is probably an error, since you should not delete only one atom of a molecule. -*Fix gcmc using full\_energy option* - Fix gcmc has automatically turned on the full\_energy option since it +*Fix gcmc using full_energy option* + Fix gcmc has automatically turned on the full_energy option since it is required for systems like the one specified by the user. User input included one or more of the following: kspace, triclinic, a hybrid pair style, an eam pair style, or no "single" function for the pair @@ -265,19 +265,19 @@ This will most likely cause errors in kinetic fluctuations. *Fixes cannot send data in Kokkos communication, switching to classic communication* This is current restriction with Kokkos. -*For better accuracy use 'pair\_modify table 0'* +*For better accuracy use 'pair_modify table 0'* The user-specified force accuracy cannot be achieved unless the table - feature is disabled by using 'pair\_modify table 0'. + feature is disabled by using 'pair_modify table 0'. *Geometric mixing assumed for 1/r\^6 coefficients* Self-explanatory. -*Group for fix\_modify temp != fix group* - The fix\_modify command is specifying a temperature computation that +*Group for fix_modify temp != fix group* + The fix_modify command is specifying a temperature computation that computes a temperature on a different group of atoms than the fix itself operates on. This is probably not what you want to do. -*H matrix size has been exceeded: m\_fill=%d H.m=%d\n* +*H matrix size has been exceeded: m_fill=%d H.m=%d\n* This is the size of the matrix. *Ignoring unknown or incorrect info command flag* @@ -299,7 +299,7 @@ This will most likely cause errors in kinetic fluctuations. *Impropers are defined but no improper style is set* The topology contains impropers, but there are no improper forces computed - since there was no improper\_style command. + since there was no improper_style command. *Inconsistent image flags* The image flags for a pair on bonded atoms appear to be inconsistent. @@ -334,22 +334,22 @@ This will most likely cause errors in kinetic fluctuations. *KIM Model does not provide 'particleVirial'; virial per atom will be zero* Self-explanatory. -*Kspace\_modify slab param < 2.0 may cause unphysical behavior* - The kspace\_modify slab parameter should be larger to insure periodic +*Kspace_modify slab param < 2.0 may cause unphysical behavior* + The kspace_modify slab parameter should be larger to insure periodic grids padded with empty space do not overlap. *Less insertions than requested* The fix pour command was unsuccessful at finding open space for as many particles as it tried to insert. -*Library error in lammps\_gather\_atoms* +*Library error in lammps_gather_atoms* This library function cannot be used if atom IDs are not defined or are not consecutively numbered. -*Library error in lammps\_scatter\_atoms* +*Library error in lammps_scatter_atoms* This library function cannot be used if atom IDs are not defined or are not consecutively numbered, or if no atom map is defined. See the - atom\_modify command for details about atom maps. + atom_modify command for details about atom maps. *Likewise 1-2 special neighbor interactions != 1.0* The topology contains bonds, but there is no bond style defined @@ -372,15 +372,15 @@ This will most likely cause errors in kinetic fluctuations. pairs in the neighbor list in expectation of interactions for those pairs being computed from the dihedral style. -*Lost atoms via change\_box: original %ld current %ld* +*Lost atoms via change_box: original %ld current %ld* The command options you have used caused atoms to be lost. -*Lost atoms via displace\_atoms: original %ld current %ld* +*Lost atoms via displace_atoms: original %ld current %ld* The command options you have used caused atoms to be lost. *Lost atoms: original %ld current %ld* Lost atoms are checked for each time thermo output is done. See the - thermo\_modify lost command for options. Lost atoms usually indicate + thermo_modify lost command for options. Lost atoms usually indicate bad dynamics, e.g. atoms have been blown far out of the simulation box, or moved further than one processor's sub-domain away before reneighboring. @@ -403,8 +403,8 @@ This will most likely cause errors in kinetic fluctuations. This means the bonded atoms will not be excluded in pair-wise interactions. -*Molecule template for create\_atoms has multiple molecules* - The create\_atoms command will only create molecules of a single type, +*Molecule template for create_atoms has multiple molecules* + The create_atoms command will only create molecules of a single type, i.e. the first molecule in the template. *Molecule template for fix gcmc has multiple molecules* @@ -469,21 +469,21 @@ This will most likely cause errors in kinetic fluctuations. *Neighbor exclusions used with KSpace solver may give inconsistent Coulombic energies* This is because excluding specific pair interactions also excludes them from long-range interactions which may not be the desired effect. - The special\_bonds command handles this consistently by insuring + The special_bonds command handles this consistently by insuring excluded (or weighted) 1-2, 1-3, 1-4 interactions are treated consistently by both the short-range pair style and the long-range solver. This is not done for exclusions of charged atom pairs via the - neigh\_modify exclude command. + neigh_modify exclude command. -*New thermo\_style command, previous thermo\_modify settings will be lost* - If a thermo\_style command is used after a thermo\_modify command, the - settings changed by the thermo\_modify command will be reset to their - default values. This is because the thermo\_modify command acts on - the currently defined thermo style, and a thermo\_style command creates +*New thermo_style command, previous thermo_modify settings will be lost* + If a thermo_style command is used after a thermo_modify command, the + settings changed by the thermo_modify command will be reset to their + default values. This is because the thermo_modify command acts on + the currently defined thermo style, and a thermo_style command creates a new style. *No Kspace calculation with verlet/split* - The 2nd partition performs a kspace calculation so the kspace\_style + The 2nd partition performs a kspace calculation so the kspace_style command must be used. *No automatic unit conversion to XTC file format conventions possible for units lj* @@ -507,7 +507,7 @@ This will most likely cause errors in kinetic fluctuations. of two and the number of grid points in one or more directions have been adjusted to meet this requirement. -*OMP\_NUM\_THREADS environment is not set.* +*OMP_NUM_THREADS environment is not set.* This environment variable must be set appropriately to use the USER-OMP package. @@ -541,10 +541,10 @@ This will most likely cause errors in kinetic fluctuations. *Pair dpd needs newton pair on for momentum conservation* Self-explanatory. -*Pair dsmc: num\_of\_collisions > number\_of\_A* +*Pair dsmc: num_of_collisions > number_of_A* Collision model in DSMC is breaking down. -*Pair dsmc: num\_of\_collisions > number\_of\_B* +*Pair dsmc: num_of_collisions > number_of_B* Collision model in DSMC is breaking down. *Pair style in data file differs from currently defined pair style* @@ -569,15 +569,15 @@ This will most likely cause errors in kinetic fluctuations. sub-domain before reneighboring is triggered. *Reducing PPPM order b/c stencil extends beyond nearest neighbor processor* - This may lead to a larger grid than desired. See the kspace\_modify overlap + This may lead to a larger grid than desired. See the kspace_modify overlap command to prevent changing of the PPPM order. *Reducing PPPMDisp Coulomb order b/c stencil extends beyond neighbor processor* - This may lead to a larger grid than desired. See the kspace\_modify overlap + This may lead to a larger grid than desired. See the kspace_modify overlap command to prevent changing of the PPPM order. *Reducing PPPMDisp dispersion order b/c stencil extends beyond neighbor processor* - This may lead to a larger grid than desired. See the kspace\_modify overlap + This may lead to a larger grid than desired. See the kspace_modify overlap command to prevent changing of the PPPM order. *Replacing a fix, but new group != old group* @@ -590,19 +590,19 @@ This will most likely cause errors in kinetic fluctuations. dimension to be replicated; this may cause unwanted behavior. *Resetting reneighboring criteria during PRD* - A PRD simulation requires that neigh\_modify settings be delay = 0, + A PRD simulation requires that neigh_modify settings be delay = 0, every = 1, check = yes. Since these settings were not in place, LAMMPS changed them and will restore them to their original values after the PRD simulation. *Resetting reneighboring criteria during TAD* - A TAD simulation requires that neigh\_modify settings be delay = 0, + A TAD simulation requires that neigh_modify settings be delay = 0, every = 1, check = yes. Since these settings were not in place, LAMMPS changed them and will restore them to their original values after the PRD simulation. *Resetting reneighboring criteria during minimization* - Minimization requires that neigh\_modify settings be delay = 0, every = + Minimization requires that neigh_modify settings be delay = 0, every = 1, check = yes. Since these settings were not in place, LAMMPS changed them and will restore them to their original values after the minimization. @@ -706,7 +706,7 @@ This will most likely cause errors in kinetic fluctuations. which does operate on group all, so this may be inconsistent. *Temperature for thermo pressure is not for group all* - User-assigned temperature to thermo via the thermo\_modify command does + User-assigned temperature to thermo via the thermo_modify command does not compute temperature for all atoms. Since thermo computes a global pressure, the kinetic energy contribution from the temperature is assumed to also be for all atoms. Thus the pressure printed by thermo @@ -738,12 +738,12 @@ This will most likely cause errors in kinetic fluctuations. LAMMPS simulation may be inefficient as a result. *Use special bonds = 0,1,1 with bond style fene* - Most FENE models need this setting for the special\_bonds command. + Most FENE models need this setting for the special_bonds command. *Use special bonds = 0,1,1 with bond style fene/expand* - Most FENE models need this setting for the special\_bonds command. + Most FENE models need this setting for the special_bonds command. -*Using a many-body potential with bonds/angles/dihedrals and special\_bond exclusions* +*Using a many-body potential with bonds/angles/dihedrals and special_bond exclusions* This is likely not what you want to do. The exclusion settings will eliminate neighbors in the neighbor list, which the many-body potential needs to calculated its terms correctly. @@ -772,13 +772,13 @@ This will most likely cause errors in kinetic fluctuations. *Using largest cutoff for lj/long/coul/long* Self-explanatory. -*Using largest cutoff for pair\_style lj/long/tip4p/long* +*Using largest cutoff for pair_style lj/long/tip4p/long* Self-explanatory. *Using package gpu without any pair style defined* Self-explanatory. -*Using pair potential shift with pair\_modify compute no* +*Using pair potential shift with pair_modify compute no* The shift effects will thus not be computed. *Using pair tail corrections with nonperiodic system* @@ -786,8 +786,8 @@ This will most likely cause errors in kinetic fluctuations. computed by integrating the density of a periodic system out to infinity. -*Using pair tail corrections with pair\_modify compute no* +*Using pair tail corrections with pair_modify compute no* The tail corrections will thus not be computed. -*pair style reax is now deprecated and will soon be retired. Users should switch to pair\_style reax/c* +*pair style reax is now deprecated and will soon be retired. Users should switch to pair_style reax/c* Self-explanatory. diff --git a/doc/src/Examples.rst b/doc/src/Examples.rst index b45be6bcf0..36b486d31f 100644 --- a/doc/src/Examples.rst +++ b/doc/src/Examples.rst @@ -132,7 +132,7 @@ Lowercase directories +-------------+------------------------------------------------------------------+ | reax | RDX and TATB models using the ReaxFF | +-------------+------------------------------------------------------------------+ -| rerun | use of rerun and read\_dump commands | +| rerun | use of rerun and read_dump commands | +-------------+------------------------------------------------------------------+ | rigid | rigid bodies modeled as independent or coupled | +-------------+------------------------------------------------------------------+ @@ -170,7 +170,7 @@ web site. If you uncomment the :doc:`dump image ` line(s) in the input script a series of JPG images will be produced by the run (assuming you built LAMMPS with JPG support; see the -:doc:`Build\_settings ` doc page for details). These can +:doc:`Build_settings ` doc page for details). These can be viewed individually or turned into a movie or animated by tools like ImageMagick or QuickTime or various Windows-based tools. See the :doc:`dump image ` doc page for more details. E.g. this @@ -195,7 +195,7 @@ Uppercase directories +------------+--------------------------------------------------------------------------------------------------+ | ELASTIC | compute elastic constants at zero temperature | +------------+--------------------------------------------------------------------------------------------------+ -| ELASTIC\_T | compute elastic constants at finite temperature | +| ELASTIC_T | compute elastic constants at finite temperature | +------------+--------------------------------------------------------------------------------------------------+ | HEAT | compute thermal conductivity for LJ and water via fix ehex | +------------+--------------------------------------------------------------------------------------------------+ @@ -219,7 +219,7 @@ The USER directory has a large number of sub-directories which correspond by name to a USER package. They contain scripts that illustrate how to use the command(s) provided in that package. Many of the sub-directories have their own README files which give further -instructions. See the :doc:`Packages\_details ` doc +instructions. See the :doc:`Packages_details ` doc page for more info on specific USER packages. .. _openkim: https://openkim.org diff --git a/doc/src/Howto_2d.rst b/doc/src/Howto_2d.rst index a516315baf..1b4be32106 100644 --- a/doc/src/Howto_2d.rst +++ b/doc/src/Howto_2d.rst @@ -8,7 +8,7 @@ command. This is the default. If using the :doc:`create box ` command to define a simulation box, set the z dimensions narrow, but finite, so that the -create\_atoms command will tile the 3d simulation box with a single z +create_atoms command will tile the 3d simulation box with a single z plane of atoms - e.g. .. code-block:: LAMMPS @@ -17,7 +17,7 @@ plane of atoms - e.g. If using the :doc:`read data ` command to read in a file of atom coordinates, set the "zlo zhi" values to be finite but narrow, -similar to the create\_box command settings just described. For each +similar to the create_box command settings just described. For each atom in the file, assign a z coordinate so it falls inside the z-boundaries of the box - e.g. 0.0. diff --git a/doc/src/Howto_bash.rst b/doc/src/Howto_bash.rst index 2a182f5040..02322e5e1c 100644 --- a/doc/src/Howto_bash.rst +++ b/doc/src/Howto_bash.rst @@ -147,7 +147,7 @@ Compiling serial version cd src/ make -j 4 serial -This will create an executable called lmp\_serial in the src/ directory +This will create an executable called lmp_serial in the src/ directory Compiling MPI version """"""""""""""""""""" @@ -157,7 +157,7 @@ Compiling MPI version cd src/ make -j 4 mpi -This will create an executable called lmp\_mpi in the src/ directory +This will create an executable called lmp_mpi in the src/ directory ---------- @@ -192,8 +192,8 @@ examples/melt folder cd ../examples/melt -The full path of the serial executable is $LAMMPS\_DIR/lmp\_serial, while the mpi -version is $LAMMPS\_DIR/lmp\_mpi. You can run the melt example with either +The full path of the serial executable is $LAMMPS_DIR/lmp_serial, while the mpi +version is $LAMMPS_DIR/lmp_mpi. You can run the melt example with either version as follows: .. code-block:: bash @@ -206,7 +206,7 @@ or mpirun -np 4 $LAMMPS_DIR/lmp_mpi -in in.melt -Note the use of our variable $LAMMPS\_DIR, which expands into the full path of +Note the use of our variable $LAMMPS_DIR, which expands into the full path of the LAMMPS src folder we saved earlier. Adding your executable directory to your PATH @@ -241,7 +241,7 @@ and add this line **Example:** -For an executable lmp\_serial with a full path +For an executable lmp_serial with a full path .. code-block:: bash diff --git a/doc/src/Howto_body.rst b/doc/src/Howto_body.rst index 3cb65aab91..efb5a38a59 100644 --- a/doc/src/Howto_body.rst +++ b/doc/src/Howto_body.rst @@ -112,7 +112,7 @@ vanilla, prototypical example of a body particle, although as mentioned above, the :doc:`fix rigid ` command already duplicates its functionality. -The atom\_style body command for this body style takes two additional +The atom_style body command for this body style takes two additional arguments: .. parsed-literal:: @@ -188,14 +188,14 @@ The *bflag2* argument is ignored. The *rounded/polygon* body style represents body particles as a 2d polygon with a variable number of N vertices. This style can only be used for 2d models; see the :doc:`boundary ` command. See the -"pair\_style body/rounded/polygon" doc page for a diagram of two +"pair_style body/rounded/polygon" doc page for a diagram of two squares with rounded circles at the vertices. Special cases for N = 1 (circle) and N = 2 (rod with rounded ends) can also be specified. One use of this body style is for 2d discrete element models, as described in :ref:`Fraige `. -Similar to body style *nparticle*\ , the atom\_style body command for +Similar to body style *nparticle*\ , the atom_style body command for this body style takes two additional arguments: .. parsed-literal:: @@ -301,7 +301,7 @@ body particles with a wall. The *rounded/polyhedron* body style represents body particles as a 3d polyhedron with a variable number of N vertices, E edges and F faces. This style can only be used for 3d models; see the -:doc:`boundary ` command. See the "pair\_style +:doc:`boundary ` command. See the "pair_style body/rounded/polygon" doc page for a diagram of a two 2d squares with rounded circles at the vertices. A 3d cube with rounded spheres at the 8 vertices and 12 rounded edges would be similar. Special cases @@ -311,7 +311,7 @@ specified. This body style is for 3d discrete element models, as described in :ref:`Wang `. -Similar to body style *rounded/polygon*\ , the atom\_style body command +Similar to body style *rounded/polygon*\ , the atom_style body command for this body style takes two additional arguments: .. parsed-literal:: diff --git a/doc/src/Howto_client_server.rst b/doc/src/Howto_client_server.rst index 5f4e863797..c22e1ca3ab 100644 --- a/doc/src/Howto_client_server.rst +++ b/doc/src/Howto_client_server.rst @@ -93,22 +93,22 @@ client or server code: * examples/message * examples/COUPLE/README -* examples/COUPLE/lammps\_mc -* examples/COUPLE/lammps\_nwchem -* examples/COUPLE/lammps\_vasp +* examples/COUPLE/lammps_mc +* examples/COUPLE/lammps_nwchem +* examples/COUPLE/lammps_vasp The examples/message directory couples a client instance of LAMMPS to a server instance of LAMMPS. -The files in the *lammps\_mc* folder show how to couple LAMMPS as +The files in the *lammps_mc* folder show how to couple LAMMPS as a server to a simple Monte Carlo client code as the driver. -The files in the *lammps\_nwchem* folder show how to couple LAMMPS +The files in the *lammps_nwchem* folder show how to couple LAMMPS as a client code running MD timestepping to NWChem acting as a server providing quantum DFT forces, through a Python wrapper script on NWChem. -The files in the *lammps\_vasp* folder show how to couple LAMMPS as +The files in the *lammps_vasp* folder show how to couple LAMMPS as a client code running MD timestepping to VASP acting as a server providing quantum DFT forces, through a Python wrapper script on VASP. diff --git a/doc/src/Howto_couple.rst b/doc/src/Howto_couple.rst index 5bcf026387..c652d4f599 100644 --- a/doc/src/Howto_couple.rst +++ b/doc/src/Howto_couple.rst @@ -64,9 +64,9 @@ examples/COUPLE/README for more details: library * plugin: simple driver program in C which invokes LAMMPS as a plugin from a shared library. -* lammps\_quest: coupling of LAMMPS and `Quest `_, to run classical +* lammps_quest: coupling of LAMMPS and `Quest `_, to run classical MD with quantum forces calculated by a density functional code -* lammps\_spparks: coupling of LAMMPS and `SPPARKS `_, to couple +* lammps_spparks: coupling of LAMMPS and `SPPARKS `_, to couple a kinetic Monte Carlo model for grain growth using MD to calculate strain induced across grain boundaries @@ -89,7 +89,7 @@ The files src/library.cpp and library.h contain the C-style interface to LAMMPS. See the :doc:`Howto library ` doc page for a description of the interface and how to extend it for your needs. -Note that the lammps\_open() function that creates an instance of +Note that the lammps_open() function that creates an instance of LAMMPS takes an MPI communicator as an argument. This means that instance of LAMMPS will run on the set of processors in the communicator. Thus the calling code can run LAMMPS on all or a subset diff --git a/doc/src/Howto_dispersion.rst b/doc/src/Howto_dispersion.rst index f1c818162b..a173e0cfbd 100644 --- a/doc/src/Howto_dispersion.rst +++ b/doc/src/Howto_dispersion.rst @@ -29,7 +29,7 @@ that provide fast and accurate simulations, there are two approaches, which both have their up- and downsides. The first approach is to set desired real-space an kspace accuracies -via the *kspace\_modify force/disp/real* and *kspace\_modify +via the *kspace_modify force/disp/real* and *kspace_modify force/disp/kspace* commands. Note that the accuracies have to be specified in force units and are thus dependent on the chosen unit settings. For real units, 0.0001 and 0.002 seem to provide reasonable @@ -37,14 +37,14 @@ accurate and efficient computations for the real-space and kspace accuracies. 0.002 and 0.05 work well for most systems using lj units. PPPM parameters will be generated based on the desired accuracies. The upside of this approach is that it usually provides a -good set of parameters and will work for both the *kspace\_modify diff -ad* and *kspace\_modify diff ik* options. The downside of the method +good set of parameters and will work for both the *kspace_modify diff +ad* and *kspace_modify diff ik* options. The downside of the method is that setting the PPPM parameters will take some time during the initialization of the simulation. The second approach is to set the parameters for the pppm/disp -explicitly using the *kspace\_modify mesh/disp*, *kspace\_modify -order/disp*, and *kspace\_modify gewald/disp* commands. This approach +explicitly using the *kspace_modify mesh/disp*, *kspace_modify +order/disp*, and *kspace_modify gewald/disp* commands. This approach requires a more experienced user who understands well the impact of the choice of parameters on the simulation accuracy and performance. This approach provides a fast initialization of the @@ -60,12 +60,12 @@ To avoid inaccurate or inefficient simulations, the pppm/disp stops simulations with an error message if no action is taken to control the PPPM parameters. If the automatic parameter generation is desired and real-space and kspace accuracies are desired to be equal, this error -message can be suppressed using the *kspace\_modify disp/auto yes* +message can be suppressed using the *kspace_modify disp/auto yes* command. A reasonable approach that combines the upsides of both methods is to -make the first run using the *kspace\_modify force/disp/real* and -*kspace\_modify force/disp/kspace* commands, write down the PPPM +make the first run using the *kspace_modify force/disp/real* and +*kspace_modify force/disp/kspace* commands, write down the PPPM parameters from the output, and specify these parameters using the second approach in subsequent runs (which have the same composition, force field, and approximately the same volume). @@ -82,8 +82,8 @@ The second is that the mixing rule of the pair style has an impact on the computation time when using the pppm/disp. Fastest computations are achieved when using the geometric mixing rule. Using the arithmetic mixing rule substantially increases the computational cost. -The computational overhead can be reduced using the *kspace\_modify -mix/disp geom* and *kspace\_modify splittol* commands. The first +The computational overhead can be reduced using the *kspace_modify +mix/disp geom* and *kspace_modify splittol* commands. The first command simply enforces geometric mixing of the dispersion coefficients in kspace computations. This introduces some error in the computations but will also significantly speed-up the @@ -94,7 +94,7 @@ command, but will usually also not provide an equally good increase of efficiency. Finally, pppm/disp can also be used when no mixing rules apply. -This can be achieved using the *kspace\_modify mix/disp none* command. +This can be achieved using the *kspace_modify mix/disp none* command. Note that the code does not check automatically whether any mixing rule is fulfilled. If mixing rules do not apply, the user will have to specify this command explicitly. diff --git a/doc/src/Howto_drude.rst b/doc/src/Howto_drude.rst index 6efe731ee1..62659711c4 100644 --- a/doc/src/Howto_drude.rst +++ b/doc/src/Howto_drude.rst @@ -48,7 +48,7 @@ for a Langevin thermostat, or :doc:`fix drude/transform/\* thermostat. The former requires use of the command :doc:`comm_modify vel yes `. The latter requires two separate integration fixes like *nvt* or *npt*\ . The correct temperatures of the reduced degrees of freedom can be calculated using the :doc:`compute temp/drude `. This requires also to use the -command *comm\_modify vel yes*. +command *comm_modify vel yes*. Short-range damping of the induced dipole interactions can be achieved using Thole functions through the :doc:`pair style thole ` in :doc:`pair_style hybrid/overlay ` diff --git a/doc/src/Howto_drude2.rst b/doc/src/Howto_drude2.rst index 039897a20b..7a8a8b4c2c 100644 --- a/doc/src/Howto_drude2.rst +++ b/doc/src/Howto_drude2.rst @@ -76,7 +76,7 @@ important features: **Preparation of the data file** The data file is similar to a standard LAMMPS data file for -*atom\_style full*. The DPs and the *harmonic bonds* connecting them +*atom_style full*. The DPs and the *harmonic bonds* connecting them to their DC should appear in the data file as normal atoms and bonds. You can use the *polarizer* tool (Python script distributed with the @@ -159,9 +159,9 @@ Let us assume we want to run a simple NVT simulation at 300 K. Note that Drude oscillators need to be thermalized at a low temperature in order to approximate a self-consistent field (SCF), therefore it is not possible to simulate an NVE ensemble with this package. Since dipoles -are approximated by a charged DC-DP pair, the *pair\_style* must +are approximated by a charged DC-DP pair, the *pair_style* must include Coulomb interactions, for instance *lj/cut/coul/long* with -*kspace\_style pppm*. For example, with a cutoff of 10. and a precision +*kspace_style pppm*. For example, with a cutoff of 10. and a precision 1.e-4: .. code-block:: LAMMPS @@ -169,9 +169,9 @@ include Coulomb interactions, for instance *lj/cut/coul/long* with pair_style lj/cut/coul/long 10.0 kspace_style pppm 1.0e-4 -As compared to the non-polarizable input file, *pair\_coeff* lines need +As compared to the non-polarizable input file, *pair_coeff* lines need to be added for the DPs. Since the DPs have no Lennard-Jones -interactions, their :math:`\epsilon` is 0. so the only *pair\_coeff* line +interactions, their :math:`\epsilon` is 0. so the only *pair_coeff* line that needs to be added is .. code-block:: LAMMPS @@ -222,7 +222,7 @@ modification of forces but no position/velocity updates), the fix fix NVE all nve Finally, do not forget to update the atom type elements if you use -them in a *dump\_modify ... element ...* command, by adding the element +them in a *dump_modify ... element ...* command, by adding the element type of the DPs. Here for instance .. code-block:: LAMMPS @@ -232,19 +232,19 @@ type of the DPs. Here for instance The input file should now be ready for use! -You will notice that the global temperature *thermo\_temp* computed by +You will notice that the global temperature *thermo_temp* computed by LAMMPS is not 300. K as wanted. This is because LAMMPS treats DPs as standard atoms in his default compute. If you want to output the temperatures of the DC-DP pair centers of mass and of the DPs relative -to their DCs, you should use the :doc:`compute temp\_drude ` +to their DCs, you should use the :doc:`compute temp_drude ` .. code-block:: LAMMPS compute TDRUDE all temp/drude And then output the correct temperatures of the Drude oscillators -using *thermo\_style custom* with respectively *c\_TDRUDE[1]* and -*c\_TDRUDE[2]*. These should be close to 300.0 and 1.0 on average. +using *thermo_style custom* with respectively *c_TDRUDE[1]* and +*c_TDRUDE[2]*. These should be close to 300.0 and 1.0 on average. .. code-block:: LAMMPS @@ -263,8 +263,8 @@ between nearby dipoles on the same molecule may be exaggerated. Often, special bond relations prevent bonded neighboring atoms to see the charge of each other's DP, so that the problem does not always appear. It is possible to use screened dipole-dipole interactions by using the -:doc:`*pair\_style thole* `. This is implemented as a -correction to the Coulomb pair\_styles, which dampens at short distance +:doc:`*pair_style thole* `. This is implemented as a +correction to the Coulomb pair_styles, which dampens at short distance the interactions between the charges representing the induced dipoles. It is to be used as *hybrid/overlay* with any standard *coul* pair style. In our example, we would use @@ -273,15 +273,15 @@ style. In our example, we would use pair_style hybrid/overlay lj/cut/coul/long 10.0 thole 2.6 10.0 -This tells LAMMPS that we are using two pair\_styles. The first one is +This tells LAMMPS that we are using two pair_styles. The first one is as above (\ *lj/cut/coul/long 10.0*\ ). The second one is a *thole* -pair\_style with default screening factor 2.6 (:ref:`Noskov `) and +pair_style with default screening factor 2.6 (:ref:`Noskov `) and cutoff 10.0. Since *hybrid/overlay* does not support mixing rules, the interaction coefficients of all the pairs of atom types with i < j should be explicitly defined. The output of the *polarizer* script can be used -to complete the *pair\_coeff* section of the input file. In our +to complete the *pair_coeff* section of the input file. In our example, this will look like: .. code-block:: LAMMPS @@ -324,17 +324,17 @@ For the *thole* pair style the coefficients are #. the atom polarizability in units of cubic length #. the screening factor of the Thole function (optional, default value - specified by the pair\_style command) -#. the cutoff (optional, default value defined by the pair\_style command) + specified by the pair_style command) +#. the cutoff (optional, default value defined by the pair_style command) The special neighbors have charge-charge and charge-dipole -interactions screened by the *coul* factors of the *special\_bonds* +interactions screened by the *coul* factors of the *special_bonds* command (0.0, 0.0, and 0.5 in the example above). Without using the -pair\_style *thole*\ , dipole-dipole interactions are screened by the -same factor. By using the pair\_style *thole*\ , dipole-dipole +pair_style *thole*\ , dipole-dipole interactions are screened by the +same factor. By using the pair_style *thole*\ , dipole-dipole interactions are screened by Thole's function, whatever their special relationship (except within each DC-DP pair of course). Consider for -example 1-2 neighbors: using the pair\_style *thole*\ , their dipoles +example 1-2 neighbors: using the pair_style *thole*\ , their dipoles will see each other (despite the *coul* factor being 0.) and the interactions between these dipoles will be damped by Thole's function. @@ -375,7 +375,7 @@ For our phenol example, the groups would be defined as group DRUDES type 6 7 8 # DPs Note that with the fixes *drude/transform*\ , it is not required to -specify *comm\_modify vel yes* because the fixes do it anyway (several +specify *comm_modify vel yes* because the fixes do it anyway (several times and for the forces also). To avoid the flying ice cube artifact :ref:`(Lamoureux) `, where the atoms progressively freeze and the center of mass of the whole system drifts faster and faster, the *fix @@ -392,7 +392,7 @@ DPs should be *nvt* (or vice versa). Second, the *fix npt* computes a global pressure and thus a global temperature whatever the fix group. We do want the pressure to correspond to the whole system, but we want the temperature to correspond to the fix group only. We must then use -the *fix\_modify* command for this. In the end, the block of +the *fix_modify* command for this. In the end, the block of instructions for thermostatting and barostatting will look like .. code-block:: LAMMPS diff --git a/doc/src/Howto_elastic.rst b/doc/src/Howto_elastic.rst index 1d633e6e98..4870942458 100644 --- a/doc/src/Howto_elastic.rst +++ b/doc/src/Howto_elastic.rst @@ -4,14 +4,14 @@ Calculate elastic constants Elastic constants characterize the stiffness of a material. The formal definition is provided by the linear relation that holds between the stress and strain tensors in the limit of infinitesimal deformation. -In tensor notation, this is expressed as s\_ij = C\_ijkl \* e\_kl, where -the repeated indices imply summation. s\_ij are the elements of the -symmetric stress tensor. e\_kl are the elements of the symmetric strain -tensor. C\_ijkl are the elements of the fourth rank tensor of elastic +In tensor notation, this is expressed as s_ij = C_ijkl \* e_kl, where +the repeated indices imply summation. s_ij are the elements of the +symmetric stress tensor. e_kl are the elements of the symmetric strain +tensor. C_ijkl are the elements of the fourth rank tensor of elastic constants. In three dimensions, this tensor has 3\^4=81 elements. Using -Voigt notation, the tensor can be written as a 6x6 matrix, where C\_ij -is now the derivative of s\_i w.r.t. e\_j. Because s\_i is itself a -derivative w.r.t. e\_i, it follows that C\_ij is also symmetric, with at +Voigt notation, the tensor can be written as a 6x6 matrix, where C_ij +is now the derivative of s_i w.r.t. e_j. Because s_i is itself a +derivative w.r.t. e_i, it follows that C_ij is also symmetric, with at most 7\*6/2 = 21 distinct elements. At zero temperature, it is easy to estimate these derivatives by diff --git a/doc/src/Howto_github.rst b/doc/src/Howto_github.rst index f51d15d865..55db356589 100644 --- a/doc/src/Howto_github.rst +++ b/doc/src/Howto_github.rst @@ -287,10 +287,10 @@ After each push, the automated checks are run again. LAMMPS developers may add labels to your pull request to assign it to categories (mostly for bookkeeping purposes), but a few of them are -important: needs\_work, work\_in\_progress, test-for-regression, and +important: needs_work, work_in_progress, test-for-regression, and full-regression-test. The first two indicate, that your pull request -is not considered to be complete. With "needs\_work" the burden is on -exclusively on you; while "work\_in\_progress" can also mean, that a +is not considered to be complete. With "needs_work" the burden is on +exclusively on you; while "work_in_progress" can also mean, that a LAMMPS developer may want to add changes. Please watch the comments to the pull requests. The two "test" labels are used to trigger extended tests before the code is merged. This is sometimes done by @@ -458,7 +458,7 @@ should be submitted, there is now also an "unstable" and a "stable" branch; these have the same content as "master", but are only updated after a patch release or stable release was made. Furthermore, the naming of the patches now follow the pattern -"patch\_" to simplify comparisons between releases. +"patch_" to simplify comparisons between releases. Finally, all patches and submissions are subject to automatic testing and code checks to make sure they at the very least compile. diff --git a/doc/src/Howto_granular.rst b/doc/src/Howto_granular.rst index 25fc9869ea..c696d44249 100644 --- a/doc/src/Howto_granular.rst +++ b/doc/src/Howto_granular.rst @@ -22,7 +22,7 @@ Use one of these 3 pair potentials, which compute forces and torques between interacting pairs of particles: * :doc:`pair_style ` gran/history -* :doc:`pair_style ` gran/no\_history +* :doc:`pair_style ` gran/no_history * :doc:`pair_style ` gran/hertzian These commands implement fix options specific to granular systems: diff --git a/doc/src/Howto_kappa.rst b/doc/src/Howto_kappa.rst index 6b7fa6b54a..08697ecc84 100644 --- a/doc/src/Howto_kappa.rst +++ b/doc/src/Howto_kappa.rst @@ -56,7 +56,7 @@ two preceding non-equilibrium methods, where energy flows continuously between hot and cold regions of the simulation box. The :doc:`compute heat/flux ` command can calculate -the needed heat flux and describes how to implement the Green\_Kubo +the needed heat flux and describes how to implement the Green_Kubo formalism using additional LAMMPS commands, such as the :doc:`fix ave/correlate ` command to calculate the needed auto-correlation. See the doc page for the :doc:`compute heat/flux ` command for an example input script that calculates the thermal conductivity of solid Ar via the GK diff --git a/doc/src/Howto_library.rst b/doc/src/Howto_library.rst index 55216f9ef7..774d9838c1 100644 --- a/doc/src/Howto_library.rst +++ b/doc/src/Howto_library.rst @@ -12,7 +12,7 @@ functions therein have a C-style argument list, but contain C++ code you could write yourself in a C++ application that was invoking LAMMPS directly. The C++ code in the functions illustrates how to invoke internal LAMMPS operations. Note that LAMMPS classes are defined -within a LAMMPS namespace (LAMMPS\_NS) if you use them from another C++ +within a LAMMPS namespace (LAMMPS_NS) if you use them from another C++ application. The examples/COUPLE and python/examples directories have example C++ @@ -34,7 +34,7 @@ interface LAMMPS to Fortran libraries, or the code uses static variables Another major issue to deal with is to correctly handle MPI. Creating a LAMMPS instance requires passing an MPI communicator, or it assumes -the MPI\_COMM\_WORLD communicator, which spans all MPI processor ranks. +the MPI_COMM_WORLD communicator, which spans all MPI processor ranks. When creating multiple LAMMPS object instances from different threads, this communicator has to be different for each thread or else collisions can happen, or it has to be guaranteed, that only one thread at a time @@ -70,11 +70,11 @@ details. void lammps_commands_string(void *, char *) void lammps_free(void *) -The lammps\_open() function is used to initialize LAMMPS, passing in a +The lammps_open() function is used to initialize LAMMPS, passing in a list of strings as if they were :doc:`command-line arguments ` when LAMMPS is run in stand-alone mode from the command line, and a MPI communicator for LAMMPS to run under. It returns a ptr to the LAMMPS object that is created, and which is -used in subsequent library calls. The lammps\_open() function can be +used in subsequent library calls. The lammps_open() function can be called multiple times, to create multiple instances of LAMMPS. LAMMPS will run on the set of processors in the communicator. This @@ -86,14 +86,14 @@ half to the other code and run both codes simultaneously before syncing them up periodically. Or it might instantiate multiple instances of LAMMPS to perform different calculations. -The lammps\_open\_no\_mpi() function is similar except that no MPI -communicator is passed from the caller. Instead, MPI\_COMM\_WORLD is +The lammps_open_no_mpi() function is similar except that no MPI +communicator is passed from the caller. Instead, MPI_COMM_WORLD is used to instantiate LAMMPS, and MPI is initialized if necessary. -The lammps\_close() function is used to shut down an instance of LAMMPS +The lammps_close() function is used to shut down an instance of LAMMPS and free all its memory. -The lammps\_version() function can be used to determined the specific +The lammps_version() function can be used to determined the specific version of the underlying LAMMPS code. This is particularly useful when loading LAMMPS as a shared library via dlopen(). The code using the library interface can than use this information to adapt to @@ -101,8 +101,8 @@ changes to the LAMMPS command syntax between versions. The returned LAMMPS version code is an integer (e.g. 2 Sep 2015 results in 20150902) that grows with every new LAMMPS version. -The lammps\_file(), lammps\_command(), lammps\_commands\_list(), and -lammps\_commands\_string() functions are used to pass one or more +The lammps_file(), lammps_command(), lammps_commands_list(), and +lammps_commands_string() functions are used to pass one or more commands to LAMMPS to execute, the same as if they were coming from an input script. @@ -113,19 +113,19 @@ can interleave the command function calls with operations it performs, calls to extract information from or set information within LAMMPS, or calls to another code's library. -The lammps\_file() function passes the filename of an input script. -The lammps\_command() function passes a single command as a string. -The lammps\_commands\_list() function passes multiple commands in a -char\*\* list. In both lammps\_command() and lammps\_commands\_list(), +The lammps_file() function passes the filename of an input script. +The lammps_command() function passes a single command as a string. +The lammps_commands_list() function passes multiple commands in a +char\*\* list. In both lammps_command() and lammps_commands_list(), individual commands may or may not have a trailing newline. The -lammps\_commands\_string() function passes multiple commands +lammps_commands_string() function passes multiple commands concatenated into one long string, separated by newline characters. -In both lammps\_commands\_list() and lammps\_commands\_string(), a single +In both lammps_commands_list() and lammps_commands_string(), a single command can be spread across multiple lines, if the last printable character of all but the last line is "&", the same as if the lines appeared in an input script. -The lammps\_free() function is a clean-up function to free memory that +The lammps_free() function is a clean-up function to free memory that the library allocated previously via other function calls. See comments in src/library.cpp file for which other functions need this clean-up. @@ -146,15 +146,15 @@ which quantities can be queried by name: void *lammps_extract_fix(void *, char *, int, int, int, int) void *lammps_extract_variable(void *, char *, char *) -The extract\_setting() function returns info on the size +The extract_setting() function returns info on the size of data types (e.g. 32-bit or 64-bit atom IDs) used by the LAMMPS executable (a compile-time choice). The other extract functions return a pointer to various global or per-atom quantities stored in LAMMPS or to values calculated by a compute, fix, or variable. The pointer returned by the -extract\_global() function can be used as a permanent reference to a -value which may change. For the extract\_atom() method, see the +extract_global() function can be used as a permanent reference to a +value which may change. For the extract_atom() method, see the extract() method in the src/atom.cpp file for a list of valid per-atom properties. New names could easily be added if the property you want is not listed. For the other extract functions, the underlying @@ -169,18 +169,18 @@ function to assure a current pointer or returned value(s). int lammps_set_variable(void *, char *, char *) void lammps_reset_box(void *, double *, double *, double, double, double) -The lammps\_get\_thermo() function returns the current value of a thermo +The lammps_get_thermo() function returns the current value of a thermo keyword as a double precision value. -The lammps\_get\_natoms() function returns the total number of atoms in +The lammps_get_natoms() function returns the total number of atoms in the system and can be used by the caller to allocate memory for the -lammps\_gather\_atoms() and lammps\_scatter\_atoms() functions. +lammps_gather_atoms() and lammps_scatter_atoms() functions. -The lammps\_set\_variable() function can set an existing string-style +The lammps_set_variable() function can set an existing string-style variable to a new string value, so that subsequent LAMMPS commands can access the variable. -The lammps\_reset\_box() function resets the size and shape of the +The lammps_reset_box() function resets the size and shape of the simulation box, e.g. as part of restoring a previously extracted and saved state of a simulation. @@ -202,17 +202,17 @@ owned by different processors. .. warning:: These functions are not compatible with the - -DLAMMPS\_BIGBIG setting when compiling LAMMPS. Dummy functions + -DLAMMPS_BIGBIG setting when compiling LAMMPS. Dummy functions that result in an error message and abort will be substituted instead of resulting in random crashes and memory corruption. -The lammps\_gather\_atoms() function does this for all N atoms in the +The lammps_gather_atoms() function does this for all N atoms in the system, ordered by atom ID, from 1 to N. The -lammps\_gather\_atoms\_concat() function does it for all N atoms, but +lammps_gather_atoms_concat() function does it for all N atoms, but simply concatenates the subset of atoms owned by each processor. The resulting vector is not ordered by atom ID. Atom IDs can be requested by the same function if the caller needs to know the ordering. The -lammps\_gather\_subset() function allows the caller to request values +lammps_gather_subset() function allows the caller to request values for only a subset of atoms (identified by ID). For all 3 gather function, per-atom image flags can be retrieved in 2 ways. If the count is specified as 1, they are returned @@ -220,10 +220,10 @@ in a packed format with all three image flags stored in a single integer. If the count is specified as 3, the values are unpacked into xyz flags by the library before returning them. -The lammps\_scatter\_atoms() function takes a list of values for all N +The lammps_scatter_atoms() function takes a list of values for all N atoms in the system, ordered by atom ID, from 1 to N, and assigns those values to each atom in the system. The -lammps\_scatter\_atoms\_subset() function takes a subset of IDs as an +lammps_scatter_atoms_subset() function takes a subset of IDs as an argument and only scatters those values to the owning atoms. .. code-block:: c @@ -231,12 +231,12 @@ argument and only scatters those values to the owning atoms. void lammps_create_atoms(void *, int, tagint *, int *, double *, double *, imageint *, int) -The lammps\_create\_atoms() function takes a list of N atoms as input +The lammps_create_atoms() function takes a list of N atoms as input with atom types and coords (required), an optionally atom IDs and velocities and image flags. It uses the coords of each atom to assign it as a new atom to the processor that owns it. This function is useful to add atoms to a simulation or (in tandem with -lammps\_reset\_box()) to restore a previously extracted and saved state +lammps_reset_box()) to restore a previously extracted and saved state of a simulation. Additional properties for the new atoms can then be -assigned via the lammps\_scatter\_atoms() or lammps\_extract\_atom() +assigned via the lammps_scatter_atoms() or lammps_extract_atom() functions. diff --git a/doc/src/Howto_manifold.rst b/doc/src/Howto_manifold.rst index e7d31d79d9..239c32b342 100644 --- a/doc/src/Howto_manifold.rst +++ b/doc/src/Howto_manifold.rst @@ -19,17 +19,17 @@ to the relevant fixes. +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ | cylinder | R | x\^2 + y\^2 - R\^2 = 0 | Cylinder along z-axis, axis going through (0,0,0) | +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ -| cylinder\_dent | R l a | x\^2 + y\^2 - r(z)\^2 = 0, r(x) = R if \| z \| > l, r(z) = R - a\*(1 + cos(z/l))/2 otherwise | A cylinder with a dent around z = 0 | +| cylinder_dent | R l a | x\^2 + y\^2 - r(z)\^2 = 0, r(x) = R if \| z \| > l, r(z) = R - a\*(1 + cos(z/l))/2 otherwise | A cylinder with a dent around z = 0 | +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ | dumbbell | a A B c | -( x\^2 + y\^2 ) + (a\^2 - z\^2/c\^2) \* ( 1 + (A\*sin(B\*z\^2))\^4) = 0 | A dumbbell | +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ | ellipsoid | a b c | (x/a)\^2 + (y/b)\^2 + (z/c)\^2 = 0 | An ellipsoid | +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ -| gaussian\_bump | A l rc1 rc2 | if( x < rc1) -z + A \* exp( -x\^2 / (2 l\^2) ); else if( x < rc2 ) -z + a + b\*x + c\*x\^2 + d\*x\^3; else z | A Gaussian bump at x = y = 0, smoothly tapered to a flat plane z = 0. | +| gaussian_bump | A l rc1 rc2 | if( x < rc1) -z + A \* exp( -x\^2 / (2 l\^2) ); else if( x < rc2 ) -z + a + b\*x + c\*x\^2 + d\*x\^3; else z | A Gaussian bump at x = y = 0, smoothly tapered to a flat plane z = 0. | +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ | plane | a b c x0 y0 z0 | a\*(x-x0) + b\*(y-y0) + c\*(z-z0) = 0 | A plane with normal (a,b,c) going through point (x0,y0,z0) | +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ -| plane\_wiggle | a w | z - a\*sin(w\*x) = 0 | A plane with a sinusoidal modulation on z along x. | +| plane_wiggle | a w | z - a\*sin(w\*x) = 0 | A plane with a sinusoidal modulation on z along x. | +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ | sphere | R | x\^2 + y\^2 + z\^2 - R\^2 = 0 | A sphere of radius R | +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ @@ -37,7 +37,7 @@ to the relevant fixes. +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ | spine | a, A, B, B2, c | -(x\^2 + y\^2) + (a\^2 - z\^2/f(z)\^2)\*(1 + (A\*sin(g(z)\*z\^2))\^4), f(z) = c if z > 0, 1 otherwise; g(z) = B if z > 0, B2 otherwise | An approximation to a dendritic spine | +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ -| spine\_two | a, A, B, B2, c | -(x\^2 + y\^2) + (a\^2 - z\^2/f(z)\^2)\*(1 + (A\*sin(g(z)\*z\^2))\^2), f(z) = c if z > 0, 1 otherwise; g(z) = B if z > 0, B2 otherwise | Another approximation to a dendritic spine | +| spine_two | a, A, B, B2, c | -(x\^2 + y\^2) + (a\^2 - z\^2/f(z)\^2)\*(1 + (A\*sin(g(z)\*z\^2))\^2), f(z) = c if z > 0, 1 otherwise; g(z) = B if z > 0, B2 otherwise | Another approximation to a dendritic spine | +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ | thylakoid | wB LB lB | Various, see :ref:`(Paquay) ` | A model grana thylakoid consisting of two block-like compartments connected by a bridge of width wB, length LB and taper length lB | +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ diff --git a/doc/src/Howto_output.rst b/doc/src/Howto_output.rst index 64a9e01971..04e73c2272 100644 --- a/doc/src/Howto_output.rst +++ b/doc/src/Howto_output.rst @@ -68,11 +68,11 @@ notation, where ID in this case is the ID of a compute. The leading "c\_" would be replaced by "f\_" for a fix, or "v\_" for a variable: +-------------+--------------------------------------------+ -| c\_ID | entire scalar, vector, or array | +| c_ID | entire scalar, vector, or array | +-------------+--------------------------------------------+ -| c\_ID[I] | one element of vector, one column of array | +| c_ID[I] | one element of vector, one column of array | +-------------+--------------------------------------------+ -| c\_ID[I][J] | one element of array | +| c_ID[I][J] | one element of array | +-------------+--------------------------------------------+ In other words, using one bracket reduces the dimension of the data @@ -92,7 +92,7 @@ The frequency and format of thermodynamic output is set by the :doc:`thermo_style ` command also specifies what values are calculated and written out. Pre-defined keywords can be specified (e.g. press, etotal, etc). Three additional kinds of keywords can -also be specified (c\_ID, f\_ID, v\_name), where a :doc:`compute ` +also be specified (c_ID, f_ID, v_name), where a :doc:`compute ` or :doc:`fix ` or :doc:`variable ` provides the value to be output. In each case, the compute, fix, or variable must generate global values for input to the :doc:`thermo_style custom ` @@ -121,7 +121,7 @@ pre-defined formats (dump atom, dump xtc, etc). There is also a :doc:`dump custom ` format where the user specifies what values are output with each atom. Pre-defined atom attributes can be specified (id, x, fx, etc). Three additional kinds -of keywords can also be specified (c\_ID, f\_ID, v\_name), where a +of keywords can also be specified (c_ID, f_ID, v_name), where a :doc:`compute ` or :doc:`fix ` or :doc:`variable ` provides the values to be output. In each case, the compute, fix, or variable must generate per-atom values for input to the :doc:`dump custom ` command. @@ -129,7 +129,7 @@ variable must generate per-atom values for input to the :doc:`dump custom There is also a :doc:`dump local ` format where the user specifies what local values to output. A pre-defined index keyword can be specified to enumerate the local values. Two additional kinds of -keywords can also be specified (c\_ID, f\_ID), where a +keywords can also be specified (c_ID, f_ID), where a :doc:`compute ` or :doc:`fix ` or :doc:`variable ` provides the values to be output. In each case, the compute or fix must generate local values for input to the :doc:`dump local ` diff --git a/doc/src/Howto_restart.rst b/doc/src/Howto_restart.rst index bc7a7502ae..6323ba4158 100644 --- a/doc/src/Howto_restart.rst +++ b/doc/src/Howto_restart.rst @@ -46,8 +46,8 @@ last 50 timesteps: run 50 Note that the following commands do not need to be repeated because -their settings are included in the restart file: *units, atom\_style, -special\_bonds, pair\_style, bond\_style*. However these commands do +their settings are included in the restart file: *units, atom_style, +special_bonds, pair_style, bond_style*. However these commands do need to be used, since their settings are not in the restart file: *neighbor, fix, timestep*\ . @@ -89,7 +89,7 @@ Then, this script could be used to re-run the last 50 steps: run 50 Note that nearly all the settings specified in the original *in.chain* -script must be repeated, except the *pair\_coeff* and *bond\_coeff* +script must be repeated, except the *pair_coeff* and *bond_coeff* commands since the new data file lists the force field coefficients. Also, the :doc:`reset_timestep ` command is used to tell LAMMPS the current timestep. This value is stored in restart files, diff --git a/doc/src/Howto_spherical.rst b/doc/src/Howto_spherical.rst index 886156c6cc..7ca8a1b060 100644 --- a/doc/src/Howto_spherical.rst +++ b/doc/src/Howto_spherical.rst @@ -115,7 +115,7 @@ such interactions. These are the various :doc:`pair styles ` that g * :doc:`pair_style gran/history ` * :doc:`pair_style gran/hertzian ` -* :doc:`pair_style gran/no\_history ` +* :doc:`pair_style gran/no_history ` * :doc:`pair_style dipole/cut ` * :doc:`pair_style gayberne ` * :doc:`pair_style resquared ` diff --git a/doc/src/Howto_triclinic.rst b/doc/src/Howto_triclinic.rst index ffe71e36f6..632d0364d5 100644 --- a/doc/src/Howto_triclinic.rst +++ b/doc/src/Howto_triclinic.rst @@ -221,7 +221,7 @@ calculated from the 9 triclinic box parameters zhi_bound = zhi These formulas can be inverted if you need to convert the bounding box -back into the triclinic box parameters, e.g. xlo = xlo\_bound - +back into the triclinic box parameters, e.g. xlo = xlo_bound - MIN(0.0,xy,xz,xy+xz). One use of triclinic simulation boxes is to model solid-state crystals diff --git a/doc/src/Install_linux.rst b/doc/src/Install_linux.rst index 0343ccf4f6..ec4f3fcc8e 100644 --- a/doc/src/Install_linux.rst +++ b/doc/src/Install_linux.rst @@ -38,7 +38,7 @@ To install LAMMPS do the following once: $ sudo apt-get install lammps-daily -This downloads an executable named "lmp\_daily" to your box, which +This downloads an executable named "lmp_daily" to your box, which can then be used in the usual way to run input scripts: .. code-block:: bash @@ -103,10 +103,10 @@ linking to the C library interface (lammps-devel, lammps-mpich-devel, lammps-openmpi-devel), the header for compiling programs using the C library interface (lammps-headers), and the LAMMPS python module for Python 3. All packages can be installed at the same -time and the name of the LAMMPS executable is *lmp* and *lmp\_openmpi* -or *lmp\_mpich* respectively. By default, *lmp* will refer to the +time and the name of the LAMMPS executable is *lmp* and *lmp_openmpi* +or *lmp_mpich* respectively. By default, *lmp* will refer to the serial executable, unless one of the MPI environment modules is loaded -("module load mpi/mpich-x86\_64" or "module load mpi/openmpi-x86\_64"). +("module load mpi/mpich-x86_64" or "module load mpi/openmpi-x86_64"). Then the corresponding parallel LAMMPS executable can be used. The same mechanism applies when loading the LAMMPS python module. diff --git a/doc/src/Install_mac.rst b/doc/src/Install_mac.rst index f1cee0dac5..41b53c0595 100644 --- a/doc/src/Install_mac.rst +++ b/doc/src/Install_mac.rst @@ -14,7 +14,7 @@ the following commands: % brew install lammps -This will install the executables "lammps\_serial" and "lammps\_mpi", as well as +This will install the executables "lammps_serial" and "lammps_mpi", as well as the LAMMPS "doc", "potentials", "tools", "bench", and "examples" directories. Once LAMMPS is installed, you can test the installation with the diff --git a/doc/src/Install_windows.rst b/doc/src/Install_windows.rst index 32375264db..9a876eb732 100644 --- a/doc/src/Install_windows.rst +++ b/doc/src/Install_windows.rst @@ -26,7 +26,7 @@ When you download the installer package, you run it on your Windows machine. It will then prompt you with a dialog, where you can choose the installation directory, unpack and copy several executables, potential files, documentation pdfs, selected example files, etc. It -will then update a few system settings (e.g. PATH, LAMMPS\_POTENTIALS) +will then update a few system settings (e.g. PATH, LAMMPS_POTENTIALS) and add an entry into the Start Menu (with references to the documentation, LAMMPS homepage and more). From that menu, there is also a link to an uninstaller that removes the files and undoes the diff --git a/doc/src/Manual_build.rst b/doc/src/Manual_build.rst index dfb133a3e4..f87ce8bec2 100644 --- a/doc/src/Manual_build.rst +++ b/doc/src/Manual_build.rst @@ -28,8 +28,8 @@ and PDF files are not included. Instead you need to create them, in one of two ways: a. You can "fetch" the current HTML and PDF files from the LAMMPS web - site. Just type "make fetch". This should download a html\_www - directory and Manual\_www.pdf/Developer\_www.pdf files. Note that if + site. Just type "make fetch". This should download a html_www + directory and Manual_www.pdf/Developer_www.pdf files. Note that if new LAMMPS features have been added more recently than the date of your LAMMPS version, the fetched documentation will include those changes (but your source code will not, unless you update your local diff --git a/doc/src/Modify_atom.rst b/doc/src/Modify_atom.rst index 14bcb08ee2..f863da3157 100644 --- a/doc/src/Modify_atom.rst +++ b/doc/src/Modify_atom.rst @@ -8,78 +8,78 @@ style can be created if one of the existing atom styles does not define all the attributes you need to store and communicate with atoms. -Atom\_vec\_atomic.cpp is a simple example of an atom style. +Atom_vec_atomic.cpp is a simple example of an atom style. Here is a brief description of methods you define in your new derived -class. See atom\_vec.h for details. +class. See atom_vec.h for details. +-------------------------+--------------------------------------------------------------------------------+ | init | one time setup (optional) | +-------------------------+--------------------------------------------------------------------------------+ | grow | re-allocate atom arrays to longer lengths (required) | +-------------------------+--------------------------------------------------------------------------------+ -| grow\_reset | make array pointers in Atom and AtomVec classes consistent (required) | +| grow_reset | make array pointers in Atom and AtomVec classes consistent (required) | +-------------------------+--------------------------------------------------------------------------------+ | copy | copy info for one atom to another atom's array locations (required) | +-------------------------+--------------------------------------------------------------------------------+ -| pack\_comm | store an atom's info in a buffer communicated every timestep (required) | +| pack_comm | store an atom's info in a buffer communicated every timestep (required) | +-------------------------+--------------------------------------------------------------------------------+ -| pack\_comm\_vel | add velocity info to communication buffer (required) | +| pack_comm_vel | add velocity info to communication buffer (required) | +-------------------------+--------------------------------------------------------------------------------+ -| pack\_comm\_hybrid | store extra info unique to this atom style (optional) | +| pack_comm_hybrid | store extra info unique to this atom style (optional) | +-------------------------+--------------------------------------------------------------------------------+ -| unpack\_comm | retrieve an atom's info from the buffer (required) | +| unpack_comm | retrieve an atom's info from the buffer (required) | +-------------------------+--------------------------------------------------------------------------------+ -| unpack\_comm\_vel | also retrieve velocity info (required) | +| unpack_comm_vel | also retrieve velocity info (required) | +-------------------------+--------------------------------------------------------------------------------+ -| unpack\_comm\_hybrid | retrieve extra info unique to this atom style (optional) | +| unpack_comm_hybrid | retrieve extra info unique to this atom style (optional) | +-------------------------+--------------------------------------------------------------------------------+ -| pack\_reverse | store an atom's info in a buffer communicating partial forces (required) | +| pack_reverse | store an atom's info in a buffer communicating partial forces (required) | +-------------------------+--------------------------------------------------------------------------------+ -| pack\_reverse\_hybrid | store extra info unique to this atom style (optional) | +| pack_reverse_hybrid | store extra info unique to this atom style (optional) | +-------------------------+--------------------------------------------------------------------------------+ -| unpack\_reverse | retrieve an atom's info from the buffer (required) | +| unpack_reverse | retrieve an atom's info from the buffer (required) | +-------------------------+--------------------------------------------------------------------------------+ -| unpack\_reverse\_hybrid | retrieve extra info unique to this atom style (optional) | +| unpack_reverse_hybrid | retrieve extra info unique to this atom style (optional) | +-------------------------+--------------------------------------------------------------------------------+ -| pack\_border | store an atom's info in a buffer communicated on neighbor re-builds (required) | +| pack_border | store an atom's info in a buffer communicated on neighbor re-builds (required) | +-------------------------+--------------------------------------------------------------------------------+ -| pack\_border\_vel | add velocity info to buffer (required) | +| pack_border_vel | add velocity info to buffer (required) | +-------------------------+--------------------------------------------------------------------------------+ -| pack\_border\_hybrid | store extra info unique to this atom style (optional) | +| pack_border_hybrid | store extra info unique to this atom style (optional) | +-------------------------+--------------------------------------------------------------------------------+ -| unpack\_border | retrieve an atom's info from the buffer (required) | +| unpack_border | retrieve an atom's info from the buffer (required) | +-------------------------+--------------------------------------------------------------------------------+ -| unpack\_border\_vel | also retrieve velocity info (required) | +| unpack_border_vel | also retrieve velocity info (required) | +-------------------------+--------------------------------------------------------------------------------+ -| unpack\_border\_hybrid | retrieve extra info unique to this atom style (optional) | +| unpack_border_hybrid | retrieve extra info unique to this atom style (optional) | +-------------------------+--------------------------------------------------------------------------------+ -| pack\_exchange | store all an atom's info to migrate to another processor (required) | +| pack_exchange | store all an atom's info to migrate to another processor (required) | +-------------------------+--------------------------------------------------------------------------------+ -| unpack\_exchange | retrieve an atom's info from the buffer (required) | +| unpack_exchange | retrieve an atom's info from the buffer (required) | +-------------------------+--------------------------------------------------------------------------------+ -| size\_restart | number of restart quantities associated with proc's atoms (required) | +| size_restart | number of restart quantities associated with proc's atoms (required) | +-------------------------+--------------------------------------------------------------------------------+ -| pack\_restart | pack atom quantities into a buffer (required) | +| pack_restart | pack atom quantities into a buffer (required) | +-------------------------+--------------------------------------------------------------------------------+ -| unpack\_restart | unpack atom quantities from a buffer (required) | +| unpack_restart | unpack atom quantities from a buffer (required) | +-------------------------+--------------------------------------------------------------------------------+ -| create\_atom | create an individual atom of this style (required) | +| create_atom | create an individual atom of this style (required) | +-------------------------+--------------------------------------------------------------------------------+ -| data\_atom | parse an atom line from the data file (required) | +| data_atom | parse an atom line from the data file (required) | +-------------------------+--------------------------------------------------------------------------------+ -| data\_atom\_hybrid | parse additional atom info unique to this atom style (optional) | +| data_atom_hybrid | parse additional atom info unique to this atom style (optional) | +-------------------------+--------------------------------------------------------------------------------+ -| data\_vel | parse one line of velocity information from data file (optional) | +| data_vel | parse one line of velocity information from data file (optional) | +-------------------------+--------------------------------------------------------------------------------+ -| data\_vel\_hybrid | parse additional velocity data unique to this atom style (optional) | +| data_vel_hybrid | parse additional velocity data unique to this atom style (optional) | +-------------------------+--------------------------------------------------------------------------------+ -| memory\_usage | tally memory allocated by atom arrays (required) | +| memory_usage | tally memory allocated by atom arrays (required) | +-------------------------+--------------------------------------------------------------------------------+ The constructor of the derived class sets values for several variables that you must set when defining a new atom style, which are documented -in atom\_vec.h. New atom arrays are defined in atom.cpp. Search for +in atom_vec.h. New atom arrays are defined in atom.cpp. Search for the word "customize" and you will find locations you will need to modify. @@ -95,12 +95,12 @@ modify. New :doc:`pair styles `, :doc:`fixes `, or :doc:`computes ` can be added to LAMMPS, as discussed below. The code for these classes can use the per-atom properties defined by -fix property/atom. The Atom class has a find\_custom() method that is +fix property/atom. The Atom class has a find_custom() method that is useful in this context: -.. parsed-literal:: +.. code-block:: c++ - int index = atom->find_custom(char \*name, int &flag); + int index = atom->find_custom(char *name, int &flag); The "name" of a custom attribute, as specified in the :doc:`fix property/atom ` command, is checked to verify that it exists and its index is returned. The method also sets flag = @@ -108,10 +108,10 @@ that it exists and its index is returned. The method also sets flag = The vector of values associated with the attribute can then be accessed using the returned index as -.. parsed-literal:: +.. code-block:: c++ - int \*ivector = atom->ivector[index]; - double \*dvector = atom->dvector[index]; + int *ivector = atom->ivector[index]; + double *dvector = atom->dvector[index]; Ivector or dvector are vectors of length Nlocal = # of owned atoms, which store the attributes of individual atoms. diff --git a/doc/src/Modify_body.rst b/doc/src/Modify_body.rst index e469b8520f..b923416bdc 100644 --- a/doc/src/Modify_body.rst +++ b/doc/src/Modify_body.rst @@ -10,14 +10,14 @@ See the :doc:`Howto body ` doc page for an overview of using body particles and the various body styles LAMMPS supports. New styles can be created to add new kinds of body particles to LAMMPS. -Body\_nparticle.cpp is an example of a body particle that is treated as +Body_nparticle.cpp is an example of a body particle that is treated as a rigid body containing N sub-particles. Here is a brief description of methods you define in your new derived class. See body.h for details. +----------------------+-----------------------------------------------------------+ -| data\_body | process a line from the Bodies section of a data file | +| data_body | process a line from the Bodies section of a data file | +----------------------+-----------------------------------------------------------+ | noutrow | number of sub-particles output is generated for | +----------------------+-----------------------------------------------------------+ @@ -25,11 +25,11 @@ class. See body.h for details. +----------------------+-----------------------------------------------------------+ | output | output values for the Mth sub-particle | +----------------------+-----------------------------------------------------------+ -| pack\_comm\_body | body attributes to communicate every timestep | +| pack_comm_body | body attributes to communicate every timestep | +----------------------+-----------------------------------------------------------+ -| unpack\_comm\_body | unpacking of those attributes | +| unpack_comm_body | unpacking of those attributes | +----------------------+-----------------------------------------------------------+ -| pack\_border\_body | body attributes to communicate when reneighboring is done | +| pack_border_body | body attributes to communicate when reneighboring is done | +----------------------+-----------------------------------------------------------+ -| unpack\_border\_body | unpacking of those attributes | +| unpack_border_body | unpacking of those attributes | +----------------------+-----------------------------------------------------------+ diff --git a/doc/src/Modify_bond.rst b/doc/src/Modify_bond.rst index 06db272395..c2d220767e 100644 --- a/doc/src/Modify_bond.rst +++ b/doc/src/Modify_bond.rst @@ -5,7 +5,7 @@ Classes that compute molecular interactions are derived from the Bond, Angle, Dihedral, and Improper classes. New styles can be created to add new potentials to LAMMPS. -Bond\_harmonic.cpp is the simplest example of a bond style. Ditto for +Bond_harmonic.cpp is the simplest example of a bond style. Ditto for the harmonic forms of the angle, dihedral, and improper style commands. @@ -14,9 +14,9 @@ new derived class. See bond.h, angle.h, dihedral.h, and improper.h for details and specific additional methods. +-----------------------+---------------------------------------------------------------------------+ -| init | check if all coefficients are set, calls *init\_style* (optional) | +| init | check if all coefficients are set, calls *init_style* (optional) | +-----------------------+---------------------------------------------------------------------------+ -| init\_style | check if style specific conditions are met (optional) | +| init_style | check if style specific conditions are met (optional) | +-----------------------+---------------------------------------------------------------------------+ | compute | compute the molecular interactions (required) | +-----------------------+---------------------------------------------------------------------------+ @@ -24,13 +24,13 @@ for details and specific additional methods. +-----------------------+---------------------------------------------------------------------------+ | coeff | set coefficients for one type (required) | +-----------------------+---------------------------------------------------------------------------+ -| equilibrium\_distance | length of bond, used by SHAKE (required, bond only) | +| equilibrium_distance | length of bond, used by SHAKE (required, bond only) | +-----------------------+---------------------------------------------------------------------------+ -| equilibrium\_angle | opening of angle, used by SHAKE (required, angle only) | +| equilibrium_angle | opening of angle, used by SHAKE (required, angle only) | +-----------------------+---------------------------------------------------------------------------+ -| write & read\_restart | writes/reads coeffs to restart files (required) | +| write & read_restart | writes/reads coeffs to restart files (required) | +-----------------------+---------------------------------------------------------------------------+ | single | force and energy of a single bond or angle (required, bond or angle only) | +-----------------------+---------------------------------------------------------------------------+ -| memory\_usage | tally memory allocated by the style (optional) | +| memory_usage | tally memory allocated by the style (optional) | +-----------------------+---------------------------------------------------------------------------+ diff --git a/doc/src/Modify_command.rst b/doc/src/Modify_command.rst index 37e1b2c490..2d0a1d99d9 100644 --- a/doc/src/Modify_command.rst +++ b/doc/src/Modify_command.rst @@ -2,8 +2,8 @@ Input script command style ========================== New commands can be added to LAMMPS input scripts by adding new -classes that have a "command" method. For example, the create\_atoms, -read\_data, velocity, and run commands are all implemented in this +classes that have a "command" method. For example, the create_atoms, +read_data, velocity, and run commands are all implemented in this fashion. When such a command is encountered in the LAMMPS input script, LAMMPS simply creates a class with the corresponding name, invokes the "command" method of the class, and passes it the arguments diff --git a/doc/src/Modify_compute.rst b/doc/src/Modify_compute.rst index b32350e048..8fad775b3a 100644 --- a/doc/src/Modify_compute.rst +++ b/doc/src/Modify_compute.rst @@ -7,8 +7,8 @@ quantities like kinetic energy and the centro-symmetry parameter are derived from the Compute class. New styles can be created to add new calculations to LAMMPS. -Compute\_temp.cpp is a simple example of computing a scalar -temperature. Compute\_ke\_atom.cpp is a simple example of computing +Compute_temp.cpp is a simple example of computing a scalar +temperature. Compute_ke_atom.cpp is a simple example of computing per-atom kinetic energy. Here is a brief description of methods you define in your new derived @@ -17,41 +17,41 @@ class. See compute.h for details. +-----------------------+------------------------------------------------------------------+ | init | perform one time setup (required) | +-----------------------+------------------------------------------------------------------+ -| init\_list | neighbor list setup, if needed (optional) | +| init_list | neighbor list setup, if needed (optional) | +-----------------------+------------------------------------------------------------------+ -| compute\_scalar | compute a scalar quantity (optional) | +| compute_scalar | compute a scalar quantity (optional) | +-----------------------+------------------------------------------------------------------+ -| compute\_vector | compute a vector of quantities (optional) | +| compute_vector | compute a vector of quantities (optional) | +-----------------------+------------------------------------------------------------------+ -| compute\_peratom | compute one or more quantities per atom (optional) | +| compute_peratom | compute one or more quantities per atom (optional) | +-----------------------+------------------------------------------------------------------+ -| compute\_local | compute one or more quantities per processor (optional) | +| compute_local | compute one or more quantities per processor (optional) | +-----------------------+------------------------------------------------------------------+ -| pack\_comm | pack a buffer with items to communicate (optional) | +| pack_comm | pack a buffer with items to communicate (optional) | +-----------------------+------------------------------------------------------------------+ -| unpack\_comm | unpack the buffer (optional) | +| unpack_comm | unpack the buffer (optional) | +-----------------------+------------------------------------------------------------------+ -| pack\_reverse | pack a buffer with items to reverse communicate (optional) | +| pack_reverse | pack a buffer with items to reverse communicate (optional) | +-----------------------+------------------------------------------------------------------+ -| unpack\_reverse | unpack the buffer (optional) | +| unpack_reverse | unpack the buffer (optional) | +-----------------------+------------------------------------------------------------------+ -| remove\_bias | remove velocity bias from one atom (optional) | +| remove_bias | remove velocity bias from one atom (optional) | +-----------------------+------------------------------------------------------------------+ -| remove\_bias\_all | remove velocity bias from all atoms in group (optional) | +| remove_bias_all | remove velocity bias from all atoms in group (optional) | +-----------------------+------------------------------------------------------------------+ -| restore\_bias | restore velocity bias for one atom after remove\_bias (optional) | +| restore_bias | restore velocity bias for one atom after remove_bias (optional) | +-----------------------+------------------------------------------------------------------+ -| restore\_bias\_all | same as before, but for all atoms in group (optional) | +| restore_bias_all | same as before, but for all atoms in group (optional) | +-----------------------+------------------------------------------------------------------+ -| pair\_tally\_callback | callback function for *tally*\ -style computes (optional). | +| pair_tally_callback | callback function for *tally*\ -style computes (optional). | +-----------------------+------------------------------------------------------------------+ -| memory\_usage | tally memory usage (optional) | +| memory_usage | tally memory usage (optional) | +-----------------------+------------------------------------------------------------------+ Tally-style computes are a special case, as their computation is done in two stages: the callback function is registered with the pair style -and then called from the Pair::ev\_tally() function, which is called for +and then called from the Pair::ev_tally() function, which is called for each pair after force and energy has been computed for this pair. Then -the tallied values are retrieved with the standard compute\_scalar or -compute\_vector or compute\_peratom methods. The USER-TALLY package -provides *examples*\ \_compute\_tally.html for utilizing this mechanism. +the tallied values are retrieved with the standard compute_scalar or +compute_vector or compute_peratom methods. The USER-TALLY package +provides *examples*\ _compute_tally.html for utilizing this mechanism. diff --git a/doc/src/Modify_contribute.rst b/doc/src/Modify_contribute.rst index 358861c720..ed2ef783f4 100644 --- a/doc/src/Modify_contribute.rst +++ b/doc/src/Modify_contribute.rst @@ -90,8 +90,8 @@ packages in the src directory for examples. If you are uncertain, please ask. * All source files you provide must compile with the most current version of LAMMPS with multiple configurations. In particular you - need to test compiling LAMMPS from scratch with -DLAMMPS\_BIGBIG - set in addition to the default -DLAMMPS\_SMALLBIG setting. Your code + need to test compiling LAMMPS from scratch with -DLAMMPS_BIGBIG + set in addition to the default -DLAMMPS_SMALLBIG setting. Your code will need to work correctly in serial and in parallel using MPI. * For consistency with the rest of LAMMPS and especially, if you want @@ -106,7 +106,7 @@ packages in the src directory for examples. If you are uncertain, please ask. (, , or ) instead of the C-style names , , or ), and forward declarations used where possible or needed to avoid including headers. - All added code should be placed into the LAMMPS\_NS namespace or a + All added code should be placed into the LAMMPS_NS namespace or a sub-namespace; global or static variables should be avoided, as they conflict with the modular nature of LAMMPS and the C++ class structure. Header files must **not** import namespaces with *using*\ . @@ -164,7 +164,7 @@ packages in the src directory for examples. If you are uncertain, please ask. mathematical expression or figures (see doc/JPG for examples). Additional PDF files with further details (see doc/PDF for examples) may also be included. The doc page should also include literature - citations as appropriate; see the bottom of doc/fix\_nh.rst for + citations as appropriate; see the bottom of doc/fix_nh.rst for examples and the earlier part of the same file for how to format the cite itself. Citation labels must be unique across all .rst files. The "Restrictions" section of the doc page should indicate if your @@ -191,7 +191,7 @@ packages in the src directory for examples. If you are uncertain, please ask. * If there is a paper of yours describing your feature (either the algorithm/science behind the feature itself, or its initial usage, or its implementation in LAMMPS), you can add the citation to the \*.cpp - source file. See src/USER-EFF/atom\_vec\_electron.cpp for an example. + source file. See src/USER-EFF/atom_vec_electron.cpp for an example. A LaTeX citation is stored in a variable at the top of the file and a single line of code that references the variable is added to the constructor of the class. Whenever a user invokes your feature from diff --git a/doc/src/Modify_dump.rst b/doc/src/Modify_dump.rst index 8d98f848d2..1379326d1e 100644 --- a/doc/src/Modify_dump.rst +++ b/doc/src/Modify_dump.rst @@ -4,21 +4,21 @@ Dump styles Classes that dump per-atom info to files are derived from the Dump class. To dump new quantities or in a new format, a new derived dump class can be added, but it is typically simpler to modify the -DumpCustom class contained in the dump\_custom.cpp file. +DumpCustom class contained in the dump_custom.cpp file. -Dump\_atom.cpp is a simple example of a derived dump class. +Dump_atom.cpp is a simple example of a derived dump class. Here is a brief description of methods you define in your new derived class. See dump.h for details. +---------------+---------------------------------------------------+ -| write\_header | write the header section of a snapshot of atoms | +| write_header | write the header section of a snapshot of atoms | +---------------+---------------------------------------------------+ | count | count the number of lines a processor will output | +---------------+---------------------------------------------------+ | pack | pack a proc's output data into a buffer | +---------------+---------------------------------------------------+ -| write\_data | write a proc's data to a file | +| write_data | write a proc's data to a file | +---------------+---------------------------------------------------+ See the :doc:`dump ` command and its *custom* style for a list of diff --git a/doc/src/Modify_fix.rst b/doc/src/Modify_fix.rst index 9e1705e435..9a97e30fbe 100644 --- a/doc/src/Modify_fix.rst +++ b/doc/src/Modify_fix.rst @@ -10,7 +10,7 @@ constraints or boundary conditions (SHAKE or walls), and diagnostics (compute a diffusion coefficient). New styles can be created to add new options to LAMMPS. -Fix\_setforce.cpp is a simple example of setting forces on atoms to +Fix_setforce.cpp is a simple example of setting forces on atoms to prescribed values. There are dozens of fix options already in LAMMPS; choose one as a template that is similar to what you want to implement. @@ -23,105 +23,105 @@ derived class. See fix.h for details. +---------------------------+--------------------------------------------------------------------------------------------+ | init | initialization before a run (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| setup\_pre\_exchange | called before atom exchange in setup (optional) | +| setup_pre_exchange | called before atom exchange in setup (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| setup\_pre\_force | called before force computation in setup (optional) | +| setup_pre_force | called before force computation in setup (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ | setup | called immediately before the 1st timestep and after forces are computed (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| min\_setup\_pre\_force | like setup\_pre\_force, but for minimizations instead of MD runs (optional) | +| min_setup_pre_force | like setup_pre_force, but for minimizations instead of MD runs (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| min\_setup | like setup, but for minimizations instead of MD runs (optional) | +| min_setup | like setup, but for minimizations instead of MD runs (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| initial\_integrate | called at very beginning of each timestep (optional) | +| initial_integrate | called at very beginning of each timestep (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| pre\_exchange | called before atom exchange on re-neighboring steps (optional) | +| pre_exchange | called before atom exchange on re-neighboring steps (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| pre\_neighbor | called before neighbor list build (optional) | +| pre_neighbor | called before neighbor list build (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| pre\_force | called before pair & molecular forces are computed (optional) | +| pre_force | called before pair & molecular forces are computed (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| post\_force | called after pair & molecular forces are computed and communicated (optional) | +| post_force | called after pair & molecular forces are computed and communicated (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| final\_integrate | called at end of each timestep (optional) | +| final_integrate | called at end of each timestep (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| end\_of\_step | called at very end of timestep (optional) | +| end_of_step | called at very end of timestep (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| write\_restart | dumps fix info to restart file (optional) | +| write_restart | dumps fix info to restart file (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ | restart | uses info from restart file to re-initialize the fix (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| grow\_arrays | allocate memory for atom-based arrays used by fix (optional) | +| grow_arrays | allocate memory for atom-based arrays used by fix (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| copy\_arrays | copy atom info when an atom migrates to a new processor (optional) | +| copy_arrays | copy atom info when an atom migrates to a new processor (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| pack\_exchange | store atom's data in a buffer (optional) | +| pack_exchange | store atom's data in a buffer (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| unpack\_exchange | retrieve atom's data from a buffer (optional) | +| unpack_exchange | retrieve atom's data from a buffer (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| pack\_restart | store atom's data for writing to restart file (optional) | +| pack_restart | store atom's data for writing to restart file (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| unpack\_restart | retrieve atom's data from a restart file buffer (optional) | +| unpack_restart | retrieve atom's data from a restart file buffer (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| size\_restart | size of atom's data (optional) | +| size_restart | size of atom's data (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| maxsize\_restart | max size of atom's data (optional) | +| maxsize_restart | max size of atom's data (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| setup\_pre\_force\_respa | same as setup\_pre\_force, but for rRESPA (optional) | +| setup_pre_force_respa | same as setup_pre_force, but for rRESPA (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| initial\_integrate\_respa | same as initial\_integrate, but for rRESPA (optional) | +| initial_integrate_respa | same as initial_integrate, but for rRESPA (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| post\_integrate\_respa | called after the first half integration step is done in rRESPA (optional) | +| post_integrate_respa | called after the first half integration step is done in rRESPA (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| pre\_force\_respa | same as pre\_force, but for rRESPA (optional) | +| pre_force_respa | same as pre_force, but for rRESPA (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| post\_force\_respa | same as post\_force, but for rRESPA (optional) | +| post_force_respa | same as post_force, but for rRESPA (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| final\_integrate\_respa | same as final\_integrate, but for rRESPA (optional) | +| final_integrate_respa | same as final_integrate, but for rRESPA (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| min\_pre\_force | called after pair & molecular forces are computed in minimizer (optional) | +| min_pre_force | called after pair & molecular forces are computed in minimizer (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| min\_post\_force | called after pair & molecular forces are computed and communicated in minimizer (optional) | +| min_post_force | called after pair & molecular forces are computed and communicated in minimizer (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| min\_store | store extra data for linesearch based minimization on a LIFO stack (optional) | +| min_store | store extra data for linesearch based minimization on a LIFO stack (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| min\_pushstore | push the minimization LIFO stack one element down (optional) | +| min_pushstore | push the minimization LIFO stack one element down (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| min\_popstore | pop the minimization LIFO stack one element up (optional) | +| min_popstore | pop the minimization LIFO stack one element up (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| min\_clearstore | clear minimization LIFO stack (optional) | +| min_clearstore | clear minimization LIFO stack (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| min\_step | reset or move forward on line search minimization (optional) | +| min_step | reset or move forward on line search minimization (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| min\_dof | report number of degrees of freedom *added* by this fix in minimization (optional) | +| min_dof | report number of degrees of freedom *added* by this fix in minimization (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| max\_alpha | report maximum allowed step size during linesearch minimization (optional) | +| max_alpha | report maximum allowed step size during linesearch minimization (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| pack\_comm | pack a buffer to communicate a per-atom quantity (optional) | +| pack_comm | pack a buffer to communicate a per-atom quantity (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| unpack\_comm | unpack a buffer to communicate a per-atom quantity (optional) | +| unpack_comm | unpack a buffer to communicate a per-atom quantity (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| pack\_reverse\_comm | pack a buffer to reverse communicate a per-atom quantity (optional) | +| pack_reverse_comm | pack a buffer to reverse communicate a per-atom quantity (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| unpack\_reverse\_comm | unpack a buffer to reverse communicate a per-atom quantity (optional) | +| unpack_reverse_comm | unpack a buffer to reverse communicate a per-atom quantity (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ | dof | report number of degrees of freedom *removed* by this fix during MD (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| compute\_scalar | return a global scalar property that the fix computes (optional) | +| compute_scalar | return a global scalar property that the fix computes (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| compute\_vector | return a component of a vector property that the fix computes (optional) | +| compute_vector | return a component of a vector property that the fix computes (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| compute\_array | return a component of an array property that the fix computes (optional) | +| compute_array | return a component of an array property that the fix computes (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ | deform | called when the box size is changed (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| reset\_target | called when a change of the target temperature is requested during a run (optional) | +| reset_target | called when a change of the target temperature is requested during a run (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| reset\_dt | is called when a change of the time step is requested during a run (optional) | +| reset_dt | is called when a change of the time step is requested during a run (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| modify\_param | called when a fix\_modify request is executed (optional) | +| modify_param | called when a fix_modify request is executed (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ -| memory\_usage | report memory used by fix (optional) | +| memory_usage | report memory used by fix (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ | thermo | compute quantities for thermodynamic output (optional) | +---------------------------+--------------------------------------------------------------------------------------------+ @@ -129,12 +129,12 @@ derived class. See fix.h for details. Typically, only a small fraction of these methods are defined for a particular fix. Setmask is mandatory, as it determines when the fix will be invoked during the timestep. Fixes that perform time -integration (\ *nve*\ , *nvt*\ , *npt*\ ) implement initial\_integrate() and -final\_integrate() to perform velocity Verlet updates. Fixes that -constrain forces implement post\_force(). +integration (\ *nve*\ , *nvt*\ , *npt*\ ) implement initial_integrate() and +final_integrate() to perform velocity Verlet updates. Fixes that +constrain forces implement post_force(). -Fixes that perform diagnostics typically implement end\_of\_step(). For -an end\_of\_step fix, one of your fix arguments must be the variable +Fixes that perform diagnostics typically implement end_of_step(). For +an end_of_step fix, one of your fix arguments must be the variable "nevery" which is used to determine when to call the fix and you must set this variable in the constructor of your fix. By convention, this is the first argument the fix defines (after the ID, group-ID, style). @@ -142,12 +142,12 @@ is the first argument the fix defines (after the ID, group-ID, style). If the fix needs to store information for each atom that persists from timestep to timestep, it can manage that memory and migrate the info with the atoms as they move from processors to processor by -implementing the grow\_arrays, copy\_arrays, pack\_exchange, and -unpack\_exchange methods. Similarly, the pack\_restart and -unpack\_restart methods can be implemented to store information about +implementing the grow_arrays, copy_arrays, pack_exchange, and +unpack_exchange methods. Similarly, the pack_restart and +unpack_restart methods can be implemented to store information about the fix in restart files. If you wish an integrator or force constraint fix to work with rRESPA (see the :doc:`run_style ` -command), the initial\_integrate, post\_force\_integrate, and -final\_integrate\_respa methods can be implemented. The thermo method +command), the initial_integrate, post_force_integrate, and +final_integrate_respa methods can be implemented. The thermo method enables a fix to contribute values to thermodynamic output, as printed quantities and/or to be summed to the potential energy of the system. diff --git a/doc/src/Modify_kspace.rst b/doc/src/Modify_kspace.rst index c45c8f94a1..e1b10eac8d 100644 --- a/doc/src/Modify_kspace.rst +++ b/doc/src/Modify_kspace.rst @@ -17,5 +17,5 @@ class. See kspace.h for details. +---------------+----------------------------------------------+ | compute | every-timestep computation | +---------------+----------------------------------------------+ -| memory\_usage | tally of memory usage | +| memory_usage | tally of memory usage | +---------------+----------------------------------------------+ diff --git a/doc/src/Modify_min.rst b/doc/src/Modify_min.rst index d8bcd2d3f2..ed7c101a6c 100644 --- a/doc/src/Modify_min.rst +++ b/doc/src/Modify_min.rst @@ -5,7 +5,7 @@ Classes that perform energy minimization derived from the Min class. New styles can be created to add new minimization algorithms to LAMMPS. -Min\_cg.cpp is an example of conjugate gradient minimization. +Min_cg.cpp is an example of conjugate gradient minimization. Here is a brief description of methods you define in your new derived class. See min.h for details. @@ -15,5 +15,5 @@ class. See min.h for details. +---------------+------------------------------------------+ | run | perform the minimization | +---------------+------------------------------------------+ -| memory\_usage | tally of memory usage | +| memory_usage | tally of memory usage | +---------------+------------------------------------------+ diff --git a/doc/src/Modify_overview.rst b/doc/src/Modify_overview.rst index 1bbcf8e120..2deceae7db 100644 --- a/doc/src/Modify_overview.rst +++ b/doc/src/Modify_overview.rst @@ -25,8 +25,8 @@ and variables needed to define the new feature are in the 2 files you write, and thus shouldn't make the rest of LAMMPS more complex or cause side-effect bugs. -Here is a concrete example. Suppose you write 2 files pair\_foo.cpp -and pair\_foo.h that define a new class PairFoo that computes pairwise +Here is a concrete example. Suppose you write 2 files pair_foo.cpp +and pair_foo.h that define a new class PairFoo that computes pairwise potentials described in the classic 1997 :ref:`paper ` by Foo, et al. If you wish to invoke those potentials in a LAMMPS input script with a command like @@ -35,7 +35,7 @@ command like pair_style foo 0.1 3.5 -then your pair\_foo.h file should be structured as follows: +then your pair_foo.h file should be structured as follows: .. code-block:: c++ @@ -47,12 +47,12 @@ then your pair\_foo.h file should be structured as follows: ... #endif -where "foo" is the style keyword in the pair\_style command, and -PairFoo is the class name defined in your pair\_foo.cpp and pair\_foo.h +where "foo" is the style keyword in the pair_style command, and +PairFoo is the class name defined in your pair_foo.cpp and pair_foo.h files. When you re-build LAMMPS, your new pairwise potential becomes part of -the executable and can be invoked with a pair\_style command like the +the executable and can be invoked with a pair_style command like the example above. Arguments like 0.1 and 3.5 can be defined and processed by your new class. @@ -80,7 +80,7 @@ that are not set to 0 are functions you may override or not. Those are usually defined with an empty function body. Additionally, new output options can be added directly to the -thermo.cpp, dump\_custom.cpp, and variable.cpp files. These are also +thermo.cpp, dump_custom.cpp, and variable.cpp files. These are also listed on the :doc:`Modify page `. Here are additional guidelines for modifying LAMMPS and adding new diff --git a/doc/src/Modify_pair.rst b/doc/src/Modify_pair.rst index 78ee144d53..7263b8fd48 100644 --- a/doc/src/Modify_pair.rst +++ b/doc/src/Modify_pair.rst @@ -7,7 +7,7 @@ such as EAM or Tersoff where particles interact without a static bond topology. New styles can be created to add new pair potentials to LAMMPS. -Pair\_lj\_cut.cpp is a simple example of a Pair class, though it +Pair_lj_cut.cpp is a simple example of a Pair class, though it includes some optional methods to enable its use with rRESPA. Here is a brief description of the class methods in pair.h: @@ -19,17 +19,17 @@ Here is a brief description of the class methods in pair.h: +---------------------------------+-------------------------------------------------------------------+ | coeff | set coefficients for one i,j type pair | +---------------------------------+-------------------------------------------------------------------+ -| init\_one | perform initialization for one i,j type pair | +| init_one | perform initialization for one i,j type pair | +---------------------------------+-------------------------------------------------------------------+ -| init\_style | initialization specific to this pair style | +| init_style | initialization specific to this pair style | +---------------------------------+-------------------------------------------------------------------+ -| write & read\_restart | write/read i,j pair coeffs to restart files | +| write & read_restart | write/read i,j pair coeffs to restart files | +---------------------------------+-------------------------------------------------------------------+ -| write & read\_restart\_settings | write/read global settings to restart files | +| write & read_restart_settings | write/read global settings to restart files | +---------------------------------+-------------------------------------------------------------------+ | single | force and energy of a single pairwise interaction between 2 atoms | +---------------------------------+-------------------------------------------------------------------+ -| compute\_inner/middle/outer | versions of compute used by rRESPA | +| compute_inner/middle/outer | versions of compute used by rRESPA | +---------------------------------+-------------------------------------------------------------------+ The inner/middle/outer routines are optional. diff --git a/doc/src/Modify_region.rst b/doc/src/Modify_region.rst index a9e9c734a4..fa97df32c7 100644 --- a/doc/src/Modify_region.rst +++ b/doc/src/Modify_region.rst @@ -6,7 +6,7 @@ class. Regions are used elsewhere in LAMMPS to group atoms, delete atoms to create a void, insert atoms in a specified region, etc. New styles can be created to add new region shapes to LAMMPS. -Region\_sphere.cpp is an example of a spherical region. +Region_sphere.cpp is an example of a spherical region. Here is a brief description of methods you define in your new derived class. See region.h for details. @@ -14,9 +14,9 @@ class. See region.h for details. +-------------------+---------------------------------------------------------------------+ | inside | determine whether a point is in the region | +-------------------+---------------------------------------------------------------------+ -| surface\_interior | determine if a point is within a cutoff distance inside of surface | +| surface_interior | determine if a point is within a cutoff distance inside of surface | +-------------------+---------------------------------------------------------------------+ -| surface\_exterior | determine if a point is within a cutoff distance outside of surface | +| surface_exterior | determine if a point is within a cutoff distance outside of surface | +-------------------+---------------------------------------------------------------------+ -| shape\_update | change region shape if set by time-dependent variable | +| shape_update | change region shape if set by time-dependent variable | +-------------------+---------------------------------------------------------------------+ diff --git a/doc/src/Packages_details.rst b/doc/src/Packages_details.rst index f60fc1c11b..e20c2886ed 100644 --- a/doc/src/Packages_details.rst +++ b/doc/src/Packages_details.rst @@ -10,7 +10,7 @@ scripts, and pictures/movies (if available) that illustrate use of the package. The majority of packages can be included in a LAMMPS build with a -single setting (-D PGK\_NAME for CMake) or command ("make yes-name" for +single setting (-D PGK_NAME for CMake) or command ("make yes-name" for make). See the :doc:`Build package ` doc page for more info. A few packages may require additional steps; this is indicated in the descriptions below. The :doc:`Build extras ` doc @@ -123,8 +123,8 @@ particle models including ellipsoids, 2d lines, and 3d triangles. * :doc:`Howto spherical ` * :doc:`pair_style gayberne ` * :doc:`pair_style resquared ` -* `doc/PDF/pair\_gayberne\_extra.pdf `_ -* `doc/PDF/pair\_resquared\_extra.pdf `_ +* `doc/PDF/pair_gayberne_extra.pdf `_ +* `doc/PDF/pair_resquared_extra.pdf `_ * examples/ASPHERE * examples/ellipse * https://lammps.sandia.gov/movies.html#line @@ -147,7 +147,7 @@ overview. **Supporting info:** * src/BODY filenames -> commands -* :doc:`Howto\_body ` +* :doc:`Howto_body ` * :doc:`atom_style body ` * :doc:`fix nve/body ` * :doc:`pair_style body/nparticle ` @@ -367,7 +367,7 @@ This package contains a set of commands that serve as a wrapper on the `Open Knowledgebase of Interatomic Models (OpenKIM) `_ repository of interatomic models (IMs) enabling compatible ones to be used in LAMMPS simulations. -This includes :doc:`kim_init and kim\_interactions ` +This includes :doc:`kim_init and kim_interactions ` commands to select, initialize and instantiate the IM, and a :doc:`kim_query ` command to perform web queries for material property predictions of OpenKIM IMs. @@ -377,7 +377,7 @@ is provided by the :doc:`pair_style kim ` command. .. note:: - The command *pair\_style kim* is called by *kim\_interactions* and + The command *pair_style kim* is called by *kim_interactions* and is not recommended to be directly used in input scripts. To use this package you must have the KIM API library available on your @@ -392,7 +392,7 @@ The KIM project is led by Ellad Tadmor and Ryan Elliott (U Minnesota) and is funded by the `National Science Foundation `_. **Authors:** Ryan Elliott (U Minnesota) is the main developer for the KIM -API and the *pair\_style kim* command. Axel Kohlmeyer (Temple U) and +API and the *pair_style kim* command. Axel Kohlmeyer (Temple U) and Ellad Tadmor (U Minnesota) contributed to the :doc:`kim_commands ` interface in close collaboration with Ryan Elliott. @@ -782,9 +782,9 @@ Foster (UTSA). **Supporting info:** * src/PERI: filenames -> commands -* `doc/PDF/PDLammps\_overview.pdf `_ -* `doc/PDF/PDLammps\_EPS.pdf `_ -* `doc/PDF/PDLammps\_VES.pdf `_ +* `doc/PDF/PDLammps_overview.pdf `_ +* `doc/PDF/PDLammps_EPS.pdf `_ +* `doc/PDF/PDLammps_VES.pdf `_ * :doc:`atom_style peri ` * :doc:`pair_style peri/\* ` * :doc:`compute damage/atom ` @@ -1890,7 +1890,7 @@ And a :doc:`dynamical_matrix ` as well as a and third order tensor from finite differences. **Authors:** Ling-Ti Kong (Shanghai Jiao Tong University) for "fix phonon" -and Charlie Sievers (UC Davis) for "dynamical\_matrix" and "third\_order" +and Charlie Sievers (UC Davis) for "dynamical_matrix" and "third_order" **Supporting info:** @@ -1918,8 +1918,8 @@ Matching methodology. **Supporting info:** -* src/USER-PTM: filenames not starting with ptm\\_ -> commands -* src/USER-PTM: filenames starting with ptm\\_ -> supporting code +* src/USER-PTM: filenames not starting with ptm\_ -> commands +* src/USER-PTM: filenames starting with ptm\_ -> supporting code * src/USER-PTM/LICENSE * :doc:`compute ptm/atom ` @@ -2132,7 +2132,7 @@ is an extension of smoothed particle hydrodynamics (SPH) to mesoscale where thermal fluctuations are important (see the :ref:`USER-SPH package `). Also two fixes for moving and rigid body integration of SPH/SDPD particles -(particles of atom\_style meso). +(particles of atom_style meso). **Author:** Morteza Jalalvand (Institute for Advanced Studies in Basic Sciences, Iran). @@ -2180,7 +2180,7 @@ This package has :ref:`specific installation instructions ` on the :do * src/USER-SMD: filenames -> commands * src/USER-SMD/README -* doc/PDF/SMD\_LAMMPS\_userguide.pdf +* doc/PDF/SMD_LAMMPS_userguide.pdf * examples/USER/smd * https://lammps.sandia.gov/movies.html#smd @@ -2237,7 +2237,7 @@ Dynamics, Ernst Mach Institute, Germany). * src/USER-SPH: filenames -> commands * src/USER-SPH/README -* doc/PDF/SPH\_LAMMPS\_userguide.pdf +* doc/PDF/SPH_LAMMPS_userguide.pdf * examples/USER/sph * https://lammps.sandia.gov/movies.html#sph diff --git a/doc/src/Python_examples.rst b/doc/src/Python_examples.rst index 0bfee9caf5..c3b0381e64 100644 --- a/doc/src/Python_examples.rst +++ b/doc/src/Python_examples.rst @@ -20,16 +20,16 @@ distribution. +----------------------------------------------------------------+--------------------------------------------------+ | GUI go/stop/temperature-slider to control LAMMPS | plot.py | +----------------------------------------------------------------+--------------------------------------------------+ -| real-time temperature plot with GnuPlot via Pizza.py | viz\_tool.py | +| real-time temperature plot with GnuPlot via Pizza.py | viz_tool.py | +----------------------------------------------------------------+--------------------------------------------------+ -| real-time viz via some viz package | vizplotgui\_tool.py | +| real-time viz via some viz package | vizplotgui_tool.py | +----------------------------------------------------------------+--------------------------------------------------+ -| combination of viz\_tool.py and plot.py and gui.py | | +| combination of viz_tool.py and plot.py and gui.py | | +----------------------------------------------------------------+--------------------------------------------------+ ---------- -For the viz\_tool.py and vizplotgui\_tool.py commands, replace "tool" +For the viz_tool.py and vizplotgui_tool.py commands, replace "tool" with "gl" or "atomeye" or "pymol" or "vmd", depending on what visualization package you have installed. @@ -79,7 +79,7 @@ variables that have to match the VMD installation on your system. See the python/README file for instructions on how to run them and the source code for individual scripts for comments about what they do. -Here are screenshots of the vizplotgui\_tool.py script in action for +Here are screenshots of the vizplotgui_tool.py script in action for different visualization package options. Click to see larger images: .. image:: JPG/screenshot_gl_small.jpg diff --git a/doc/src/Python_head.rst b/doc/src/Python_head.rst index 0a58ecdde1..fc808489a5 100644 --- a/doc/src/Python_head.rst +++ b/doc/src/Python_head.rst @@ -27,7 +27,7 @@ its library interface, or to hook multiple pieces of software together, such as a simulation code plus a visualization tool, or to run a coupled multiscale or multiphysics model. -See the :doc:`Howto\_couple ` doc page for more ideas about +See the :doc:`Howto_couple ` doc page for more ideas about coupling LAMMPS to other codes. See the :doc:`Howto library ` doc page for a description of the LAMMPS library interface provided in src/library.h and src/library.h. That interface is exposed to Python either when calling LAMMPS from Python diff --git a/doc/src/Python_install.rst b/doc/src/Python_install.rst index 04e3660c52..aaeece7752 100644 --- a/doc/src/Python_install.rst +++ b/doc/src/Python_install.rst @@ -36,7 +36,7 @@ this to your ~/.cshrc file, one line for each of the two files: setenv PYTHONPATH ${PYTHONPATH}:/home/sjplimp/lammps/python setenv LD_LIBRARY_PATH ${LD_LIBRARY_PATH}:/home/sjplimp/lammps/src -On MacOSX you may also need to set DYLD\_LIBRARY\_PATH accordingly. +On MacOSX you may also need to set DYLD_LIBRARY_PATH accordingly. For Bourne/Korn shells accordingly into the corresponding files using the "export" shell builtin. @@ -58,11 +58,11 @@ you can invoke install.py from the python directory manually as * and the optional -d flag to a custom (legacy) installation folder If you use a legacy installation folder, you will need to set your -PYTHONPATH and LD\_LIBRARY\_PATH (and/or DYLD\_LIBRARY\_PATH) environment +PYTHONPATH and LD_LIBRARY_PATH (and/or DYLD_LIBRARY_PATH) environment variables accordingly, as described above. Note that if you want Python to be able to load different versions of the LAMMPS shared library (see :doc:`this section `), you will -need to manually copy files like liblammps\_g++.so into the appropriate -system directory. This is not needed if you set the LD\_LIBRARY\_PATH +need to manually copy files like liblammps_g++.so into the appropriate +system directory. This is not needed if you set the LD_LIBRARY_PATH environment variable as described above. diff --git a/doc/src/Python_library.rst b/doc/src/Python_library.rst index 0d3767170f..2100074c4e 100644 --- a/doc/src/Python_library.rst +++ b/doc/src/Python_library.rst @@ -135,21 +135,21 @@ script, and coordinate and run multiple simulations, e.g. lmp1.file("in.file1") lmp2.file("in.file2") -The file(), command(), commands\_list(), commands\_string() methods +The file(), command(), commands_list(), commands_string() methods allow an input script, a single command, or multiple commands to be invoked. -The extract\_setting(), extract\_global(), extract\_box(), -extract\_atom(), extract\_compute(), extract\_fix(), and -extract\_variable() methods return values or pointers to data +The extract_setting(), extract_global(), extract_box(), +extract_atom(), extract_compute(), extract_fix(), and +extract_variable() methods return values or pointers to data structures internal to LAMMPS. -For extract\_global() see the src/library.cpp file for the list of +For extract_global() see the src/library.cpp file for the list of valid names. New names could easily be added. A double or integer is returned. You need to specify the appropriate data type via the type argument. -For extract\_atom(), a pointer to internal LAMMPS atom-based data is +For extract_atom(), a pointer to internal LAMMPS atom-based data is returned, which you can use via normal Python subscripting. See the extract() method in the src/atom.cpp file for a list of valid names. Again, new names could easily be added if the property you want is not @@ -157,7 +157,7 @@ listed. A pointer to a vector of doubles or integers, or a pointer to an array of doubles (double \*\*) or integers (int \*\*) is returned. You need to specify the appropriate data type via the type argument. -For extract\_compute() and extract\_fix(), the global, per-atom, or +For extract_compute() and extract_fix(), the global, per-atom, or local data calculated by the compute or fix can be accessed. What is returned depends on whether the compute or fix calculates a scalar or vector or array. For a scalar, a single double value is returned. If @@ -173,7 +173,7 @@ data types. See the doc pages for individual :doc:`computes ` and :doc:`fixes ` for a description of what they calculate and store. -For extract\_variable(), an :doc:`equal-style or atom-style variable ` is evaluated and its result returned. +For extract_variable(), an :doc:`equal-style or atom-style variable ` is evaluated and its result returned. For equal-style variables a single double value is returned and the group argument is ignored. For atom-style variables, a vector of @@ -181,17 +181,17 @@ doubles is returned, one value per atom, which you can use via normal Python subscripting. The values will be zero for atoms not in the specified group. -The get\_thermo() method returns the current value of a thermo +The get_thermo() method returns the current value of a thermo keyword as a float. -The get\_natoms() method returns the total number of atoms in the +The get_natoms() method returns the total number of atoms in the simulation, as an int. -The set\_variable() method sets an existing string-style variable to a +The set_variable() method sets an existing string-style variable to a new string value, so that subsequent LAMMPS commands can access the variable. -The reset\_box() method resets the size and shape of the simulation +The reset_box() method resets the size and shape of the simulation box, e.g. as part of restoring a previously extracted and saved state of a simulation. @@ -203,19 +203,19 @@ passed by all calling processors, to individual atoms, which may be owned by different processors. Note that the data returned by the gather methods, -e.g. gather\_atoms("x"), is different from the data structure returned -by extract\_atom("x") in four ways. (1) Gather\_atoms() returns a -vector which you index as x[i]; extract\_atom() returns an array -which you index as x[i][j]. (2) Gather\_atoms() orders the atoms -by atom ID while extract\_atom() does not. (3) Gather\_atoms() returns -a list of all atoms in the simulation; extract\_atoms() returns just -the atoms local to each processor. (4) Finally, the gather\_atoms() +e.g. gather_atoms("x"), is different from the data structure returned +by extract_atom("x") in four ways. (1) Gather_atoms() returns a +vector which you index as x[i]; extract_atom() returns an array +which you index as x[i][j]. (2) Gather_atoms() orders the atoms +by atom ID while extract_atom() does not. (3) Gather_atoms() returns +a list of all atoms in the simulation; extract_atoms() returns just +the atoms local to each processor. (4) Finally, the gather_atoms() data structure is a copy of the atom coords stored internally in -LAMMPS, whereas extract\_atom() returns an array that effectively +LAMMPS, whereas extract_atom() returns an array that effectively points directly to the internal data. This means you can change values inside LAMMPS from Python by assigning a new values to the -extract\_atom() array. To do this with the gather\_atoms() vector, you -need to change values in the vector, then invoke the scatter\_atoms() +extract_atom() array. To do this with the gather_atoms() vector, you +need to change values in the vector, then invoke the scatter_atoms() method. For the scatter methods, the array of coordinates passed to must be a diff --git a/doc/src/Python_mpi.rst b/doc/src/Python_mpi.rst index 659d5c57fd..e702172fe9 100644 --- a/doc/src/Python_mpi.rst +++ b/doc/src/Python_mpi.rst @@ -64,7 +64,7 @@ and see one line of output for each processor you run on. it is using, since you specify the details in your low-level src/MAKE/Makefile.foo file. Mpi4py uses the "mpicc" command to find information about the MPI it uses to build against. And it tries to - load "libmpi.so" from the LD\_LIBRARY\_PATH. This may or may not find + load "libmpi.so" from the LD_LIBRARY_PATH. This may or may not find the MPI library that LAMMPS is using. If you have problems running both mpi4py and LAMMPS together, this is an issue you may need to address, e.g. by moving other MPI installations so that mpi4py finds diff --git a/doc/src/Python_shlib.rst b/doc/src/Python_shlib.rst index b9d8e50242..aa11d84432 100644 --- a/doc/src/Python_shlib.rst +++ b/doc/src/Python_shlib.rst @@ -5,7 +5,7 @@ Build LAMMPS as a shared library using make ------------------------------------------- Instructions on how to build LAMMPS as a shared library are given on -the :doc:`Build\_basics ` doc page. A shared library is +the :doc:`Build_basics ` doc page. A shared library is one that is dynamically loadable, which is what Python requires to wrap LAMMPS. On Linux this is a library file that ends in ".so", not ".a". @@ -17,7 +17,7 @@ From the src directory, type make foo mode=shlib where foo is the machine target name, such as mpi or serial. -This should create the file liblammps\_foo.so in the src directory, as +This should create the file liblammps_foo.so in the src directory, as well as a soft link liblammps.so, which is what the Python wrapper will load by default. Note that if you are building multiple machine versions of the shared library, the soft link is always set to the @@ -29,7 +29,7 @@ most recently built version. auxiliary libraries (used by various packages), then all of these extra libraries must also be shared libraries. If the LAMMPS shared-library build fails with an error complaining about this, see - the :doc:`Build\_basics ` doc page. + the :doc:`Build_basics ` doc page. Build LAMMPS as a shared library using CMake -------------------------------------------- @@ -45,10 +45,10 @@ shared library: What this does is create a liblammps.so which contains the majority of LAMMPS code. The generated lmp binary also dynamically links to this library. This means that either this liblammps.so file has to be in the same directory, a system -library path (e.g. /usr/lib64/) or in the LD\_LIBRARY\_PATH. +library path (e.g. /usr/lib64/) or in the LD_LIBRARY_PATH. If you want to use the shared library with Python the recommended way is to create a virtualenv and use it as -CMAKE\_INSTALL\_PREFIX. +CMAKE_INSTALL_PREFIX. .. parsed-literal:: @@ -66,7 +66,7 @@ CMAKE\_INSTALL\_PREFIX. make install This will also install the Python module into your virtualenv. Since virtualenv -doesn't change your LD\_LIBRARY\_PATH, you still need to add its lib64 folder to +doesn't change your LD_LIBRARY_PATH, you still need to add its lib64 folder to it, which contains the installed liblammps.so. .. parsed-literal:: @@ -74,4 +74,4 @@ it, which contains the installed liblammps.so. export LD_LIBRARY_PATH=$VIRTUAL_ENV/lib64:$LD_LIBRARY_PATH Starting Python outside (!) of your build directory, but with the virtualenv -enabled and with the LD\_LIBRARY\_PATH set gives you access to LAMMPS via Python. +enabled and with the LD_LIBRARY_PATH set gives you access to LAMMPS via Python. diff --git a/doc/src/Python_test.rst b/doc/src/Python_test.rst index 1877a12bca..89a4c32504 100644 --- a/doc/src/Python_test.rst +++ b/doc/src/Python_test.rst @@ -31,8 +31,8 @@ first importing from the lammps.py file: >>> CDLL("liblammps.so") If an error occurs, carefully go through the steps on the -:doc:`Build\_basics ` doc page about building a shared -library and the :doc:`Python\_install ` doc page about +:doc:`Build_basics ` doc page about building a shared +library and the :doc:`Python_install ` doc page about insuring Python can find the necessary two files it needs. Test LAMMPS and Python in serial: diff --git a/doc/src/Run_basics.rst b/doc/src/Run_basics.rst index 956f341c80..d02873a8be 100644 --- a/doc/src/Run_basics.rst +++ b/doc/src/Run_basics.rst @@ -65,7 +65,7 @@ or "-bind-to core" (MPICH) can be used. If the LAMMPS command(s) you are using support multi-threading, you can set the number of threads per MPI task via the environment -variable OMP\_NUM\_THREADS, before you launch LAMMPS: +variable OMP_NUM_THREADS, before you launch LAMMPS: .. code-block:: bash diff --git a/doc/src/Run_options.rst b/doc/src/Run_options.rst index 989408a798..afdae20376 100644 --- a/doc/src/Run_options.rst +++ b/doc/src/Run_options.rst @@ -23,7 +23,7 @@ letter abbreviation can be used: * :ref:`-sf or -suffix ` * :ref:`-v or -var ` -For example, the lmp\_mpi executable might be launched as follows: +For example, the lmp_mpi executable might be launched as follows: .. code-block:: bash @@ -50,8 +50,8 @@ set by using the :doc:`echo ` command in the input script itself. **-help** Print a brief help summary and a list of options compiled into this -executable for each LAMMPS style (atom\_style, fix, compute, -pair\_style, bond\_style, etc). This can tell you if the command you +executable for each LAMMPS style (atom_style, fix, compute, +pair_style, bond_style, etc). This can tell you if the command you want to use was included via the appropriate package at compile time. LAMMPS will print the info and immediately exit if this switch is used. @@ -65,7 +65,7 @@ used. Specify a file to use as an input script. This is an optional switch when running LAMMPS in one-partition mode. If it is not specified, LAMMPS reads its script from standard input, typically from a script -via I/O redirection; e.g. lmp\_linux < in.run. I/O redirection should +via I/O redirection; e.g. lmp_linux < in.run. I/O redirection should also work in parallel, but if it does not (in the unlikely case that an MPI implementation does not support it), then use the -in flag. Note that this is a required switch when running LAMMPS in @@ -201,8 +201,8 @@ command which also launches another executable(s) at the same time. (The other executable could be LAMMPS as well.) The color is an integer value which should be different for each executable (another application may set this value in a different way). LAMMPS and the -other executable(s) perform an MPI\_Comm\_split() with their own colors -to shrink the MPI\_COMM\_WORLD communication to be the subset of +other executable(s) perform an MPI_Comm_split() with their own colors +to shrink the MPI_COMM_WORLD communication to be the subset of processors they are actually running on. Currently, this is only used in LAMMPS to perform client/server @@ -284,7 +284,7 @@ log files are created. This overrides the filename specified in the -log command-line option. This option is useful when working with large numbers of partitions, allowing the partition log files to be suppressed (-plog none) or placed in a sub-directory (-plog -replica\_files/log.lammps) If this option is not used the log file for +replica_files/log.lammps) If this option is not used the log file for partition N is log.lammps.N or whatever is specified by the -log command-line option. @@ -300,7 +300,7 @@ partition screen files are created. This overrides the filename specified in the -screen command-line option. This option is useful when working with large numbers of partitions, allowing the partition screen files to be suppressed (-pscreen none) or placed in a -sub-directory (-pscreen replica\_files/screen). If this option is not +sub-directory (-pscreen replica_files/screen). If this option is not used the screen file for partition N is screen.N or whatever is specified by the -screen command-line option. @@ -469,7 +469,7 @@ The syntax following restartfile (or remap), namely is identical to the arguments of the :doc:`write_dump ` command. See its doc page for details. This includes what per-atom -fields are written to the dump file and optional dump\_modify settings, +fields are written to the dump file and optional dump_modify settings, including ones that affect how parallel dump files are written, e.g. the *nfile* and *fileper* keywords. See the :doc:`dump_modify ` doc page for details. @@ -520,7 +520,7 @@ having to edit an input script. As an example, all of the packages provide a :doc:`pair_style lj/cut ` variant, with style names lj/cut/gpu, lj/cut/intel, lj/cut/kk, lj/cut/omp, and lj/cut/opt. A variant style -can be specified explicitly in your input script, e.g. pair\_style +can be specified explicitly in your input script, e.g. pair_style lj/cut/gpu. If the -suffix switch is used the specified suffix (gpu,intel,kk,omp,opt) is automatically appended whenever your input script command creates a new :doc:`atom `, diff --git a/doc/src/Run_output.rst b/doc/src/Run_output.rst index 4aeaf36707..d7d92dc5ee 100644 --- a/doc/src/Run_output.rst +++ b/doc/src/Run_output.rst @@ -168,7 +168,7 @@ additional information is printed, e.g. The first line is the time spent doing 3d FFTs (several per timestep) and the fraction it represents of the total KSpace time (listed above). Each 3d FFT requires computation (3 sets of 1d FFTs) and -communication (transposes). The total flops performed is 5Nlog\_2(N), +communication (transposes). The total flops performed is 5Nlog_2(N), where N is the number of points in the 3d grid. The FFTs are timed with and without the communication and a Gflop rate is computed. The 3d rate is with communication; the 1d rate is without (just the 1d diff --git a/doc/src/Run_windows.rst b/doc/src/Run_windows.rst index 65b299421e..4a60af331a 100644 --- a/doc/src/Run_windows.rst +++ b/doc/src/Run_windows.rst @@ -7,7 +7,7 @@ To run a serial (non-MPI) executable, follow these steps: then typing "cmd". * Move to the directory where you have your input script, (e.g. by typing: cd "Documents"). -* At the command prompt, type "lmp\_serial -in in.file", where +* At the command prompt, type "lmp_serial -in in.file", where in.file is the name of your LAMMPS input script. Note that the serial executable includes support for multi-threading diff --git a/doc/src/Speed_compare.rst b/doc/src/Speed_compare.rst index 8adcce52ef..d3947ec3ef 100644 --- a/doc/src/Speed_compare.rst +++ b/doc/src/Speed_compare.rst @@ -66,7 +66,7 @@ section below for examples where this has been done. acceleration and instead run it - concurrently with a GPU accelerated pair style - on the CPU. This can often be easily achieved with placing a *suffix off* command before and a *suffix on* command after the - *kspace\_style pppm* command. + *kspace_style pppm* command. * The KOKKOS/OpenMP and USER-OMP package have different thread management strategies, which should result in USER-OMP being more efficient for a small number of threads with increasing overhead as the number of threads diff --git a/doc/src/Speed_gpu.rst b/doc/src/Speed_gpu.rst index eb03ff560c..fd0556f67b 100644 --- a/doc/src/Speed_gpu.rst +++ b/doc/src/Speed_gpu.rst @@ -35,9 +35,9 @@ toolkit software on your system (this is primarily tested on Linux and completely unsupported on Windows): * Check if you have an NVIDIA GPU: cat /proc/driver/nvidia/gpus/\*/information -* Go to http://www.nvidia.com/object/cuda\_get.html +* Go to http://www.nvidia.com/object/cuda_get.html * Install a driver and toolkit appropriate for your system (SDK is not necessary) -* Run lammps/lib/gpu/nvc\_get\_devices (after building the GPU library, see below) to +* Run lammps/lib/gpu/nvc_get_devices (after building the GPU library, see below) to list supported devices and properties To compile and use this package in OpenCL mode, you currently need @@ -47,7 +47,7 @@ installed. There can be multiple of them for the same or different hardware (GPUs, CPUs, Accelerators) installed at the same time. OpenCL refers to those as 'platforms'. The GPU library will select the **first** suitable platform, but this can be overridden using the device option of the :doc:`package ` -command. run lammps/lib/gpu/ocl\_get\_devices to get a list of available +command. run lammps/lib/gpu/ocl_get_devices to get a list of available platforms and devices with a suitable ICD available. **Building LAMMPS with the GPU package:** diff --git a/doc/src/Speed_intel.rst b/doc/src/Speed_intel.rst index 1cad9cbeb8..a203b4789d 100644 --- a/doc/src/Speed_intel.rst +++ b/doc/src/Speed_intel.rst @@ -79,7 +79,7 @@ order of operations compared to LAMMPS without acceleration: * The *newton* setting applies to all atoms, not just atoms shared between MPI tasks * Vectorization can change the order for adding pairwise forces -* When using the -DLMP\_USE\_MKL\_RNG define (all included intel optimized +* When using the -DLMP_USE_MKL_RNG define (all included intel optimized makefiles do) at build time, the random number generator for dissipative particle dynamics (pair style dpd/intel) uses the Mersenne Twister generator included in the Intel MKL library (that should be @@ -102,8 +102,8 @@ LAMMPS should be built with the USER-INTEL package installed. Simulations should be run with 1 MPI task per physical *core*\ , not *hardware thread*\ . -* Edit src/MAKE/OPTIONS/Makefile.intel\_cpu\_intelmpi as necessary. -* Set the environment variable KMP\_BLOCKTIME=0 +* Edit src/MAKE/OPTIONS/Makefile.intel_cpu_intelmpi as necessary. +* Set the environment variable KMP_BLOCKTIME=0 * "-pk intel 0 omp $t -sf intel" added to LAMMPS command-line * $t should be 2 for Intel Xeon CPUs and 2 or 4 for Intel Xeon Phi * For some of the simple 2-body potentials without long-range @@ -111,26 +111,26 @@ not *hardware thread*\ . the "newton off" setting added to the input script * For simulations on higher node counts, add "processors \* \* \* grid numa" to the beginning of the input script for better scalability -* If using *kspace\_style pppm* in the input script, add - "kspace\_modify diff ad" for better performance +* If using *kspace_style pppm* in the input script, add + "kspace_modify diff ad" for better performance For Intel Xeon Phi CPUs: * Runs should be performed using MCDRAM. -For simulations using *kspace\_style pppm* on Intel CPUs supporting +For simulations using *kspace_style pppm* on Intel CPUs supporting AVX-512: -* Add "kspace\_modify diff ad" to the input script +* Add "kspace_modify diff ad" to the input script * The command-line option should be changed to "-pk intel 0 omp $r lrt yes -sf intel" where $r is the number of threads minus 1. -* Do not use thread affinity (set KMP\_AFFINITY=none) +* Do not use thread affinity (set KMP_AFFINITY=none) * The "newton off" setting may provide better scalability For Intel Xeon Phi co-processors (Offload): -* Edit src/MAKE/OPTIONS/Makefile.intel\_co-processor as necessary +* Edit src/MAKE/OPTIONS/Makefile.intel_co-processor as necessary * "-pk intel N omp 1" added to command-line where N is the number of co-processors per node. @@ -213,7 +213,7 @@ directory: Makefile.intel_cpu_openpmi # Intel Compiler, OpenMPI, No Offload Makefile.intel_co-processor # Intel Compiler, Intel MPI, Offload -Makefile.knl is identical to Makefile.intel\_cpu\_intelmpi except that +Makefile.knl is identical to Makefile.intel_cpu_intelmpi except that it explicitly specifies that vectorization should be for Intel Xeon Phi x200 processors making it easier to cross-compile. For users with recent installations of Intel Parallel Studio, the process can be as @@ -234,12 +234,12 @@ without offload support will produce a smaller binary. The general requirements for Makefiles with the USER-INTEL package are as follows. When using Intel compilers, "-restrict" is required and "-qopenmp" is highly recommended for CCFLAGS and LINKFLAGS. -CCFLAGS should include "-DLMP\_INTEL\_USELRT" (unless POSIX Threads -are not supported in the build environment) and "-DLMP\_USE\_MKL\_RNG" +CCFLAGS should include "-DLMP_INTEL_USELRT" (unless POSIX Threads +are not supported in the build environment) and "-DLMP_USE_MKL_RNG" (unless Intel Math Kernel Library (MKL) is not available in the build environment). For Intel compilers, LIB should include "-ltbbmalloc" -or if the library is not available, "-DLMP\_INTEL\_NO\_TBB" can be added -to CCFLAGS. For builds supporting offload, "-DLMP\_INTEL\_OFFLOAD" is +or if the library is not available, "-DLMP_INTEL_NO_TBB" can be added +to CCFLAGS. For builds supporting offload, "-DLMP_INTEL_OFFLOAD" is required for CCFLAGS and "-qoffload" is required for LINKFLAGS. Other recommended CCFLAG options for best performance are "-O2 -fno-alias -ansi-alias -qoverride-limits fp-model fast=2 -no-prec-div". @@ -297,9 +297,9 @@ almost all cases. OpenMP threads on the host (CPU) will be set by default on the host *when using offload to a co-processor*\ . In this case, it is unnecessary to use other methods to control affinity (e.g. taskset, numactl, - I\_MPI\_PIN\_DOMAIN, etc.). This can be disabled with the *no\_affinity* + I_MPI_PIN_DOMAIN, etc.). This can be disabled with the *no_affinity* option to the :doc:`package intel ` command or by disabling the - option at build time (by adding -DINTEL\_OFFLOAD\_NOAFFINITY to the + option at build time (by adding -DINTEL_OFFLOAD_NOAFFINITY to the CCFLAGS line of your Makefile). Disabling this option is not recommended, especially when running on a machine with Intel Hyper-Threading technology disabled. @@ -313,7 +313,7 @@ editing the input script. This switch will automatically append :doc:`package intel 1 `. This package command is used to set options for the USER-INTEL package. The default package command will specify that USER-INTEL calculations are performed in mixed precision, -that the number of OpenMP threads is specified by the OMP\_NUM\_THREADS +that the number of OpenMP threads is specified by the OMP_NUM_THREADS environment variable, and that if co-processors are present and the binary was built with offload support, that 1 co-processor per node will be used with automatic balancing of work between the CPU and the @@ -324,11 +324,11 @@ the "-pk intel Nphi" :doc:`command-line switch ` with keyword/value pairs as specified in the documentation. Here, Nphi = # of Xeon Phi co-processors/node (ignored without offload support). Common options to the USER-INTEL package include *omp* to -override any OMP\_NUM\_THREADS setting and specify the number of OpenMP +override any OMP_NUM_THREADS setting and specify the number of OpenMP threads, *mode* to set the floating-point precision mode, and *lrt* to enable Long-Range Thread mode as described below. See the :doc:`package intel ` command for details, including the default values used for all its options if not specified, and how to set the number -of OpenMP threads via the OMP\_NUM\_THREADS environment variable if +of OpenMP threads via the OMP_NUM_THREADS environment variable if desired. Examples (see documentation for your MPI/Machine for differences in @@ -375,7 +375,7 @@ Long-Range Thread (LRT) mode is an option to the :doc:`package intel ` with SMT. It generates an extra pthread for each MPI task. The thread is dedicated to performing some of the PPPM calculations and MPI communications. This feature requires setting the pre-processor flag --DLMP\_INTEL\_USELRT in the makefile when compiling LAMMPS. It is unset +-DLMP_INTEL_USELRT in the makefile when compiling LAMMPS. It is unset in the default makefiles (\ *Makefile.mpi* and *Makefile.serial*\ ) but it is set in all makefiles tuned for the USER-INTEL package. On Intel Xeon Phi x200 series CPUs, the LRT feature will likely improve @@ -387,7 +387,7 @@ normally be used for the run and add the "lrt yes" option to the "-pk" command-line suffix or "package intel" command. For example, if a run would normally perform best with "-pk intel 0 omp 4", instead use "-pk intel 0 omp 3 lrt yes". When using LRT, you should set the -environment variable "KMP\_AFFINITY=none". LRT mode is not supported +environment variable "KMP_AFFINITY=none". LRT mode is not supported when using offload. .. note:: @@ -425,7 +425,7 @@ alternative to LRT mode and the two cannot be used together. Currently, when using Intel MPI with Intel Xeon Phi x200 series CPUs, better performance might be obtained by setting the -environment variable "I\_MPI\_SHM\_LMT=shm" for Linux kernels that do +environment variable "I_MPI_SHM_LMT=shm" for Linux kernels that do not yet have full support for AVX-512. Runs on Intel Xeon Phi x200 series processors will always perform better using MCDRAM. Please consult your system documentation for the best approach to specify @@ -513,7 +513,7 @@ When offloading to a co-processor, :doc:`hybrid ` styles that require skip lists for neighbor builds cannot be offloaded. Using :doc:`hybrid/overlay ` is allowed. Only one intel accelerated style may be used with hybrid styles when offloading. -:doc:`Special\_bonds ` exclusion lists are not currently +:doc:`Special_bonds ` exclusion lists are not currently supported with offload, however, the same effect can often be accomplished by setting cutoffs for excluded atom types to 0. None of the pair styles in the USER-INTEL package currently support the diff --git a/doc/src/Speed_kokkos.rst b/doc/src/Speed_kokkos.rst index 46b4be571c..6658957006 100644 --- a/doc/src/Speed_kokkos.rst +++ b/doc/src/Speed_kokkos.rst @@ -21,7 +21,7 @@ package was developed primarily by Christian Trott (Sandia) and Stan Moore (Sandia) with contributions of various styles by others, including Sikandar Mashayak (UIUC), Ray Shan (Sandia), and Dan Ibanez (Sandia). For more information on developing using Kokkos abstractions -see the Kokkos programmers' guide at /lib/kokkos/doc/Kokkos\_PG.pdf. +see the Kokkos programmers' guide at /lib/kokkos/doc/Kokkos_PG.pdf. Kokkos currently provides support for 3 modes of execution (per MPI task). These are Serial (MPI-only for CPUs and Intel Phi), OpenMP @@ -108,8 +108,8 @@ below. .. note:: When using a single OpenMP thread, the Kokkos Serial back end (i.e. - Makefile.kokkos\_mpi\_only) will give better performance than the OpenMP - back end (i.e. Makefile.kokkos\_omp) because some of the overhead to make + Makefile.kokkos_mpi_only) will give better performance than the OpenMP + back end (i.e. Makefile.kokkos_omp) because some of the overhead to make the code thread-safe is removed. .. note:: @@ -134,8 +134,8 @@ small numbers of threads (i.e. 8 or less) but does increase memory footprint and is not scalable to large numbers of threads. An alternative to data duplication is to use thread-level atomic operations which do not require data duplication. The use of atomic operations can -be enforced by compiling LAMMPS with the "-DLMP\_KOKKOS\_USE\_ATOMICS" -pre-processor flag. Most but not all Kokkos-enabled pair\_styles support +be enforced by compiling LAMMPS with the "-DLMP_KOKKOS_USE_ATOMICS" +pre-processor flag. Most but not all Kokkos-enabled pair_styles support data duplication. Alternatively, full neighbor lists avoid the need for duplication or atomic operations but require more compute operations per atom. When using the Kokkos Serial back end or the OpenMP back end with @@ -159,9 +159,9 @@ for your MPI installation), binding can be forced with these flags: For binding threads with KOKKOS OpenMP, use thread affinity environment variables to force binding. With OpenMP 3.1 (gcc 4.7 or later, intel 12 or later) setting the environment variable -OMP\_PROC\_BIND=true should be sufficient. In general, for best -performance with OpenMP 4.0 or better set OMP\_PROC\_BIND=spread and -OMP\_PLACES=threads. For binding threads with the KOKKOS pthreads +OMP_PROC_BIND=true should be sufficient. In general, for best +performance with OpenMP 4.0 or better set OMP_PROC_BIND=spread and +OMP_PLACES=threads. For binding threads with the KOKKOS pthreads option, compile LAMMPS the KOKKOS HWLOC=yes option as described below. **Running on Knight's Landing (KNL) Intel Xeon Phi:** @@ -290,7 +290,7 @@ one or more nodes, each with two GPUs: .. note:: To get an accurate timing breakdown between time spend in pair, - kspace, etc., you must set the environment variable CUDA\_LAUNCH\_BLOCKING=1. + kspace, etc., you must set the environment variable CUDA_LAUNCH_BLOCKING=1. However, this will reduce performance and is not recommended for production runs. **Run with the KOKKOS package by editing an input script:** @@ -320,8 +320,8 @@ wish to change any of its option defaults, as set by the "-k on" With the KOKKOS package, both OpenMP multi-threading and GPUs can be used together in a few special cases. In the Makefile, the -KOKKOS\_DEVICES variable must include both "Cuda" and "OpenMP", as is -the case for /src/MAKE/OPTIONS/Makefile.kokkos\_cuda\_mpi +KOKKOS_DEVICES variable must include both "Cuda" and "OpenMP", as is +the case for /src/MAKE/OPTIONS/Makefile.kokkos_cuda_mpi .. code-block:: bash @@ -357,7 +357,7 @@ GPU. First compile with "--default-stream per-thread" added to CCFLAGS in the Kokkos CUDA Makefile. Then explicitly use the "/kk/host" suffix for kspace and bonds, angles, etc. in the input file and the "kk" suffix (equal to "kk/device") on the command line. Also make -sure the environment variable CUDA\_LAUNCH\_BLOCKING is not set to "1" +sure the environment variable CUDA_LAUNCH_BLOCKING is not set to "1" so CPU/GPU overlap can occur. **Speed-ups to expect:** @@ -394,34 +394,34 @@ Makefile.machine, or they can be specified as CMake variables. Each takes a value shown below. The default value is listed, which is set in the lib/kokkos/Makefile.kokkos file. -* KOKKOS\_DEBUG, values = *yes*\ , *no*\ , default = *no* -* KOKKOS\_USE\_TPLS, values = *hwloc*\ , *librt*\ , *experimental\_memkind*, default = *none* -* KOKKOS\_CXX\_STANDARD, values = *c++11*\ , *c++1z*\ , default = *c++11* -* KOKKOS\_OPTIONS, values = *aggressive\_vectorization*, *disable\_profiling*, default = *none* -* KOKKOS\_CUDA\_OPTIONS, values = *force\_uvm*, *use\_ldg*, *rdc*\ , *enable\_lambda*, default = *enable\_lambda* +* KOKKOS_DEBUG, values = *yes*\ , *no*\ , default = *no* +* KOKKOS_USE_TPLS, values = *hwloc*\ , *librt*\ , *experimental_memkind*, default = *none* +* KOKKOS_CXX_STANDARD, values = *c++11*\ , *c++1z*\ , default = *c++11* +* KOKKOS_OPTIONS, values = *aggressive_vectorization*, *disable_profiling*, default = *none* +* KOKKOS_CUDA_OPTIONS, values = *force_uvm*, *use_ldg*, *rdc*\ , *enable_lambda*, default = *enable_lambda* -KOKKOS\_USE\_TPLS=hwloc binds threads to hardware cores, so they do not -migrate during a simulation. KOKKOS\_USE\_TPLS=hwloc should always be -used if running with KOKKOS\_DEVICES=Pthreads for pthreads. It is not -necessary for KOKKOS\_DEVICES=OpenMP for OpenMP, because OpenMP +KOKKOS_USE_TPLS=hwloc binds threads to hardware cores, so they do not +migrate during a simulation. KOKKOS_USE_TPLS=hwloc should always be +used if running with KOKKOS_DEVICES=Pthreads for pthreads. It is not +necessary for KOKKOS_DEVICES=OpenMP for OpenMP, because OpenMP provides alternative methods via environment variables for binding threads to hardware cores. More info on binding threads to cores is given on the :doc:`Speed omp ` doc page. -KOKKOS\_USE\_TPLS=librt enables use of a more accurate timer mechanism +KOKKOS_USE_TPLS=librt enables use of a more accurate timer mechanism on most Unix platforms. This library is not available on all platforms. -KOKKOS\_DEBUG is only useful when developing a Kokkos-enabled style -within LAMMPS. KOKKOS\_DEBUG=yes enables printing of run-time +KOKKOS_DEBUG is only useful when developing a Kokkos-enabled style +within LAMMPS. KOKKOS_DEBUG=yes enables printing of run-time debugging information that can be useful. It also enables runtime bounds checking on Kokkos data structures. -KOKKOS\_CXX\_STANDARD and KOKKOS\_OPTIONS are typically not changed when +KOKKOS_CXX_STANDARD and KOKKOS_OPTIONS are typically not changed when building LAMMPS. -KOKKOS\_CUDA\_OPTIONS are additional options for CUDA. The LAMMPS KOKKOS -package must be compiled with the *enable\_lambda* option when using +KOKKOS_CUDA_OPTIONS are additional options for CUDA. The LAMMPS KOKKOS +package must be compiled with the *enable_lambda* option when using GPUs. Restrictions diff --git a/doc/src/Speed_measure.rst b/doc/src/Speed_measure.rst index 2f86aa18f2..686fdb6adc 100644 --- a/doc/src/Speed_measure.rst +++ b/doc/src/Speed_measure.rst @@ -14,7 +14,7 @@ timings; you can simply extrapolate from short runs. For the set of runs, look at the timing data printed to the screen and log file at the end of each LAMMPS run. The -:doc:`Run\_output ` doc page gives an overview. +:doc:`Run_output ` doc page gives an overview. Running on one (or a few processors) should give a good estimate of the serial performance and what portions of the timestep are taking @@ -42,5 +42,5 @@ inaccurate relative timing data, because processors have to wait when communication occurs for other processors to catch up. Thus the reported times for "Communication" or "Other" may be higher than they really are, due to load-imbalance. If this is an issue, you can -uncomment the MPI\_Barrier() lines in src/timer.cpp, and re-compile +uncomment the MPI_Barrier() lines in src/timer.cpp, and re-compile LAMMPS, to obtain synchronized timings. diff --git a/doc/src/Speed_omp.rst b/doc/src/Speed_omp.rst index 812d774867..5e034e51ec 100644 --- a/doc/src/Speed_omp.rst +++ b/doc/src/Speed_omp.rst @@ -43,14 +43,14 @@ node), otherwise performance will suffer. As in the lines above, use the "-sf omp" :doc:`command-line switch `, which will automatically append "omp" to styles that support it. The "-sf omp" switch also issues a default :doc:`package omp 0 ` command, which will set the number of -threads per MPI task via the OMP\_NUM\_THREADS environment variable. +threads per MPI task via the OMP_NUM_THREADS environment variable. You can also use the "-pk omp Nt" :doc:`command-line switch `, to explicitly set Nt = # of OpenMP threads per MPI task to use, as well as additional options. Its syntax is the same as the :doc:`package omp ` command whose doc page gives details, including the default values used if it is not specified. It also gives more details on how to set the number of threads via the -OMP\_NUM\_THREADS environment variable. +OMP_NUM_THREADS environment variable. **Or run with the USER-OMP package by editing an input script:** @@ -67,7 +67,7 @@ Use the :doc:`suffix omp ` command, or you can explicitly add an You must also use the :doc:`package omp ` command to enable the USER-OMP package. When you do this you also specify how many threads per MPI task to use. The command doc page explains other options and -how to set the number of threads via the OMP\_NUM\_THREADS environment +how to set the number of threads via the OMP_NUM_THREADS environment variable. **Speed-ups to expect:** diff --git a/doc/src/Speed_packages.rst b/doc/src/Speed_packages.rst index e515a89d19..97eb7a64c2 100644 --- a/doc/src/Speed_packages.rst +++ b/doc/src/Speed_packages.rst @@ -90,13 +90,13 @@ listed above: +--------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------+ | re-build LAMMPS | make machine | +--------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------+ -| prepare and test a regular LAMMPS simulation | lmp\_machine -in in.script; mpirun -np 32 lmp\_machine -in in.script | +| prepare and test a regular LAMMPS simulation | lmp_machine -in in.script; mpirun -np 32 lmp_machine -in in.script | +--------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------+ | enable specific accelerator support via '-k on' :doc:`command-line switch `, | only needed for KOKKOS package | +--------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------+ | set any needed options for the package via "-pk" :doc:`command-line switch ` or :doc:`package ` command, | only if defaults need to be changed | +--------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------+ -| use accelerated styles in your input via "-sf" :doc:`command-line switch ` or :doc:`suffix ` command | lmp\_machine -in in.script -sf gpu | +| use accelerated styles in your input via "-sf" :doc:`command-line switch ` or :doc:`suffix ` command | lmp_machine -in in.script -sf gpu | +--------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------+ Note that the first 4 steps can be done as a single command with diff --git a/doc/src/Tools.rst b/doc/src/Tools.rst index cfe8a17d55..10b1e5033c 100644 --- a/doc/src/Tools.rst +++ b/doc/src/Tools.rst @@ -171,7 +171,7 @@ To compile the tools, edit the makefile for your system and run "make". Please report problems and issues the colvars library and its tools at: https://github.com/colvars/colvars/issues -abf\_integrate: +abf_integrate: MC-based integration of multidimensional free energy gradient Version 20110511 @@ -238,7 +238,7 @@ at univ-bpclermont.fr, alain.dequidt at univ-bpclermont.fr eam database tool ----------------------------- -The tools/eam\_database directory contains a Fortran program that will +The tools/eam_database directory contains a Fortran program that will generate EAM alloy setfl potential files for any combination of 16 elements: Cu, Ag, Au, Ni, Pd, Pt, Al, Pb, Fe, Mo, Ta, W, Mg, Co, Ti, Zr. The files can then be used with the :doc:`pair_style eam/alloy ` command. @@ -256,7 +256,7 @@ X. W. Zhou, R. A. Johnson, and H. N. G. Wadley, Phys. Rev. B, 69, eam generate tool ----------------------------- -The tools/eam\_generate directory contains several one-file C programs +The tools/eam_generate directory contains several one-file C programs that convert an analytic formula into a tabulated :doc:`embedded atom method (EAM) ` setfl potential file. The potentials they produce are in the potentials directory, and can be used with the :doc:`pair_style eam/alloy ` command. @@ -512,10 +512,10 @@ This tool was written by Zachary Kraus at Georgia Tech. .. _pymol: -pymol\_asphere tool +pymol_asphere tool ------------------------------- -The pymol\_asphere sub-directory contains a tool for converting a +The pymol_asphere sub-directory contains a tool for converting a LAMMPS dump file that contains orientation info for ellipsoidal particles into an input file for the `PyMol visualization package `_ or its `open source variant `_. @@ -525,7 +525,7 @@ particles into an input file for the `PyMol visualization package `_ Specifically, the tool triangulates the ellipsoids so they can be viewed as true ellipsoidal particles within PyMol. See the README and -examples directory within pymol\_asphere for more information. +examples directory within pymol_asphere for more information. This tool was written by Mike Brown at Sandia. @@ -555,7 +555,7 @@ README for more info on Pizza.py and how to use these scripts. replica tool -------------------------- -The tools/replica directory contains the reorder\_remd\_traj python script which +The tools/replica directory contains the reorder_remd_traj python script which can be used to reorder the replica trajectories (resulting from the use of the temper command) according to temperature. This will produce discontinuous trajectories with all frames at the same temperature in each trajectory. @@ -568,7 +568,7 @@ while at the Shell lab at UC Santa Barbara. (tanmoy dot 7989 at gmail.com) ---------- -.. _reax\_tool: +.. _reax_tool: reax tool -------------------------- @@ -587,7 +587,7 @@ These tools were written by Aidan Thompson at Sandia. smd tool ------------------ -The smd sub-directory contains a C++ file dump2vtk\_tris.cpp and +The smd sub-directory contains a C++ file dump2vtk_tris.cpp and Makefile which can be compiled and used to convert triangle output files created by the Smooth-Mach Dynamics (USER-SMD) package into a VTK-compatible unstructured grid file. It could then be read in and @@ -610,7 +610,7 @@ The spin sub-directory contains a C file interpolate.c which can be compiled and used to perform a cubic polynomial interpolation of the MEP following a GNEB calculation. -See the README file in tools/spin/interpolate\_gneb for more details. +See the README file in tools/spin/interpolate_gneb for more details. This tool was written by the SPIN package author, Julien Tranchida at Sandia National Labs (jtranch at sandia.gov, and by Aleksei @@ -618,7 +618,7 @@ Ivanov, at University of Iceland (ali5 at hi.is). ---------- -.. _singularity\_tool: +.. _singularity_tool: singularity tool ---------------------------------------- diff --git a/doc/src/angle_charmm.rst b/doc/src/angle_charmm.rst index fc8641d93c..a8c227c765 100644 --- a/doc/src/angle_charmm.rst +++ b/doc/src/angle_charmm.rst @@ -36,7 +36,7 @@ The *charmm* angle style uses the potential E = K (\theta - \theta_0)^2 + K_{ub} (r - r_{ub})^2 -with an additional Urey\_Bradley term based on the distance :math:`r` between +with an additional Urey_Bradley term based on the distance :math:`r` between the 1st and 3rd atoms in the angle. :math:`K`, :math:`\theta_0`, :math:`K_{ub}`, and :math:`R_{ub}` are coefficients defined for each angle type. diff --git a/doc/src/angle_cross.rst b/doc/src/angle_cross.rst index 95852acd11..4fa95481ac 100644 --- a/doc/src/angle_cross.rst +++ b/doc/src/angle_cross.rst @@ -53,7 +53,7 @@ Restrictions """""""""""" This angle style can only be used if LAMMPS was built with the -USER\_YAFF package. See the :doc:`Build package ` doc +USER_YAFF package. See the :doc:`Build package ` doc page for more info. Related commands diff --git a/doc/src/angle_fourier.rst b/doc/src/angle_fourier.rst index a47f9e5620..a2008f731c 100644 --- a/doc/src/angle_fourier.rst +++ b/doc/src/angle_fourier.rst @@ -66,7 +66,7 @@ Restrictions """""""""""" This angle style can only be used if LAMMPS was built with the -USER\_MISC package. See the :doc:`Build package ` doc +USER_MISC package. See the :doc:`Build package ` doc page for more info. Related commands diff --git a/doc/src/angle_fourier_simple.rst b/doc/src/angle_fourier_simple.rst index 7b257a6a54..795142ccaa 100644 --- a/doc/src/angle_fourier_simple.rst +++ b/doc/src/angle_fourier_simple.rst @@ -65,7 +65,7 @@ Restrictions """""""""""" This angle style can only be used if LAMMPS was built with the -USER\_MISC package. See the :doc:`Build package ` doc +USER_MISC package. See the :doc:`Build package ` doc page for more info. Related commands diff --git a/doc/src/angle_hybrid.rst b/doc/src/angle_hybrid.rst index e39c079e0a..c84b351132 100644 --- a/doc/src/angle_hybrid.rst +++ b/doc/src/angle_hybrid.rst @@ -34,7 +34,7 @@ command or in the data file. In the :doc:`angle_coeff ` commands, the name of an angle style must be added after the angle type, with the remaining coefficients being those -appropriate to that style. In the example above, the 2 angle\_coeff +appropriate to that style. In the example above, the 2 angle_coeff commands set angles of angle type 1 to be computed with a *harmonic* potential with coefficients 80.0, 30.0 for :math:`K`, :math:`\theta_0`. All other angle types :math:`(2 - N)` are computed with a *cosine* potential with coefficient diff --git a/doc/src/angle_mm3.rst b/doc/src/angle_mm3.rst index 9568bf165c..cc6ee120cd 100644 --- a/doc/src/angle_mm3.rst +++ b/doc/src/angle_mm3.rst @@ -47,7 +47,7 @@ Restrictions """""""""""" This angle style can only be used if LAMMPS was built with the -USER\_YAFF package. See the :doc:`Build package ` doc +USER_YAFF package. See the :doc:`Build package ` doc page for more info. Related commands diff --git a/doc/src/angle_quartic.rst b/doc/src/angle_quartic.rst index be44854298..4559389a2a 100644 --- a/doc/src/angle_quartic.rst +++ b/doc/src/angle_quartic.rst @@ -72,7 +72,7 @@ Restrictions """""""""""" This angle style can only be used if LAMMPS was built with the -USER\_MISC package. See the :doc:`Build package ` doc +USER_MISC package. See the :doc:`Build package ` doc page for more info. Related commands diff --git a/doc/src/angle_sdk.rst b/doc/src/angle_sdk.rst index cbdb809530..5601e4f245 100644 --- a/doc/src/angle_sdk.rst +++ b/doc/src/angle_sdk.rst @@ -37,7 +37,7 @@ where :math:`\theta_0` is the equilibrium value of the angle and *lj/sdk* pair style between the atoms 1 and 3. This angle potential is intended for coarse grained MD simulations with the CMM parameterization using the :doc:`pair_style lj/sdk `. Relative to the -pair\_style *lj/sdk*\ , however, the energy is shifted by +pair_style *lj/sdk*\ , however, the energy is shifted by :math:`\epsilon`, to avoid sudden jumps. Note that the usual 1/2 factor is included in :math:`K`. @@ -50,7 +50,7 @@ The following coefficients must be defined for each angle type via the :math:`\theta_0` is specified in degrees, but LAMMPS converts it to radians internally; hence the units of :math:`K` are in energy/radian\^2. The also required *lj/sdk* parameters will be extracted automatically -from the pair\_style. +from the pair_style. ---------- diff --git a/doc/src/angle_style.rst b/doc/src/angle_style.rst index e43dee2591..91232a6b6c 100644 --- a/doc/src/angle_style.rst +++ b/doc/src/angle_style.rst @@ -41,7 +41,7 @@ files which means angle_style and :doc:`angle_coeff ` commands do not need to be re-specified in an input script that restarts a simulation. See the :doc:`read_restart ` command for details on how to do this. The one exception is that -angle\_style *hybrid* only stores the list of sub-styles in the restart +angle_style *hybrid* only stores the list of sub-styles in the restart file; angle coefficients need to be re-specified. .. note:: @@ -61,7 +61,7 @@ the style to display the formula it computes and coefficients specified by the associated :doc:`angle_coeff ` command. Click on the style to display the formula it computes, any additional -arguments specified in the angle\_style command, and coefficients +arguments specified in the angle_style command, and coefficients specified by the associated :doc:`angle_coeff ` command. There are also additional accelerated pair styles included in the @@ -98,7 +98,7 @@ of (g,i,k,o,t) to indicate which accelerated styles exist. Restrictions """""""""""" -Angle styles can only be set for atom\_styles that allow angles to be +Angle styles can only be set for atom_styles that allow angles to be defined. Most angle styles are part of the MOLECULE package. They are only diff --git a/doc/src/angle_table.rst b/doc/src/angle_table.rst index 9759e7fcd9..729d890d67 100644 --- a/doc/src/angle_table.rst +++ b/doc/src/angle_table.rst @@ -87,7 +87,7 @@ keyword followed by one or more numeric values. The parameter "N" is required and its value is the number of table entries that follow. Note that this may be different than the *N* specified in the :doc:`angle_style table ` command. Let -Ntable = *N* in the angle\_style command, and Nfile = "N" in the +Ntable = *N* in the angle_style command, and Nfile = "N" in the tabulated file. What LAMMPS does is a preliminary interpolation by creating splines using the Nfile tabulated values as nodal points. It uses these to interpolate as needed to generate energy and derivative @@ -148,12 +148,12 @@ instructions on how to use the accelerated styles effectively. **Restart info:** -This angle style writes the settings for the "angle\_style table" -command to :doc:`binary restart files `, so a angle\_style +This angle style writes the settings for the "angle_style table" +command to :doc:`binary restart files `, so a angle_style command does not need to specified in an input script that reads a restart file. However, the coefficient information is not stored in the restart file, since it is tabulated in the potential files. Thus, -angle\_coeff commands do need to be specified in the restart input +angle_coeff commands do need to be specified in the restart input script. Restrictions diff --git a/doc/src/atom_modify.rst b/doc/src/atom_modify.rst index c4686c4f21..c94ca65c1c 100644 --- a/doc/src/atom_modify.rst +++ b/doc/src/atom_modify.rst @@ -60,8 +60,8 @@ The only reason not to use atom IDs is if you are running an atomic simulation so large that IDs cannot be uniquely assigned. For a default LAMMPS build this limit is 2\^31 or about 2 billion atoms. However, even in this case, you can use 64-bit atom IDs, allowing 2\^63 -or about 9e18 atoms, if you build LAMMPS with the - DLAMMPS\_BIGBIG -switch. This is described on the :doc:`Build\_settings ` +or about 9e18 atoms, if you build LAMMPS with the - DLAMMPS_BIGBIG +switch. This is described on the :doc:`Build_settings ` doc page. If atom IDs are not used, they must be specified as 0 for all atoms, e.g. in a data or restart file. @@ -108,7 +108,7 @@ this command. Note that specifying "all" as the group-ID effectively turns off the *first* option. It is OK to use the *first* keyword with a group that has not yet been -defined, e.g. to use the atom\_modify first command at the beginning of +defined, e.g. to use the atom_modify first command at the beginning of your input script. LAMMPS does not use the group until a simulation is run. diff --git a/doc/src/atom_style.rst b/doc/src/atom_style.rst index fcd138c836..df00c65f01 100644 --- a/doc/src/atom_style.rst +++ b/doc/src/atom_style.rst @@ -119,7 +119,7 @@ quantities. +--------------+-----------------------------------------------------+--------------------------------------+ | *tri* | corner points, angular momentum | rigid bodies | +--------------+-----------------------------------------------------+--------------------------------------+ -| *wavepacket* | charge, spin, eradius, etag, cs\_re, cs\_im | AWPMD | +| *wavepacket* | charge, spin, eradius, etag, cs_re, cs_im | AWPMD | +--------------+-----------------------------------------------------+--------------------------------------+ .. note:: @@ -158,7 +158,7 @@ For the *dipole* style, a point dipole is defined for each point particle. Note that if you wish the particles to be finite-size spheres as in a Stockmayer potential for a dipolar fluid, so that the particles can rotate due to dipole-dipole interactions, then you need -to use atom\_style hybrid sphere dipole, which will assign both a +to use atom_style hybrid sphere dipole, which will assign both a diameter and dipole moment to each particle. For the *electron* style, the particles representing electrons are 3d @@ -171,14 +171,14 @@ per-particle mass and volume. The *dpd* style is for dissipative particle dynamics (DPD) particles. Note that it is part of the USER-DPD package, and is not for use with the :doc:`pair_style dpd or dpd/stat ` commands, which can -simply use atom\_style atomic. Atom\_style dpd extends DPD particle +simply use atom_style atomic. Atom_style dpd extends DPD particle properties with internal temperature (dpdTheta), internal conductive energy (uCond), internal mechanical energy (uMech), and internal chemical energy (uChem). The *edpd* style is for energy-conserving dissipative particle -dynamics (eDPD) particles which store a temperature (edpd\_temp), and -heat capacity(edpd\_cv). +dynamics (eDPD) particles which store a temperature (edpd_temp), and +heat capacity(edpd_cv). The *mdpd* style is for many-body dissipative particle dynamics (mDPD) particles which store a density (rho) for considering @@ -186,7 +186,7 @@ density-dependent many-body interactions. The *tdpd* style is for transport dissipative particle dynamics (tDPD) particles which store a set of chemical concentration. An integer -"cc\_species" is required to specify the number of chemical species +"cc_species" is required to specify the number of chemical species involved in a tDPD system. The *meso* style is for smoothed particle hydrodynamics (SPH) @@ -205,7 +205,7 @@ Those spins have a norm (their magnetic moment) and a direction. The *wavepacket* style is similar to *electron*\ , but the electrons may consist of several Gaussian wave packets, summed up with coefficients -cs= (cs\_re,cs\_im). Each of the wave packets is treated as a separate +cs= (cs_re,cs_im). Each of the wave packets is treated as a separate particle in LAMMPS, wave packets belonging to the same electron must have identical *etag* values. @@ -232,7 +232,7 @@ can be advantageous for large-scale coarse-grained systems. .. note:: When using the *template* style with a :doc:`molecule template ` that contains multiple molecules, you should - insure the atom types, bond types, angle\_types, etc in all the + insure the atom types, bond types, angle_types, etc in all the molecules are consistent. E.g. if one molecule represents H2O and another CO2, then you probably do not want each molecule file to define 2 atom types and a single bond type, because they will conflict @@ -256,7 +256,7 @@ orientation and position can be time integrated due to forces and torques. Note that there may be additional arguments required along with the -*bstyle* specification, in the atom\_style body command. These +*bstyle* specification, in the atom_style body command. These arguments are described on the :doc:`Howto body ` doc page. ---------- @@ -271,7 +271,7 @@ If some atoms have bonds, but others do not, use the *bond* style. The only scenario where the *hybrid* style is needed is if there is no single style which defines all needed properties of all atoms. For example, as mentioned above, if you want dipolar particles which will -rotate due to torque, you need to use "atom\_style hybrid sphere +rotate due to torque, you need to use "atom_style hybrid sphere dipole". When a hybrid style is used, atoms store and communicate the union of all quantities implied by the individual styles. @@ -351,7 +351,7 @@ Related commands Default """"""" -atom\_style atomic +atom_style atomic ---------- diff --git a/doc/src/balance.rst b/doc/src/balance.rst index f3015127d9..5e631fdd27 100644 --- a/doc/src/balance.rst +++ b/doc/src/balance.rst @@ -197,7 +197,7 @@ The "grid" methods can be used with either of the :doc:`comm_style ` command options, *brick* or *tiled*\ . The "tiling" methods can only be used with :doc:`comm_style tiled `. Note that it can be useful to use a "grid" method with :doc:`comm_style tiled ` to return the domain -partitioning to a logical 3d grid of processors so that "comm\_style +partitioning to a logical 3d grid of processors so that "comm_style brick" can afterwords be specified for subsequent :doc:`run ` commands. @@ -228,7 +228,7 @@ that specify the position of the cutting planes. This requires knowing Ps = Px or Py or Pz = the number of processors assigned by LAMMPS to the relevant dimension. This assignment is made (and the Px, Py, Pz values printed out) when the simulation box is created by -the "create\_box" or "read\_data" or "read\_restart" command and is +the "create_box" or "read_data" or "read_restart" command and is influenced by the settings of the :doc:`processors ` command. @@ -333,7 +333,7 @@ particles in that sub-box. ---------- -.. _weighted\_balance: +.. _weighted_balance: This sub-section describes how to perform weighted load balancing using the *weight* keyword. @@ -462,7 +462,7 @@ velocity, the volume of its Voronoi cell, etc. The *store* weight style does not compute a weight factor. Instead it stores the current accumulated weights in a custom per-atom property -specified by *name*\ . This must be a property defined as *d\_name* via +specified by *name*\ . This must be a property defined as *d_name* via the :doc:`fix property/atom ` command. Note that these custom per-atom properties can be output in a :doc:`dump ` file, so this is a way to examine, debug, or visualize the diff --git a/doc/src/bond_coeff.rst b/doc/src/bond_coeff.rst index 2a45e32534..416190a367 100644 --- a/doc/src/bond_coeff.rst +++ b/doc/src/bond_coeff.rst @@ -40,7 +40,7 @@ leading asterisk means all types from 1 to n (inclusive). A trailing asterisk means all types from n to N (inclusive). A middle asterisk means all types from m to n (inclusive). -Note that using a bond\_coeff command can override a previous setting +Note that using a bond_coeff command can override a previous setting for the same bond type. For example, these commands set the coeffs for all bond types, then overwrite the coeffs for just bond type 2: @@ -50,7 +50,7 @@ for all bond types, then overwrite the coeffs for just bond type 2: bond_coeff 2 200.0 1.2 A line in a data file that specifies bond coefficients uses the exact -same format as the arguments of the bond\_coeff command in an input +same format as the arguments of the bond_coeff command in an input script, except that wild-card asterisks should not be used since coefficients for all N types must be listed in the file. For example, under the "Bond Coeffs" section of a data file, the line that @@ -68,7 +68,7 @@ compact form on the :doc:`Commands bond ` doc page. On either of those pages, click on the style to display the formula it computes and its coefficients as specified by the associated -bond\_coeff command. +bond_coeff command. ---------- diff --git a/doc/src/bond_hybrid.rst b/doc/src/bond_hybrid.rst index 003790ecd5..74bd39988b 100644 --- a/doc/src/bond_hybrid.rst +++ b/doc/src/bond_hybrid.rst @@ -32,9 +32,9 @@ be computed with a *harmonic* potential. The assignment of bond type to style is made via the :doc:`bond_coeff ` command or in the data file. -In the bond\_coeff commands, the name of a bond style must be added +In the bond_coeff commands, the name of a bond style must be added after the bond type, with the remaining coefficients being those -appropriate to that style. In the example above, the 2 bond\_coeff +appropriate to that style. In the example above, the 2 bond_coeff commands set bonds of bond type 1 to be computed with a *harmonic* potential with coefficients 80.0, 1.2 for :math:`K`, :math:`r_0`. All other bond types (2-N) are computed with a *fene* potential with coefficients 30.0, @@ -54,7 +54,7 @@ line in the "Bond Coeffs" section, e.g. ... A bond style of *none* with no additional coefficients can be used in -place of a bond style, either in a input script bond\_coeff command or +place of a bond style, either in a input script bond_coeff command or in the data file, if you desire to turn off interactions for specific bond types. @@ -69,7 +69,7 @@ info. Unlike other bond styles, the hybrid bond style does not store bond coefficient info for individual sub-styles in a :doc:`binary restart files `. Thus when restarting a simulation from a restart -file, you need to re-specify bond\_coeff commands. +file, you need to re-specify bond_coeff commands. Related commands """""""""""""""" diff --git a/doc/src/bond_mm3.rst b/doc/src/bond_mm3.rst index d86084e01e..8ea79d9139 100644 --- a/doc/src/bond_mm3.rst +++ b/doc/src/bond_mm3.rst @@ -47,7 +47,7 @@ Restrictions """""""""""" This bond style can only be used if LAMMPS was built with the -USER\_YAFF package. See the :doc:`Build package ` doc +USER_YAFF package. See the :doc:`Build package ` doc page for more info. Related commands diff --git a/doc/src/bond_style.rst b/doc/src/bond_style.rst index 65d314c039..52cc761da1 100644 --- a/doc/src/bond_style.rst +++ b/doc/src/bond_style.rst @@ -47,10 +47,10 @@ The coefficients associated with a bond style can be specified in a data or restart file or via the :doc:`bond_coeff ` command. All bond potentials store their coefficient data in binary restart -files which means bond\_style and :doc:`bond_coeff ` commands +files which means bond_style and :doc:`bond_coeff ` commands do not need to be re-specified in an input script that restarts a simulation. See the :doc:`read_restart ` command for -details on how to do this. The one exception is that bond\_style +details on how to do this. The one exception is that bond_style *hybrid* only stores the list of sub-styles in the restart file; bond coefficients need to be re-specified. @@ -71,7 +71,7 @@ the style to display the formula it computes and coefficients specified by the associated :doc:`bond_coeff ` command. Click on the style to display the formula it computes, any additional -arguments specified in the bond\_style command, and coefficients +arguments specified in the bond_style command, and coefficients specified by the associated :doc:`bond_coeff ` command. There are also additional accelerated pair styles included in the diff --git a/doc/src/bond_table.rst b/doc/src/bond_table.rst index a790db595d..445face231 100644 --- a/doc/src/bond_table.rst +++ b/doc/src/bond_table.rst @@ -146,12 +146,12 @@ instructions on how to use the accelerated styles effectively. **Restart info:** -This bond style writes the settings for the "bond\_style table" -command to :doc:`binary restart files `, so a bond\_style +This bond style writes the settings for the "bond_style table" +command to :doc:`binary restart files `, so a bond_style command does not need to specified in an input script that reads a restart file. However, the coefficient information is not stored in the restart file, since it is tabulated in the potential files. Thus, -bond\_coeff commands do need to be specified in the restart input +bond_coeff commands do need to be specified in the restart input script. Restrictions diff --git a/doc/src/bond_zero.rst b/doc/src/bond_zero.rst index 95836a6e1c..42df0472a1 100644 --- a/doc/src/bond_zero.rst +++ b/doc/src/bond_zero.rst @@ -33,7 +33,7 @@ atoms listed in the data file read by the :doc:`read_data ` command. If no bond style is defined, this command cannot be used. The optional *nocoeff* flag allows to read data files with a BondCoeff -section for any bond style. Similarly, any bond\_coeff commands +section for any bond style. Similarly, any bond_coeff commands will only be checked for the bond type number and the rest ignored. Note that the :doc:`bond_coeff ` command must be used for diff --git a/doc/src/change_box.rst b/doc/src/change_box.rst index a3a252baa0..2ab70ddec8 100644 --- a/doc/src/change_box.rst +++ b/doc/src/change_box.rst @@ -102,10 +102,10 @@ new owning processors. .. note:: - This means that you cannot use the change\_box command to enlarge + This means that you cannot use the change_box command to enlarge a shrink-wrapped box, e.g. to make room to insert more atoms via the :doc:`create_atoms ` command, because the simulation box - will be re-shrink-wrapped before the change\_box command completes. + will be re-shrink-wrapped before the change_box command completes. Instead you could do something like this, assuming the simulation box is non-periodic and atoms extend from 0 to 20 in all dimensions: @@ -120,7 +120,7 @@ new owning processors. .. note:: - Unlike the earlier "displace\_box" version of this command, atom + Unlike the earlier "displace_box" version of this command, atom remapping is NOT performed by default. This command allows remapping to be done in a more general way, exactly when you specify it (zero or more times) in the sequence of transformations. Thus if you do not @@ -280,7 +280,7 @@ command. This command allows the boundary conditions to be changed later in your input script. Also note that the :doc:`read_restart ` will change boundary conditions to match what is stored in the restart file. So if you wish to change -them, you should use the change\_box command after the read\_restart +them, you should use the change_box command after the read_restart command. ---------- @@ -308,7 +308,7 @@ useful if you wish to use the *remap* keyword more than once or if you wish it to be applied to an intermediate box size/shape in a sequence of keyword operations. Note that the box size/shape is saved before any of the keywords are processed, i.e. the box size/shape at the time -the create\_box command is encountered in the input script. +the create_box command is encountered in the input script. The *remap* keyword remaps atom coordinates from the last saved box size/shape to the current box state. For example, if you stretch the @@ -343,7 +343,7 @@ the input script when this command is issued, no :doc:`dumps ` can be active, nor can a :doc:`fix deform ` be active. This is because these commands test whether the simulation box is orthogonal when they are first issued. Note that these commands can be used in -your script before a change\_box command is issued, so long as an +your script before a change_box command is issued, so long as an :doc:`undump ` or :doc:`unfix ` command is also used to turn them off. diff --git a/doc/src/comm_modify.rst b/doc/src/comm_modify.rst index 8f745c88b1..9a2ae60f1e 100644 --- a/doc/src/comm_modify.rst +++ b/doc/src/comm_modify.rst @@ -49,9 +49,9 @@ processors and stored as properties of ghost atoms. you specify a :doc:`comm_style ` or :doc:`read_restart ` command, all communication settings are restored to their default or stored values, including those - previously reset by a comm\_modify command. Thus if your input script - specifies a comm\_style or read\_restart command, you should use the - comm\_modify command after it. + previously reset by a comm_modify command. Thus if your input script + specifies a comm_style or read_restart command, you should use the + comm_modify command after it. The *mode* keyword determines whether a single or multiple cutoff distances are used to determine which atoms to communicate. @@ -82,7 +82,7 @@ printed. Specifying a cutoff value of 0.0 will reset any previous value to the default. If bonded interactions exist and equilibrium bond length information is available, then also a heuristic based on that bond length is computed. It is used as communication cutoff, if there is no pair -style present and no *comm\_modify cutoff* command used. Otherwise a +style present and no *comm_modify cutoff* command used. Otherwise a warning is printed, if this bond based estimate is larger than the communication cutoff used. A diff --git a/doc/src/compute.rst b/doc/src/compute.rst index 3dd079500f..0726a502bc 100644 --- a/doc/src/compute.rst +++ b/doc/src/compute.rst @@ -72,11 +72,11 @@ discussed below, it can be referenced via the following bracket notation, where ID is the ID of the compute: +-------------+--------------------------------------------+ -| c\_ID | entire scalar, vector, or array | +| c_ID | entire scalar, vector, or array | +-------------+--------------------------------------------+ -| c\_ID[I] | one element of vector, one column of array | +| c_ID[I] | one element of vector, one column of array | +-------------+--------------------------------------------+ -| c\_ID[I][J] | one element of array | +| c_ID[I][J] | one element of array | +-------------+--------------------------------------------+ In other words, using one bracket reduces the dimension of the @@ -88,7 +88,7 @@ vector or array. Note that commands and :doc:`variables ` which use compute quantities typically do not allow for all kinds, e.g. a command may require a vector of values, not a scalar. This means there is no -ambiguity about referring to a compute quantity as c\_ID even if it +ambiguity about referring to a compute quantity as c_ID even if it produces, for example, both a scalar and vector. The doc pages for various commands explain the details. @@ -116,7 +116,7 @@ e.g. temperature. Extensive means the value scales with the number of atoms in the simulation, e.g. total rotational kinetic energy. :doc:`Thermodynamic output ` will normalize extensive values by the number of atoms in the system, depending on the -"thermo\_modify norm" setting. It will not normalize intensive values. +"thermo_modify norm" setting. It will not normalize intensive values. If a compute value is accessed in another way, e.g. by a :doc:`variable `, you may want to know whether it is an intensive or extensive value. See the doc page for individual @@ -125,8 +125,8 @@ computes for further info. ---------- LAMMPS creates its own computes internally for thermodynamic output. -Three computes are always created, named "thermo\_temp", -"thermo\_press", and "thermo\_pe", as if these commands had been invoked +Three computes are always created, named "thermo_temp", +"thermo_press", and "thermo_pe", as if these commands had been invoked in the input script: .. code-block:: LAMMPS diff --git a/doc/src/compute_adf.rst b/doc/src/compute_adf.rst index 3e1160a43d..c0d754d883 100644 --- a/doc/src/compute_adf.rst +++ b/doc/src/compute_adf.rst @@ -64,7 +64,7 @@ neighbor atom in each requested ADF. those pairs will not be included in the ADF. This does not apply when using long-range coulomb interactions (\ *coul/long*\ , *coul/msm*\ , *coul/wolf* or similar. One way to get around this would be to set - special\_bond scaling factors to very tiny numbers that are not exactly + special_bond scaling factors to very tiny numbers that are not exactly zero (e.g. 1.0e-50). Another workaround is to write a dump file, and use the :doc:`rerun ` command to compute the ADF for snapshots in the dump file. The rerun script can use a @@ -106,7 +106,7 @@ in the range of types represented by *ktypeN*\ . If no *itypeN*\ , *jtypeN*\ , *ktypeN* settings are specified, then LAMMPS will generate a single ADF for all atoms in the group. The inner cutoff is set to zero and the outer cutoff is set -to the force cutoff. If no pair\_style is specified, there is no +to the force cutoff. If no pair_style is specified, there is no force cutoff and LAMMPS will give an error message. Note that in most cases, generating an ADF for all atoms is not a good thing. Such an ADF is both uninformative and diff --git a/doc/src/compute_angle.rst b/doc/src/compute_angle.rst index 666045466f..60f929197c 100644 --- a/doc/src/compute_angle.rst +++ b/doc/src/compute_angle.rst @@ -24,8 +24,8 @@ Description """"""""""" Define a computation that extracts the angle energy calculated by each -of the angle sub-styles used in the "angle\_style -hybrid" angle\_hybrid.html command. These values are made accessible +of the angle sub-styles used in the "angle_style +hybrid" angle_hybrid.html command. These values are made accessible for output or further processing by other commands. The group specified for this command is ignored. @@ -35,7 +35,7 @@ energy contributed by one or more of the hybrid sub-styles. **Output info:** This compute calculates a global vector of length N where N is the -number of sub\_styles defined by the :doc:`angle_style hybrid ` command, which can be accessed by indices +number of sub_styles defined by the :doc:`angle_style hybrid ` command, which can be accessed by indices 1-N. These values can be used by any command that uses global scalar or vector values from a compute as input. See the :doc:`Howto output ` doc page for an overview of LAMMPS output options. diff --git a/doc/src/compute_angle_local.rst b/doc/src/compute_angle_local.rst index 24a0a999fb..fe0af199e2 100644 --- a/doc/src/compute_angle_local.rst +++ b/doc/src/compute_angle_local.rst @@ -13,7 +13,7 @@ Syntax * ID, group-ID are documented in :doc:`compute ` command * angle/local = style name of this compute command * one or more values may be appended -* value = *theta* or *eng* or *v\_name* +* value = *theta* or *eng* or *v_name* .. parsed-literal:: @@ -51,9 +51,9 @@ The value *theta* is the angle for the 3 atoms in the interaction. The value *eng* is the interaction energy for the angle. -The value *v\_name* can be used together with the *set* keyword to +The value *v_name* can be used together with the *set* keyword to compute a user-specified function of the angle theta. The *name* -specified for the *v\_name* value is the name of an :doc:`equal-style variable ` which should evaluate a formula based on a +specified for the *v_name* value is the name of an :doc:`equal-style variable ` which should evaluate a formula based on a variable which will store the angle theta. This other variable must be an :doc:`internal-style variable ` defined in the input script; its initial numeric value can be anything. It must be an diff --git a/doc/src/compute_body_local.rst b/doc/src/compute_body_local.rst index 08da63aacc..395a8ebf91 100644 --- a/doc/src/compute_body_local.rst +++ b/doc/src/compute_body_local.rst @@ -61,7 +61,7 @@ group. For a body particle, the *integer* keywords refer to fields calculated by the body style for each sub-particle. The body style, as specified by the :doc:`atom_style body `, determines how many fields -exist and what they are. See the :doc:`Howto\_body ` doc +exist and what they are. See the :doc:`Howto_body ` doc page for details of the different styles. Here is an example of how to output body information using the :doc:`dump local ` command with this compute. If fields 1,2,3 for the diff --git a/doc/src/compute_bond.rst b/doc/src/compute_bond.rst index bf11d0ceda..59ac05630a 100644 --- a/doc/src/compute_bond.rst +++ b/doc/src/compute_bond.rst @@ -35,7 +35,7 @@ or more of the hybrid sub-styles. **Output info:** This compute calculates a global vector of length N where N is the -number of sub\_styles defined by the :doc:`bond_style hybrid ` command, which can be accessed by indices 1-N. +number of sub_styles defined by the :doc:`bond_style hybrid ` command, which can be accessed by indices 1-N. These values can be used by any command that uses global scalar or vector values from a compute as input. See the :doc:`Howto output ` doc page for an overview of LAMMPS output options. diff --git a/doc/src/compute_bond_local.rst b/doc/src/compute_bond_local.rst index 0d4c7efd29..32d756d52a 100644 --- a/doc/src/compute_bond_local.rst +++ b/doc/src/compute_bond_local.rst @@ -13,7 +13,7 @@ Syntax * ID, group-ID are documented in :doc:`compute ` command * bond/local = style name of this compute command * one or more values may be appended -* value = *dist* or *engpot* or *force* or *fx* or *fy* or *fz* or *engvib* or *engrot* or *engtrans* or *omega* or *velvib* or *v\_name* +* value = *dist* or *engpot* or *force* or *fx* or *fy* or *fz* or *engvib* or *engrot* or *engtrans* or *omega* or *velvib* or *v_name* .. parsed-literal:: @@ -106,9 +106,9 @@ two atoms in the bond towards each other. A negative value means the 2 atoms are moving toward each other; a positive value means they are moving apart. -The value *v\_name* can be used together with the *set* keyword to +The value *v_name* can be used together with the *set* keyword to compute a user-specified function of the bond distance. The *name* -specified for the *v\_name* value is the name of an :doc:`equal-style variable ` which should evaluate a formula based on a +specified for the *v_name* value is the name of an :doc:`equal-style variable ` which should evaluate a formula based on a variable which will store the bond distance. This other variable must be an :doc:`internal-style variable ` defined in the input script; its initial numeric value can be anything. It must be an diff --git a/doc/src/compute_chunk_atom.rst b/doc/src/compute_chunk_atom.rst index ead17e3f7c..aa404fd4da 100644 --- a/doc/src/compute_chunk_atom.rst +++ b/doc/src/compute_chunk_atom.rst @@ -270,14 +270,14 @@ chunk ID to the atom. *Nchunk* is set to the largest chunk ID. Note that this excludes atoms which are not in the specified group or optional region. -If the style begins with "c\_", a compute ID must follow which has been +If the style begins with "c_", a compute ID must follow which has been previously defined in the input script. If no bracketed integer is appended, the per-atom vector calculated by the compute is used. If a bracketed integer is appended, the Ith column of the per-atom array calculated by the compute is used. Users can also write code for their own compute styles and :doc:`add them to LAMMPS `. -If the style begins with "f\_", a fix ID must follow which has been +If the style begins with "f_", a fix ID must follow which has been previously defined in the input script. If no bracketed integer is appended, the per-atom vector calculated by the fix is used. If a bracketed integer is appended, the Ith column of the per-atom array @@ -286,7 +286,7 @@ their values on certain timesteps, which must be compatible with the timestep on which this compute accesses the fix, else an error results. Users can also write code for their own fix styles and :doc:`add them to LAMMPS `. -If a value begins with "v\_", a variable name for an *atom* or +If a value begins with "v_", a variable name for an *atom* or *atomfile* style :doc:`variable ` must follow which has been previously defined in the input script. Variables of style *atom* can reference thermodynamic keywords and various per-atom attributes, or diff --git a/doc/src/compute_chunk_spread_atom.rst b/doc/src/compute_chunk_spread_atom.rst index a00d407d70..d486da4e3e 100644 --- a/doc/src/compute_chunk_spread_atom.rst +++ b/doc/src/compute_chunk_spread_atom.rst @@ -14,7 +14,7 @@ Syntax * chunk/spread/atom = style name of this compute command * chunkID = ID of :doc:`compute chunk/atom ` command * one or more inputs can be listed -* input = c\_ID, c\_ID[N], f\_ID, f\_ID[N] +* input = c_ID, c_ID[N], f_ID, f_ID[N] .. parsed-literal:: diff --git a/doc/src/compute_cluster_atom.rst b/doc/src/compute_cluster_atom.rst index ff84ed686a..d9742a4a4b 100644 --- a/doc/src/compute_cluster_atom.rst +++ b/doc/src/compute_cluster_atom.rst @@ -82,7 +82,7 @@ multiple compute/dump commands, each of a *cluster/atom* or those pairs will not be included when computing the clusters. This does not apply when using long-range coulomb (\ *coul/long*\ , *coul/msm*\ , *coul/wolf* or similar. One way to get around this would be to set - special\_bond scaling factors to very tiny numbers that are not exactly + special_bond scaling factors to very tiny numbers that are not exactly zero (e.g. 1.0e-50). Another workaround is to write a dump file, and use the :doc:`rerun ` command to compute the clusters for snapshots in the dump file. The rerun script can use a diff --git a/doc/src/compute_coord_atom.rst b/doc/src/compute_coord_atom.rst index ff2ee2fa92..c51ea212f0 100644 --- a/doc/src/compute_coord_atom.rst +++ b/doc/src/compute_coord_atom.rst @@ -78,10 +78,10 @@ identify crystal-like atoms in a system, as discussed in :ref:`ten Wolde ` command is specified as *orientorderID*\ . The compute must invoke its *components* option to -calculate components of the *Ybar\_lm* vector for each atoms, as +calculate components of the *Ybar_lm* vector for each atoms, as described in its documentation. Note that orientorder/atom compute defines its own criteria for identifying neighboring atoms. If the -scalar product (*Ybar\_lm(i)*,*Ybar\_lm(j)*), calculated by the +scalar product (*Ybar_lm(i)*,*Ybar_lm(j)*), calculated by the orientorder/atom compute is larger than the specified *threshold*\ , then I and J are connected, and the coordination value of I is incremented by one. diff --git a/doc/src/compute_dihedral.rst b/doc/src/compute_dihedral.rst index 135c2d6365..ed87b727ec 100644 --- a/doc/src/compute_dihedral.rst +++ b/doc/src/compute_dihedral.rst @@ -34,7 +34,7 @@ total energy contributed by one or more of the hybrid sub-styles. **Output info:** This compute calculates a global vector of length N where N is the -number of sub\_styles defined by the :doc:`dihedral_style hybrid ` command. which can be accessed by indices +number of sub_styles defined by the :doc:`dihedral_style hybrid ` command. which can be accessed by indices 1-N. These values can be used by any command that uses global scalar or vector values from a compute as input. See the :doc:`Howto output ` doc page for an overview of LAMMPS output options. diff --git a/doc/src/compute_dihedral_local.rst b/doc/src/compute_dihedral_local.rst index 2f998e1138..6fd1401292 100644 --- a/doc/src/compute_dihedral_local.rst +++ b/doc/src/compute_dihedral_local.rst @@ -13,7 +13,7 @@ Syntax * ID, group-ID are documented in :doc:`compute ` command * dihedral/local = style name of this compute command * one or more values may be appended -* value = *phi* or *v\_name* +* value = *phi* or *v_name* .. parsed-literal:: @@ -49,9 +49,9 @@ by the group parameter as explained below. The value *phi* is the dihedral angle, as defined in the diagram on the :doc:`dihedral_style ` doc page. -The value *v\_name* can be used together with the *set* keyword to +The value *v_name* can be used together with the *set* keyword to compute a user-specified function of the dihedral angle phi. The -*name* specified for the *v\_name* value is the name of an :doc:`equal-style variable ` which should evaluate a formula based on a +*name* specified for the *v_name* value is the name of an :doc:`equal-style variable ` which should evaluate a formula based on a variable which will store the angle phi. This other variable must be an :doc:`internal-style variable ` defined in the input script; its initial numeric value can be anything. It must be an diff --git a/doc/src/compute_displace_atom.rst b/doc/src/compute_displace_atom.rst index 5d208823d7..9e1488cdf1 100644 --- a/doc/src/compute_displace_atom.rst +++ b/doc/src/compute_displace_atom.rst @@ -63,7 +63,7 @@ the compute command was issued. The value of the displacement will be ---------- -The *refresh* option can be used in conjunction with the "dump\_modify +The *refresh* option can be used in conjunction with the "dump_modify refresh" command to generate incremental dump files. The definition and motivation of an incremental dump file is as @@ -95,11 +95,11 @@ something like the following commands: The :doc:`dump_modify thresh ` command will only output atoms that have displaced more than 0.6 Angstroms on each snapshot -(assuming metal units). The dump\_modify *refresh* option triggers a +(assuming metal units). The dump_modify *refresh* option triggers a call to this compute at the end of every dump. The *refresh* argument for this compute is the ID of an :doc:`atom-style variable ` which calculates a Boolean value (0 or 1) -based on the same criterion used by dump\_modify thresh. This compute +based on the same criterion used by dump_modify thresh. This compute evaluates the atom-style variable. For each atom that returns 1 (true), the original (reference) coordinates of the atom (stored by this compute) are updated. @@ -112,7 +112,7 @@ Note that in the first snapshot of a subsequent run, no atoms will be typically be output. That is because the initial displacement for all atoms is 0.0. If an initial dump snapshot is desired, containing the initial reference positions of all atoms, one way to do this is -illustrated above. An initial write\_dump command can be used before +illustrated above. An initial write_dump command can be used before the first run. It will contain the positions of all the atoms, Options in the :doc:`dump_modify ` command above will append new output to that same file and delay the output until a later diff --git a/doc/src/compute_fep.rst b/doc/src/compute_fep.rst index a7d64caa98..4700817609 100644 --- a/doc/src/compute_fep.rst +++ b/doc/src/compute_fep.rst @@ -241,9 +241,9 @@ used, then the *pstyle* will be a sub-style name. You must specify I,J arguments that correspond to type pair values defined (via the :doc:`pair_coeff ` command) for that sub-style. -The *v\_name* argument for keyword *pair* is the name of an +The *v_name* argument for keyword *pair* is the name of an :doc:`equal-style variable ` which will be evaluated each time -this compute is invoked. It should be specified as v\_name, where name +this compute is invoked. It should be specified as v_name, where name is the variable name. ---------- @@ -254,9 +254,9 @@ current list of atom parameters that can be used with this compute: * charge = charge on particle -The *v\_name* argument for keyword *pair* is the name of an +The *v_name* argument for keyword *pair* is the name of an :doc:`equal-style variable ` which will be evaluated each time -this compute is invoked. It should be specified as v\_name, where name +this compute is invoked. It should be specified as v_name, where name is the variable name. ---------- @@ -282,10 +282,10 @@ trajectories during which the volume fluctuates or changes :ref:`(Allen and Tild **Output info:** This compute calculates a global vector of length 3 which contains the -energy difference ( :math:`U_1-U_0` ) as c\_ID[1], the +energy difference ( :math:`U_1-U_0` ) as c_ID[1], the Boltzmann factor :math:`\exp(-(U_1-U_0)/kT)`, or -:math:`V \exp(-(U_1-U_0)/kT)`, as c\_ID[2] and the -volume of the simulation box :math:`V` as c\_ID[3]. :math:`U_1` is the +:math:`V \exp(-(U_1-U_0)/kT)`, as c_ID[2] and the +volume of the simulation box :math:`V` as c_ID[3]. :math:`U_1` is the pair potential energy obtained with the perturbed parameters and :math:`U_0` is the pair potential energy obtained with the unperturbed parameters. The energies include kspace terms if these diff --git a/doc/src/compute_global_atom.rst b/doc/src/compute_global_atom.rst index ae6ca73a36..1b301f700e 100644 --- a/doc/src/compute_global_atom.rst +++ b/doc/src/compute_global_atom.rst @@ -12,7 +12,7 @@ Syntax * ID, group-ID are documented in :doc:`compute ` command * global/atom = style name of this compute command -* index = c\_ID, c\_ID[N], f\_ID, f\_ID[N], v\_name +* index = c_ID, c_ID[N], f_ID, f_ID[N], v_name .. parsed-literal:: @@ -23,7 +23,7 @@ Syntax v_name = per-atom vector calculated by an atom-style variable with name * one or more inputs can be listed -* input = c\_ID, c\_ID[N], f\_ID, f\_ID[N], v\_name +* input = c_ID, c_ID[N], f_ID, f_ID[N], v_name .. parsed-literal:: @@ -133,7 +133,7 @@ simple rounded down to convert the value to integer indices. The final values should range from 1 to N (inclusive), since they are used to access values from N-length vectors. -If *index* begins with "c\_", a compute ID must follow which has been +If *index* begins with "c_", a compute ID must follow which has been previously defined in the input script. The compute must generate per-atom quantities. See the individual :doc:`compute ` doc page for details. If no bracketed integer is appended, the per-atom @@ -144,7 +144,7 @@ styles and :doc:`add them to LAMMPS `. See the discussion above for how I can be specified with a wildcard asterisk to effectively specify multiple values. -If *index* begins with "f\_", a fix ID must follow which has been +If *index* begins with "f_", a fix ID must follow which has been previously defined in the input script. The Fix must generate per-atom quantities. See the individual :doc:`fix ` doc page for details. Note that some fixes only produce their values on certain @@ -157,7 +157,7 @@ own fix style and :doc:`add them to LAMMPS `. See the discussion above for how I can be specified with a wildcard asterisk to effectively specify multiple values. -If *index* begins with "v\_", a variable name must follow which has +If *index* begins with "v_", a variable name must follow which has been previously defined in the input script. It must be an :doc:`atom-style variable `. Atom-style variables can reference thermodynamic keywords and various per-atom attributes, or @@ -171,7 +171,7 @@ This section explains the kinds of *input* values that can be used. Note that inputs reference global values, as contrasted with the *index* parameter which must reference per-atom values. -If a value begins with "c\_", a compute ID must follow which has been +If a value begins with "c_", a compute ID must follow which has been previously defined in the input script. The compute must generate a global vector or array. See the individual :doc:`compute ` doc page for details. If no bracketed integer is appended, the vector @@ -181,7 +181,7 @@ used. Users can also write code for their own compute styles and :doc:`add them I can be specified with a wildcard asterisk to effectively specify multiple values. -If a value begins with "f\_", a fix ID must follow which has been +If a value begins with "f_", a fix ID must follow which has been previously defined in the input script. The fix must generate a global vector or array. See the individual :doc:`fix ` doc page for details. Note that some fixes only produce their values on @@ -194,7 +194,7 @@ own fix style and :doc:`add them to LAMMPS `. See the discussion above for how I can be specified with a wildcard asterisk to effectively specify multiple values. -If a value begins with "v\_", a variable name must follow which has +If a value begins with "v_", a variable name must follow which has been previously defined in the input script. It must be a :doc:`vector-style variable `. Vector-style variables can reference thermodynamic keywords and various other attributes of diff --git a/doc/src/compute_group_group.rst b/doc/src/compute_group_group.rst index f0b65c797a..ba29090d5e 100644 --- a/doc/src/compute_group_group.rst +++ b/doc/src/compute_group_group.rst @@ -109,7 +109,7 @@ frequently. means those pairs will not be included in the group/group interaction. This does not apply when using long-range coulomb interactions (\ *coul/long*\ , *coul/msm*\ , *coul/wolf* or similar. One way to get - around this would be to set special\_bond scaling factors to very tiny + around this would be to set special_bond scaling factors to very tiny numbers that are not exactly zero (e.g. 1.0e-50). Another workaround is to write a dump file, and use the :doc:`rerun ` command to compute the group/group interactions for snapshots in the dump file. diff --git a/doc/src/compute_hma.rst b/doc/src/compute_hma.rst index 20807ec0db..e00fdde841 100644 --- a/doc/src/compute_hma.rst +++ b/doc/src/compute_hma.rst @@ -58,12 +58,12 @@ summation should work fine, while :doc:`pair_style lj/cut ` will perform poorly unless the potential is shifted (via :doc:`pair_modify ` shift) or the cutoff is large. Furthermore, computation of the heat capacity with this compute is -restricted to those that implement the *single\_hessian* method in Pair. -Implementing *single\_hessian* in additional pair styles is simple. +restricted to those that implement the *single_hessian* method in Pair. +Implementing *single_hessian* in additional pair styles is simple. Please contact Andrew Schultz (ajs42 at buffalo.edu) and David Kofke (kofke at buffalo.edu) if your desired pair style does not have this method. This is the list of pair styles that currently implement -*single\_hessian*: +*single_hessian*: * :doc:`pair_style lj/smooth/linear ` @@ -179,7 +179,7 @@ Related commands :doc:`compute pe `, :doc:`compute pressure ` :doc:`dynamical matrix ` provides a finite difference -formulation of the hessian provided by Pair's single\_hessian, which is used by +formulation of the hessian provided by Pair's single_hessian, which is used by this compute. **Default:** none diff --git a/doc/src/compute_improper.rst b/doc/src/compute_improper.rst index bb4b150c6a..0a264a74e7 100644 --- a/doc/src/compute_improper.rst +++ b/doc/src/compute_improper.rst @@ -34,7 +34,7 @@ total energy contributed by one or more of the hybrid sub-styles. **Output info:** This compute calculates a global vector of length N where N is the -number of sub\_styles defined by the :doc:`improper_style hybrid ` command. which can be accessed by indices +number of sub_styles defined by the :doc:`improper_style hybrid ` command. which can be accessed by indices 1-N. These values can be used by any command that uses global scalar or vector values from a compute as input. See the :doc:`Howto output ` doc page for an overview of LAMMPS output options. diff --git a/doc/src/compute_ke_eff.rst b/doc/src/compute_ke_eff.rst index dddb5273f8..f1cffebc56 100644 --- a/doc/src/compute_ke_eff.rst +++ b/doc/src/compute_ke_eff.rst @@ -43,7 +43,7 @@ energy, calculated by the simple formula above. For thermodynamic output, the *ke* keyword infers kinetic energy from the temperature of the system with :math:`\frac{1}{2} k_B T` of energy for each degree of freedom. For the eFF temperature computation via the :doc:`compute -temp\_eff ` command, these are the same. But +temp_eff ` command, these are the same. But different computes that calculate temperature can subtract out different non-thermal components of velocity and/or include other degrees of freedom. diff --git a/doc/src/compute_meso_t_atom.rst b/doc/src/compute_meso_t_atom.rst index 9f5385dd48..e44425a65c 100644 --- a/doc/src/compute_meso_t_atom.rst +++ b/doc/src/compute_meso_t_atom.rst @@ -30,7 +30,9 @@ The internal temperature is the ratio of internal energy over the heat capacity associated with the internal degrees of freedom of a mesoscopic particles, e.g. a Smooth-Particle Hydrodynamics particle. -T\_\ *int* = E\_\ *int* / C\_\ *V, int* +.. math:: + + T_{int} = E_{int} / C_{V,int} See `this PDF guide `_ to using SPH in LAMMPS. diff --git a/doc/src/compute_msd.rst b/doc/src/compute_msd.rst index 05a414a0d5..94ab6a1579 100644 --- a/doc/src/compute_msd.rst +++ b/doc/src/compute_msd.rst @@ -112,7 +112,7 @@ Restrictions Related commands """""""""""""""" -:doc:`compute msd/nongauss `, :doc:`compute displace\_atom `, :doc:`fix store/state `, :doc:`compute msd/chunk ` +:doc:`compute msd/nongauss `, :doc:`compute displace_atom `, :doc:`fix store/state `, :doc:`compute msd/chunk ` Default """"""" diff --git a/doc/src/compute_orientorder_atom.rst b/doc/src/compute_orientorder_atom.rst index c651804f0a..7b894b886e 100644 --- a/doc/src/compute_orientorder_atom.rst +++ b/doc/src/compute_orientorder_atom.rst @@ -100,7 +100,7 @@ can be reproduced with this keyword. The optional keyword *components* will output the components of the normalized complex vector :math:`\bar{Y}_{lm}` of degree *ldegree*\ , which must be explicitly included in the keyword *degrees*\ . This option can be used -in conjunction with :doc:`compute coord\_atom ` to +in conjunction with :doc:`compute coord_atom ` to calculate the ten Wolde's criterion to identify crystal-like particles, as discussed in :ref:`ten Wolde `. diff --git a/doc/src/compute_pe.rst b/doc/src/compute_pe.rst index 2efaf78b01..813b577490 100644 --- a/doc/src/compute_pe.rst +++ b/doc/src/compute_pe.rst @@ -54,14 +54,14 @@ potential energy. The :doc:`fix_modify energy yes ` command must also be specified if a fix is to contribute potential energy to this command. -A compute of this style with the ID of "thermo\_pe" is created when +A compute of this style with the ID of "thermo_pe" is created when LAMMPS starts up, as if this command were in the input script: .. code-block:: LAMMPS compute thermo_pe all pe -See the "thermo\_style" command for more details. +See the "thermo_style" command for more details. ---------- diff --git a/doc/src/compute_plasticity_atom.rst b/doc/src/compute_plasticity_atom.rst index 9d8dea535d..939017f5e9 100644 --- a/doc/src/compute_plasticity_atom.rst +++ b/doc/src/compute_plasticity_atom.rst @@ -31,7 +31,7 @@ The plasticity for a Peridynamic particle is the so-called consistency parameter (lambda). For elastic deformation lambda = 0, otherwise lambda > 0 for plastic deformation. For details, see :ref:`(Mitchell) ` and the PDF doc included in the LAMMPS -distribution in `doc/PDF/PDLammps\_EPS.pdf `_. +distribution in `doc/PDF/PDLammps_EPS.pdf `_. This command can be invoked for one of the Peridynamic :doc:`pair styles `: peri/eps. diff --git a/doc/src/compute_pressure.rst b/doc/src/compute_pressure.rst index 402613d504..7366fa6d3d 100644 --- a/doc/src/compute_pressure.rst +++ b/doc/src/compute_pressure.rst @@ -100,15 +100,15 @@ Also note that the N in the first formula above is really degrees-of-freedom divided by d = dimensionality, where the DOF value is calculated by the temperature compute. See the various :doc:`compute temperature ` styles for details. -A compute of this style with the ID of "thermo\_press" is created when +A compute of this style with the ID of "thermo_press" is created when LAMMPS starts up, as if this command were in the input script: .. code-block:: LAMMPS compute thermo_press all pressure thermo_temp -where "thermo\_temp" is the ID of a similarly defined compute of style -"temp". See the "thermo\_style" command for more details. +where "thermo_temp" is the ID of a similarly defined compute of style +"temp". See the "thermo_style" command for more details. ---------- diff --git a/doc/src/compute_pressure_cylinder.rst b/doc/src/compute_pressure_cylinder.rst index b3e7accb37..104e68d533 100644 --- a/doc/src/compute_pressure_cylinder.rst +++ b/doc/src/compute_pressure_cylinder.rst @@ -15,7 +15,7 @@ Syntax * zlo = minimum z-boundary for cylinder * zhi = maximum z-boundary for cylinder * Rmax = maximum radius to perform calculation to -* bin\_width = width of radial bins to use for calculation +* bin_width = width of radial bins to use for calculation Examples """""""" @@ -31,19 +31,19 @@ Define a computation that calculates the pressure tensor of a system in cylindrical coordinates, as discussed in :ref:`(Addington) `. This is useful for systems with a single axis of rotational symmetry, such as cylindrical micelles or carbon nanotubes. The compute splits the -system into radial, cylindrical-shell-type bins of width bin\_width, -centered at x=0,y=0, and calculates the radial (P\_rhorho), azimuthal -(P\_phiphi), and axial (P\_zz) components of the configurational pressure +system into radial, cylindrical-shell-type bins of width bin_width, +centered at x=0,y=0, and calculates the radial (P_rhorho), azimuthal +(P_phiphi), and axial (P_zz) components of the configurational pressure tensor. The local density is also calculated for each bin, so that the -true pressure can be recovered as P\_kin+P\_conf=density\*k\*T+P\_conf. The +true pressure can be recovered as P_kin+P_conf=density\*k\*T+P_conf. The output is a global array with 5 columns; one each for bin radius, local -number density, P\_rhorho, P\_phiphi, and P\_zz. The number of rows is -governed by the values of Rmax and bin\_width. Pressure tensor values are +number density, P_rhorho, P_phiphi, and P_zz. The number of rows is +governed by the values of Rmax and bin_width. Pressure tensor values are output in pressure units. **Output info:** -This compute calculates a global array with 5 columns and Rmax/bin\_width +This compute calculates a global array with 5 columns and Rmax/bin_width rows. The output columns are: R (distance units), number density (inverse volume units), configurational radial pressure (pressure units), configurational azimuthal pressure (pressure units), and configurational @@ -64,7 +64,7 @@ due to exclusions for special bonds) and requires pair-wise force calculations not available for most many-body pair styles. K-space calculations are also excluded. Note that this pressure compute outputs the configurational terms only; the kinetic contribution is not included -and may be calculated from the number density output by P\_kin=density\*k\*T. +and may be calculated from the number density output by P_kin=density\*k\*T. This compute is part of the USER-MISC package. It is only enabled if LAMMPS was built with that package. See the :doc:`Build package ` doc page for more info. diff --git a/doc/src/compute_property_atom.rst b/doc/src/compute_property_atom.rst index 23dd8806d9..1643be8699 100644 --- a/doc/src/compute_property_atom.rst +++ b/doc/src/compute_property_atom.rst @@ -147,11 +147,11 @@ two atoms in the bond. Thus a bond between atoms I,J may be tallied for either atom I or atom J. If :doc:`newton bond off ` is set, it will be tallied with both atom I and atom J. -The *i\_name* and *d\_name* attributes refer to custom integer and +The *i_name* and *d_name* attributes refer to custom integer and floating-point properties that have been added to each atom via the :doc:`fix property/atom ` command. When that command is used specific names are given to each attribute which are what is -specified as the "name" portion of *i\_name* or *d\_name*. +specified as the "name" portion of *i_name* or *d_name*. **Output info:** diff --git a/doc/src/compute_ptm_atom.rst b/doc/src/compute_ptm_atom.rst index 3fac1d8810..112ed1ea6a 100644 --- a/doc/src/compute_ptm_atom.rst +++ b/doc/src/compute_ptm_atom.rst @@ -105,7 +105,7 @@ The type is a number from -1 to 8. The rmsd is a positive real number. The interatomic distance is computed from the scale factor in the RMSD equation. The (qw,qx,qy,qz) parameters represent the orientation of the local structure in quaternion form. The reference coordinates for each template (from which the -orientation is determined) can be found in the *ptm\_constants.h* file in the PTM source directory. +orientation is determined) can be found in the *ptm_constants.h* file in the PTM source directory. For atoms that are not within the compute group-ID, all values are set to zero. Restrictions diff --git a/doc/src/compute_rdf.rst b/doc/src/compute_rdf.rst index c977e2ac12..5f426ffb51 100644 --- a/doc/src/compute_rdf.rst +++ b/doc/src/compute_rdf.rst @@ -57,7 +57,7 @@ shell of distances in 3d and a thin ring of distances in 2d. those pairs will not be included in the RDF. This does not apply when using long-range coulomb interactions (\ *coul/long*\ , *coul/msm*\ , *coul/wolf* or similar. One way to get around this would be to set - special\_bond scaling factors to very tiny numbers that are not exactly + special_bond scaling factors to very tiny numbers that are not exactly zero (e.g. 1.0e-50). Another workaround is to write a dump file, and use the :doc:`rerun ` command to compute the RDF for snapshots in the dump file. The rerun script can use a @@ -74,7 +74,7 @@ distance specified. Normally, you should only use the *cutoff* keyword if no pair style is defined, e.g. the :doc:`rerun ` command is being used to post-process a dump file of snapshots. Or if you really want the RDF - for distances beyond the pair\_style force cutoff and cannot easily + for distances beyond the pair_style force cutoff and cannot easily post-process a dump file to calculate it. This is because using the *cutoff* keyword incurs extra computation and possibly communication, which may slow down your simulation. If you specify a *Rcut* <= force diff --git a/doc/src/compute_reduce.rst b/doc/src/compute_reduce.rst index 3772a788e0..3391f3c3cb 100644 --- a/doc/src/compute_reduce.rst +++ b/doc/src/compute_reduce.rst @@ -24,7 +24,7 @@ Syntax * mode = *sum* or *min* or *max* or *ave* or *sumsq* or *avesq* * one or more inputs can be listed -* input = x, y, z, vx, vy, vz, fx, fy, fz, c\_ID, c\_ID[N], f\_ID, f\_ID[N], v\_name +* input = x, y, z, vx, vy, vz, fx, fy, fz, c_ID, c_ID[N], f_ID, f_ID[N], v_name .. parsed-literal:: @@ -122,7 +122,7 @@ self-explanatory. Note that other atom attributes can be used as inputs to this fix by using the :doc:`compute property/atom ` command and then specifying an input value from that compute. -If a value begins with "c\_", a compute ID must follow which has been +If a value begins with "c_", a compute ID must follow which has been previously defined in the input script. Computes can generate per-atom or local quantities. See the individual :doc:`compute ` doc page for details. If no bracketed integer @@ -133,7 +133,7 @@ compute styles and :doc:`add them to LAMMPS `. See the discussion above for how I can be specified with a wildcard asterisk to effectively specify multiple values. -If a value begins with "f\_", a fix ID must follow which has been +If a value begins with "f_", a fix ID must follow which has been previously defined in the input script. Fixes can generate per-atom or local quantities. See the individual :doc:`fix ` doc page for details. Note that some fixes only produce their values on certain @@ -145,7 +145,7 @@ is used. Users can also write code for their own fix style and :doc:`add them t be specified with a wildcard asterisk to effectively specify multiple values. -If a value begins with "v\_", a variable name must follow which has +If a value begins with "v_", a variable name must follow which has been previously defined in the input script. It must be an :doc:`atom-style variable `. Atom-style variables can reference thermodynamic keywords and various per-atom attributes, or diff --git a/doc/src/compute_reduce_chunk.rst b/doc/src/compute_reduce_chunk.rst index 3404613875..34619efd06 100644 --- a/doc/src/compute_reduce_chunk.rst +++ b/doc/src/compute_reduce_chunk.rst @@ -15,7 +15,7 @@ Syntax * chunkID = ID of :doc:`compute chunk/atom ` command * mode = *sum* or *min* or *max* * one or more inputs can be listed -* input = c\_ID, c\_ID[N], f\_ID, f\_ID[N], v\_ID +* input = c_ID, c_ID[N], f_ID, f_ID[N], v_ID .. parsed-literal:: diff --git a/doc/src/compute_saed.rst b/doc/src/compute_saed.rst index ac596962c0..cad4bc1b93 100644 --- a/doc/src/compute_saed.rst +++ b/doc/src/compute_saed.rst @@ -15,7 +15,7 @@ Syntax * lambda = wavelength of incident radiation (length units) * type1 type2 ... typeN = chemical symbol of each atom type (see valid options below) * zero or more keyword/value pairs may be appended -* keyword = *Kmax* or *Zone* or *dR\_Ewald* or *c* or *manual* or *echo* +* keyword = *Kmax* or *Zone* or *dR_Ewald* or *c* or *manual* or *echo* .. parsed-literal:: @@ -90,7 +90,7 @@ unless small spacing parameters <0.05 Angstrom\^(-1) are implemented. Meshes with manual spacing do not require a periodic boundary. The limits of the reciprocal lattice mesh are determined by the use of -the *Kmax*\ , *Zone*\ , and *dR\_Ewald* parameters. The rectilinear mesh +the *Kmax*\ , *Zone*\ , and *dR_Ewald* parameters. The rectilinear mesh created about the origin of reciprocal space is terminated at the boundary of a sphere of radius *Kmax* centered at the origin. If *Zone* parameters z1=z2=z3=0 are used, diffraction intensities are @@ -99,7 +99,7 @@ greatly increase the cost of computation. Otherwise, *Zone* parameters will denote the z1=h, z2=k, and z3=l (in a global since) zone axis of an intersecting Ewald sphere. Diffraction intensities will only be computed at the intersection of the reciprocal lattice -mesh and a *dR\_Ewald* thick surface of the Ewald sphere. See the +mesh and a *dR_Ewald* thick surface of the Ewald sphere. See the example 3D intensity data and the intersection of a [010] zone axis in the below image. @@ -247,17 +247,17 @@ Restrictions This compute is part of the USER-DIFFRACTION package. It is only enabled if LAMMPS was built with that package. See the :doc:`Build package ` doc page for more info. -The compute\_saed command does not work for triclinic cells. +The compute_saed command does not work for triclinic cells. Related commands """""""""""""""" -:doc:`fix saed\_vtk `, :doc:`compute xrd ` +:doc:`fix saed_vtk `, :doc:`compute xrd ` Default """"""" -The option defaults are Kmax = 1.70, Zone 1 0 0, c 1 1 1, dR\_Ewald = +The option defaults are Kmax = 1.70, Zone 1 0 0, c 1 1 1, dR_Ewald = 0.01. ---------- diff --git a/doc/src/compute_slice.rst b/doc/src/compute_slice.rst index 6667dfd880..7262f2c368 100644 --- a/doc/src/compute_slice.rst +++ b/doc/src/compute_slice.rst @@ -15,7 +15,7 @@ Syntax * Nstart = starting index within input vector(s) * Nstop = stopping index within input vector(s) * Nskip = extract every Nskip elements from input vector(s) -* input = c\_ID, c\_ID[N], f\_ID, f\_ID[N] +* input = c_ID, c_ID[N], f_ID, f_ID[N] .. parsed-literal:: @@ -55,7 +55,7 @@ vector. Each listed input must be a global vector or column of a global array calculated by another :doc:`compute ` or :doc:`fix `. -If an input value begins with "c\_", a compute ID must follow which has +If an input value begins with "c_", a compute ID must follow which has been previously defined in the input script and which generates a global vector or array. See the individual :doc:`compute ` doc page for details. If no bracketed integer is appended, the vector @@ -63,7 +63,7 @@ calculated by the compute is used. If a bracketed integer is appended, the Ith column of the array calculated by the compute is used. Users can also write code for their own compute styles and :doc:`add them to LAMMPS `. -If a value begins with "f\_", a fix ID must follow which has been +If a value begins with "f_", a fix ID must follow which has been previously defined in the input script and which generates a global vector or array. See the individual :doc:`fix ` doc page for details. Note that some fixes only produce their values on certain @@ -73,7 +73,7 @@ appended, the vector calculated by the fix is used. If a bracketed integer is appended, the Ith column of the array calculated by the fix is used. Users can also write code for their own fix style and :doc:`add them to LAMMPS `. -If an input value begins with "v\_", a variable name must follow which +If an input value begins with "v_", a variable name must follow which has been previously defined in the input script. Only vector-style variables can be referenced. See the :doc:`variable ` command for details. Note that variables of style *vector* define a formula diff --git a/doc/src/compute_smd_contact_radius.rst b/doc/src/compute_smd_contact_radius.rst index 4f9e36db7d..01c543af38 100644 --- a/doc/src/compute_smd_contact_radius.rst +++ b/doc/src/compute_smd_contact_radius.rst @@ -27,7 +27,7 @@ Define a computation which outputs the contact radius, i.e., the radius used to prevent particles from penetrating each other. The contact radius is used only to prevent particles belonging to different physical bodies from penetrating each other. It is used by -the contact pair styles, e.g., smd/hertz and smd/tri\_surface. +the contact pair styles, e.g., smd/hertz and smd/tri_surface. See `this PDF guide `_ to using Smooth Mach Dynamics in LAMMPS. @@ -53,6 +53,6 @@ LAMMPS was built with that package. See the :doc:`Build package Related commands """""""""""""""" -:doc:`dump custom ` smd/hertz smd/tri\_surface +:doc:`dump custom ` smd/hertz smd/tri_surface **Default:** none diff --git a/doc/src/compute_smd_damage.rst b/doc/src/compute_smd_damage.rst index eb39c4e452..3f02ac5c74 100644 --- a/doc/src/compute_smd_damage.rst +++ b/doc/src/compute_smd_damage.rst @@ -46,6 +46,6 @@ LAMMPS was built with that package. See the "Build Related commands """""""""""""""" -:doc:`smd/plastic\_strain `, :doc:`smd/tlsph\_stress ` +:doc:`smd/plastic_strain `, :doc:`smd/tlsph_stress ` **Default:** none diff --git a/doc/src/compute_smd_hourglass_error.rst b/doc/src/compute_smd_hourglass_error.rst index 612d4d0aba..56b8a81c01 100644 --- a/doc/src/compute_smd_hourglass_error.rst +++ b/doc/src/compute_smd_hourglass_error.rst @@ -58,7 +58,7 @@ tlsph pair style. **Related Commands:** -:doc:`smd/tlsph\_defgrad ` +:doc:`smd/tlsph_defgrad ` Default """"""" diff --git a/doc/src/compute_smd_triangle_vertices.rst b/doc/src/compute_smd_triangle_vertices.rst index f510ca4bb0..ad33df3ef8 100644 --- a/doc/src/compute_smd_triangle_vertices.rst +++ b/doc/src/compute_smd_triangle_vertices.rst @@ -24,7 +24,7 @@ Description """"""""""" Define a computation that returns the coordinates of the vertices -corresponding to the triangle-elements of a mesh created by the :doc:`fix smd/wall\_surface `. +corresponding to the triangle-elements of a mesh created by the :doc:`fix smd/wall_surface `. See `this PDF guide `_ to using Smooth Mach Dynamics in LAMMPS. @@ -41,10 +41,10 @@ The per-particle vector has nine entries, (x1/y1/z1), (x2/y2/z2), and each triangle. It is only meaningful to use this compute for a group of particles -which is created via the :doc:`fix smd/wall\_surface ` command. +which is created via the :doc:`fix smd/wall_surface ` command. -The output of this compute can be used with the dump2vtk\_tris tool to -generate a VTK representation of the smd/wall\_surface mesh for +The output of this compute can be used with the dump2vtk_tris tool to +generate a VTK representation of the smd/wall_surface mesh for visualization purposes. The values will be given in :doc:`units ` of distance. @@ -59,6 +59,6 @@ Related commands """""""""""""""" :doc:`fix smd/move/tri/surf `, -:doc:`fix smd/wall\_surface ` +:doc:`fix smd/wall_surface ` **Default:** none diff --git a/doc/src/compute_sna_atom.rst b/doc/src/compute_sna_atom.rst index c6ed12d5a8..83e28b913b 100644 --- a/doc/src/compute_sna_atom.rst +++ b/doc/src/compute_sna_atom.rst @@ -27,8 +27,8 @@ Syntax * rcutfac = scale factor applied to all cutoff radii (positive real) * rfac0 = parameter in distance to angle conversion (0 < rcutfac < 1) * twojmax = band limit for bispectrum components (non-negative integer) -* R\_1, R\_2,... = list of cutoff radii, one for each type (distance units) -* w\_1, w\_2,... = list of neighbor weights, one for each type +* R_1, R_2,... = list of cutoff radii, one for each type (distance units) +* w_1, w_2,... = list of neighbor weights, one for each type * zero or more keyword/value pairs may be appended * keyword = *rmin0* or *switchflag* or *bzeroflag* or *quadraticflag* @@ -62,7 +62,7 @@ Define a computation that calculates a set of quantities related to the bispectrum components of the atoms in a group. These computes are used primarily for calculating the dependence of energy, force, and stress components on the linear coefficients in the -:doc:`snap pair\_style `, which is useful when training a +:doc:`snap pair_style `, which is useful when training a SNAP potential to match target data. Bispectrum components of an atom are order parameters characterizing @@ -71,11 +71,11 @@ mathematical definition is given in the paper by Thompson et al. :ref:`(Thompson) ` The position of a neighbor atom *i'* relative to a central atom *i* is -a point within the 3D ball of radius *R\_ii' = rcutfac\*(R\_i + R\_i')* +a point within the 3D ball of radius *R_ii' = rcutfac\*(R_i + R_i')* Bartok et al. :ref:`(Bartok) `, proposed mapping this 3D ball onto the 3-sphere, the surface of the unit ball in a four-dimensional -space. The radial distance *r* within *R\_ii'* is mapped on to a third +space. The radial distance *r* within *R_ii'* is mapped on to a third polar angle *theta0* defined by, .. math:: @@ -87,8 +87,8 @@ of the 3-sphere. Points south of the latitude *theta0max=rfac0\*Pi* are excluded. The natural basis for functions on the 3-sphere is formed by the 4D -hyperspherical harmonics *U\^j\_m,m'(theta, phi, theta0).* These -functions are better known as *D\^j\_m,m',* the elements of the Wigner +hyperspherical harmonics *U\^j_m,m'(theta, phi, theta0).* These +functions are better known as *D\^j_m,m',* the elements of the Wigner *D*\ -matrices :ref:`(Meremianin `, :ref:`Varshalovich) `. @@ -102,18 +102,18 @@ coefficient as u^j_{m,m'} = U^j_{m,m'}(0,0,0) + \sum_{r_{ii'} < R_{ii'}}{f_c(r_{ii'}) w_{i'} U^j_{m,m'}(\theta_0,\theta,\phi)} -The *w\_i'* neighbor weights are dimensionless numbers that are chosen +The *w_i'* neighbor weights are dimensionless numbers that are chosen to distinguish atoms of different types, while the central atom is arbitrarily assigned a unit weight. The function *fc(r)* ensures that the contribution of each neighbor atom goes smoothly to zero at -*R\_ii'*: +*R_ii'*: .. math:: f_c(r) = & \frac{1}{2}(\cos(\pi \frac{r-r_{min0}}{R_{ii'}-r_{min0}}) + 1), r \leq R_{ii'} \\ = & 0, r > R_{ii'} -The expansion coefficients *u\^j\_m,m'* are complex-valued and they are +The expansion coefficients *u\^j_m,m'* are complex-valued and they are not directly useful as descriptors, because they are not invariant under rotation of the polar coordinate frame. However, the following scalar triple products of expansion coefficients can be shown to be @@ -128,7 +128,7 @@ real-valued and invariant under rotation :ref:`(Bartok) `. {j_2} {m_2} {m'_2} \end{array}} u^{j_1}_{m_1,m'_1} u^{j_2}_{m_2,m'_2} -The constants *H\^jmm'\_j1m1m1'\_j2m2m2'* are coupling coefficients, +The constants *H\^jmm'_j1m1m1'_j2m2m2'* are coupling coefficients, analogous to Clebsch-Gordan coefficients for rotations on the 2-sphere. These invariants are the components of the bispectrum and these are the quantities calculated by the compute *sna/atom*\ . They @@ -176,8 +176,8 @@ broken out by type). The element in the last column of each row contains the potential energy, force, or stress, according to the row. These quantities correspond to the user-specified reference potential that must be subtracted from the target data when fitting SNAP. -The potential energy calculation uses the built in compute *thermo\_pe*. -The stress calculation uses a compute called *snap\_press* that is +The potential energy calculation uses the built in compute *thermo_pe*. +The stress calculation uses a compute called *snap_press* that is automatically created behind the scenes, according to the following command: diff --git a/doc/src/compute_spin.rst b/doc/src/compute_spin.rst index 60a75d10cf..49243e9650 100644 --- a/doc/src/compute_spin.rst +++ b/doc/src/compute_spin.rst @@ -37,7 +37,7 @@ This compute calculates the following 6 magnetic quantities: The simplest way to output the results of the compute spin calculation is to define some of the quantities as variables, and to use the thermo and -thermo\_style commands, for example: +thermo_style commands, for example: .. code-block:: LAMMPS @@ -52,7 +52,7 @@ thermo\_style commands, for example: This series of commands evaluates the total magnetization along z, the norm of the total magnetization, and the magnetic temperature. Three variables are -assigned to those quantities. The thermo and thermo\_style commands print them +assigned to those quantities. The thermo and thermo_style commands print them every 10 timesteps. **Output info:** @@ -64,7 +64,7 @@ Restrictions """""""""""" The *spin* compute is part of the SPIN package. This compute is only -enabled if LAMMPS was built with this package. See the :doc:`Build package ` doc page for more info. The atom\_style +enabled if LAMMPS was built with this package. See the :doc:`Build package ` doc page for more info. The atom_style has to be "spin" for this compute to be valid. **Related commands:** diff --git a/doc/src/compute_stress_mop.rst b/doc/src/compute_stress_mop.rst index 487e6bc365..83a8374702 100644 --- a/doc/src/compute_stress_mop.rst +++ b/doc/src/compute_stress_mop.rst @@ -72,14 +72,14 @@ corrections to the pressure added by the :doc:`pair_modify tail yes `. diff --git a/doc/src/compute_tally.rst b/doc/src/compute_tally.rst index 5988e7791c..f49c872306 100644 --- a/doc/src/compute_tally.rst +++ b/doc/src/compute_tally.rst @@ -102,7 +102,7 @@ The computes in this package are not compatible with dynamic groups. Related commands """""""""""""""" -*compute group/group*\ \_compute\_group\_group.html, *compute -heat/flux*\ \_compute\_heat\_flux.html +*compute group/group*\ _compute_group_group.html, *compute +heat/flux*\ _compute_heat_flux.html **Default:** none diff --git a/doc/src/compute_temp.rst b/doc/src/compute_temp.rst index 5616917572..9232191472 100644 --- a/doc/src/compute_temp.rst +++ b/doc/src/compute_temp.rst @@ -54,14 +54,14 @@ atoms that include these constraints will be computed correctly. If needed, the subtracted degrees-of-freedom can be altered using the *extra* option of the :doc:`compute_modify ` command. -A compute of this style with the ID of "thermo\_temp" is created when +A compute of this style with the ID of "thermo_temp" is created when LAMMPS starts up, as if this command were in the input script: .. code-block:: LAMMPS compute thermo_temp all temp -See the "thermo\_style" command for more details. +See the "thermo_style" command for more details. See the :doc:`Howto thermostat ` doc page for a discussion of different ways to compute temperature and perform diff --git a/doc/src/compute_temp_drude.rst b/doc/src/compute_temp_drude.rst index bd49cb377f..8cb9849a24 100644 --- a/doc/src/compute_temp_drude.rst +++ b/doc/src/compute_temp_drude.rst @@ -69,7 +69,7 @@ Restrictions The number of degrees of freedom contributing to the temperature is assumed to be constant for the duration of the run unless the -*fix\_modify* command sets the option *dynamic yes*\ . +*fix_modify* command sets the option *dynamic yes*\ . Related commands """""""""""""""" diff --git a/doc/src/compute_ti.rst b/doc/src/compute_ti.rst index 8fe294a2db..79fc56178c 100644 --- a/doc/src/compute_ti.rst +++ b/doc/src/compute_ti.rst @@ -58,7 +58,7 @@ to 1 (or vice versa) over the course of a :doc:`run `. The time-dependent adjustment is what the :doc:`fix adapt ` command does. -Assume that the unscaled energy of a pair\_style or kspace\_style is +Assume that the unscaled energy of a pair_style or kspace_style is given by U. Then the scaled energy is .. parsed-literal:: @@ -85,9 +85,9 @@ leading asterisk means all types from 1 to n (inclusive). A trailing asterisk means all types from n to N (inclusive). A middle asterisk means all types from m to n (inclusive). -You also specify two functions, as :doc:`equal-style variables `. The first is specified as *v\_name1*, where +You also specify two functions, as :doc:`equal-style variables `. The first is specified as *v_name1*, where *name1* is the name of the variable, and is f(lambda) in the notation -above. The second is specified as *v\_name2*, where *name2* is the +above. The second is specified as *v_name2*, where *name2* is the name of the variable, and is df(lambda) / dlambda in the notation above. I.e. it is the analytic derivative of f() with respect to lambda. Note that the *name1* variable is also typically given as an diff --git a/doc/src/compute_voronoi_atom.rst b/doc/src/compute_voronoi_atom.rst index 88b65ee8b2..a5d99d5de9 100644 --- a/doc/src/compute_voronoi_atom.rst +++ b/doc/src/compute_voronoi_atom.rst @@ -13,8 +13,8 @@ Syntax * ID, group-ID are documented in :doc:`compute ` command * voronoi/atom = style name of this compute command * zero or more keyword/value pairs may be appended -* keyword = *only\_group* or *surface* or *radius* or *edge\_histo* or *edge\_threshold* - or *face\_threshold* or *neighbors* or *peratom* +* keyword = *only_group* or *surface* or *radius* or *edge_histo* or *edge_threshold* + or *face_threshold* or *neighbors* or *peratom* .. parsed-literal:: @@ -65,7 +65,7 @@ but they are not accessible. ---------- -If the *only\_group* keyword is specified the tessellation is performed +If the *only_group* keyword is specified the tessellation is performed only with respect to the atoms contained in the compute group. This is equivalent to deleting all atoms not contained in the group prior to evaluating the tessellation. @@ -80,7 +80,7 @@ In the example above, a precipitate embedded in a matrix, only atoms at the surface of the precipitate will have non-zero surface area, and only the outward facing facets of the Voronoi cells are counted (the hull of the precipitate). The total surface area of the precipitate -can be obtained by running a "reduce sum" compute on c\_2[3] +can be obtained by running a "reduce sum" compute on c_2[3] If the *radius* keyword is specified with an atom style variable as the argument, a poly-disperse Voronoi tessellation is @@ -92,11 +92,11 @@ performed. Examples for radius variables are compute radius all property/atom radius variable r2 atom c_radius -Here v\_r1 specifies a per-type radius of 0.1 units for type 1 atoms -and 0.4 units for type 2 atoms, and v\_r2 accesses the radius property -present in atom\_style sphere for granular models. +Here v_r1 specifies a per-type radius of 0.1 units for type 1 atoms +and 0.4 units for type 2 atoms, and v_r2 accesses the radius property +present in atom_style sphere for granular models. -The *edge\_histo* keyword activates the compilation of a histogram of +The *edge_histo* keyword activates the compilation of a histogram of number of edges on the faces of the Voronoi cells in the compute group. The argument *maxedge* of the this keyword is the largest number of edges on a single Voronoi cell face expected to occur in the @@ -106,7 +106,7 @@ faces with more than *maxedge* edges. Since the polygon with the smallest amount of edges is a triangle, entries 1 and 2 of the vector will always be zero. -The *edge\_threshold* and *face\_threshold* keywords allow the +The *edge_threshold* and *face_threshold* keywords allow the suppression of edges below a given minimum length and faces below a given minimum area. Ultra short edges and ultra small faces can occur as artifacts of the Voronoi tessellation. These keywords will affect @@ -144,7 +144,7 @@ containing all the Voronoi neighbors in a system: compute 6 all voronoi/atom neighbors yes dump d2 all local 1 dump.neighbors index c_6[1] c_6[2] c_6[3] -If the *face\_threshold* keyword is used, then only faces +If the *face_threshold* keyword is used, then only faces with areas greater than the threshold are stored. ---------- @@ -199,7 +199,7 @@ per-atom values from a compute as input. See the :doc:`Howto output ` doc page for more info. -The compute\_xrd command does not work for triclinic cells. +The compute_xrd command does not work for triclinic cells. Related commands """""""""""""""" diff --git a/doc/src/create_atoms.rst b/doc/src/create_atoms.rst index 85eaa86f38..2e0b079e09 100644 --- a/doc/src/create_atoms.rst +++ b/doc/src/create_atoms.rst @@ -88,7 +88,7 @@ the specified atom *type*\ . E.g. if *type* = 2, and the file specifies atom types 1,2,3, then each created molecule will have atom types 3,4,5. -For the *box* style, the create\_atoms command fills the entire +For the *box* style, the create_atoms command fills the entire simulation box with particles on the lattice. If your simulation box is periodic, you should insure its size is a multiple of the lattice spacings, to avoid unwanted atom overlaps at the box boundaries. If @@ -136,11 +136,11 @@ outside a geometric boundary. Note that this command adds particles to those that already exist. This means it can be used to add particles to a system previously read -in from a data or restart file. Or the create\_atoms command can be +in from a data or restart file. Or the create_atoms command can be used multiple times, to add multiple sets of particles to the simulation. For example, grain boundaries can be created, by -interleaving create\_atoms with :doc:`lattice ` commands -specifying different orientations. By using the create\_atoms command +interleaving create_atoms with :doc:`lattice ` commands +specifying different orientations. By using the create_atoms command in conjunction with the :doc:`delete_atoms ` command, reasonably complex geometries can be created, or a protein can be solvated with a surrounding box of water molecules. @@ -157,10 +157,10 @@ used to remove overlapping atoms or molecules. LAMMPS. This is true even if you are using shrink-wrapped box boundaries, as specified by the :doc:`boundary ` command. However, you can first use the :doc:`change_box ` command to - temporarily expand the box, then add atoms via create\_atoms, then - finally use change\_box command again if needed to re-shrink-wrap the + temporarily expand the box, then add atoms via create_atoms, then + finally use change_box command again if needed to re-shrink-wrap the new atoms. See the :doc:`change_box ` doc page for an - example of how to do this, using the create\_atoms *single* style to + example of how to do this, using the create_atoms *single* style to insert a new atom outside the current simulation box. ---------- @@ -195,7 +195,7 @@ not overlap, regardless of their relative orientations. .. note:: If the :doc:`create_box ` command is used to create - the simulation box, followed by the create\_atoms command with its + the simulation box, followed by the create_atoms command with its *mol* option for adding molecules, then you typically need to use the optional keywords allowed by the :doc:`create_box ` command for extra bonds (angles,etc) or extra special neighbors. This is @@ -300,7 +300,7 @@ spacings. Atom IDs are assigned to created atoms in the following way. The collection of created atoms are assigned consecutive IDs that start immediately following the largest atom ID existing before the -create\_atoms command was invoked. This is done by the processor's +create_atoms command was invoked. This is done by the processor's communicating the number of atoms they each own, the first processor numbering its atoms from 1 to N1, the second processor from N1+1 to N2, etc. Where N1 = number of atoms owned by the first processor, N2 diff --git a/doc/src/create_bonds.rst b/doc/src/create_bonds.rst index 9ac145679c..b69fd909f0 100644 --- a/doc/src/create_bonds.rst +++ b/doc/src/create_bonds.rst @@ -114,7 +114,7 @@ apart such that *rmin* <= D <= *rmax*\ . The following settings must have been made in an input script before this style is used: -* special\_bonds weight for 1-2 interactions must be 0.0 +* special_bonds weight for 1-2 interactions must be 0.0 * a :doc:`pair_style ` must be defined * no :doc:`kspace_style ` defined * minimum :doc:`pair_style ` cutoff + :doc:`neighbor ` skin >= *rmax* diff --git a/doc/src/create_box.rst b/doc/src/create_box.rst index 99d5befd2d..917a4b3b0a 100644 --- a/doc/src/create_box.rst +++ b/doc/src/create_box.rst @@ -63,7 +63,7 @@ positive or negative values and are called "tilt factors" because they are the amount of displacement applied to faces of an originally orthogonal box to transform it into the parallelepiped. -By default, a *prism* region used with the create\_box command must +By default, a *prism* region used with the create_box command must have tilt factors (xy,xz,yz) that do not skew the box more than half the distance of the parallel box length. For example, if xlo = 2 and xhi = 12, then the x box length is 10 and the xy tilt factor must be @@ -124,7 +124,7 @@ keywords serve the same purpose as the analogous keywords that can be used in a data file which are recognized by the :doc:`read_data ` command when it sets up a system. -Note that if these keywords are not used, then the create\_box command +Note that if these keywords are not used, then the create_box command creates an atomic (non-molecular) simulation that does not allow bonds between pairs of atoms to be defined, or a :doc:`bond potential ` to be specified, or for molecules with special neighbors to be added to the system by commands such as @@ -133,7 +133,7 @@ or :doc:`fix pour `. As an example, see the examples/deposit/in.deposit.molecule script, which deposits molecules onto a substrate. Initially there are no -molecules in the system, but they are added later by the :doc:`fix deposit ` command. The create\_box command in the +molecules in the system, but they are added later by the :doc:`fix deposit ` command. The create_box command in the script uses the bond/types and extra/bond/per/atom keywords to allow this. If the added molecule contained more than 1 special bond (allowed by default), an extra/special/per/atom keyword would also diff --git a/doc/src/delete_bonds.rst b/doc/src/delete_bonds.rst index 7381682f6d..9c42b5a2a0 100644 --- a/doc/src/delete_bonds.rst +++ b/doc/src/delete_bonds.rst @@ -86,9 +86,9 @@ of all interactions in the specified group is simply reported. This is useful for diagnostic purposes if bonds have been turned off by a bond-breaking potential during a previous run. -The default behavior of the delete\_bonds command is to turn off +The default behavior of the delete_bonds command is to turn off interactions by toggling their type to a negative value, but not to -permanently remove the interaction. E.g. a bond\_type of 2 is set to +permanently remove the interaction. E.g. a bond_type of 2 is set to -2. The neighbor list creation routines will not include such an interaction in their interaction lists. The default is also to not alter the list of 1-2, 1-3, 1-4 neighbors computed by the @@ -105,7 +105,7 @@ interaction. Instead, if any of the atoms in the interaction are in the specified group, it will be turned off (or on if the *undo* keyword is used). -The *undo* keyword inverts the delete\_bonds command so that the +The *undo* keyword inverts the delete_bonds command so that the specified bonds, angles, etc are turned on if they are currently turned off. This means a negative value is toggled to positive. For example, for style *angle*\ , if *type* is specified as 2, then all @@ -113,14 +113,14 @@ angles with current type = -2, are reset to type = 2. Note that the :doc:`fix shake ` command also sets bond and angle types negative, so this option should not be used on those interactions. -The *remove* keyword is invoked at the end of the delete\_bonds +The *remove* keyword is invoked at the end of the delete_bonds operation. It causes turned-off bonds (angles, etc) to be removed from each atom's data structure and then adjusts the global bond (angle, etc) counts accordingly. Removal is a permanent change; removed bonds cannot be turned back on via the *undo* keyword. Removal does not alter the pairwise 1-2, 1-3, 1-4 weighting list. -The *special* keyword is invoked at the end of the delete\_bonds +The *special* keyword is invoked at the end of the delete_bonds operation, after (optional) removal. It re-computes the pairwise 1-2, 1-3, 1-4 weighting list. The weighting list computation treats turned-off bonds the same as turned-on. Thus, turned-off bonds must @@ -128,7 +128,7 @@ be removed if you wish to change the weighting list. Note that the choice of *remove* and *special* options affects how 1-2, 1-3, 1-4 pairwise interactions will be computed across bonds that -have been modified by the delete\_bonds command. +have been modified by the delete_bonds command. Restrictions """""""""""" diff --git a/doc/src/dihedral_charmm.rst b/doc/src/dihedral_charmm.rst index 84dc42f08e..38cb18d172 100644 --- a/doc/src/dihedral_charmm.rst +++ b/doc/src/dihedral_charmm.rst @@ -90,12 +90,12 @@ the ring in the opposite direction and thus the weighting factor is Note that this dihedral weighting factor is unrelated to the scaling factor specified by the :doc:`special bonds ` command which applies to all 1-4 interactions in the system. For CHARMM force -fields, the special\_bonds 1-4 interaction scaling factor should be set +fields, the special_bonds 1-4 interaction scaling factor should be set to 0.0. Since the corresponding 1-4 non-bonded interactions are computed with the dihedral. This means that if any of the weighting factors defined as dihedral coefficients (4th coeff above) are non-zero, then you must use a pair style with "lj/charmm" and set the -special\_bonds 1-4 scaling factor to 0.0 (which is the +special_bonds 1-4 scaling factor to 0.0 (which is the default). Otherwise 1-4 non-bonded interactions in dihedrals will be computed twice. @@ -110,11 +110,11 @@ i.e. within the outer cutoff specified for the pair style. The :doc:`pair_style lj/charmmfsw/coul/long ` commands. Use the *charmm* style with the older :doc:`pair_style ` commands that have just "charmm" in their style name. See the -discussion on the :doc:`CHARMM pair\_style ` doc page for +discussion on the :doc:`CHARMM pair_style ` doc page for details. Note that for AMBER force fields, which use pair styles with "lj/cut", -the special\_bonds 1-4 scaling factor should be set to the AMBER +the special_bonds 1-4 scaling factor should be set to the AMBER defaults (1/2 and 5/6) and all the dihedral weighting factors (4th coeff above) must be set to 0.0. In this case, you can use any pair style you wish, since the dihedral does not need any Lennard-Jones @@ -148,7 +148,7 @@ instructions on how to use the accelerated styles effectively. Restrictions """""""""""" -When using run\_style :doc:`respa `, these dihedral styles +When using run_style :doc:`respa `, these dihedral styles must be assigned to the same r-RESPA level as *pair* or *outer*\ . When used in combination with CHARMM pair styles, the 1-4 diff --git a/doc/src/dihedral_coeff.rst b/doc/src/dihedral_coeff.rst index f31c933b7c..d72a299416 100644 --- a/doc/src/dihedral_coeff.rst +++ b/doc/src/dihedral_coeff.rst @@ -39,7 +39,7 @@ leading asterisk means all types from 1 to n (inclusive). A trailing asterisk means all types from n to N (inclusive). A middle asterisk means all types from m to n (inclusive). -Note that using a dihedral\_coeff command can override a previous setting +Note that using a dihedral_coeff command can override a previous setting for the same dihedral type. For example, these commands set the coeffs for all dihedral types, then overwrite the coeffs for just dihedral type 2: @@ -49,7 +49,7 @@ for all dihedral types, then overwrite the coeffs for just dihedral type 2: dihedral_coeff 2 200.0 1 3 A line in a data file that specifies dihedral coefficients uses the exact -same format as the arguments of the dihedral\_coeff command in an input +same format as the arguments of the dihedral_coeff command in an input script, except that wild-card asterisks should not be used since coefficients for all N types must be listed in the file. For example, under the "Dihedral Coeffs" section of a data file, the line that @@ -83,7 +83,7 @@ in more compact form on the :ref:`Commands dihedral ` doc page. On either of those pages, click on the style to display the formula it computes and its coefficients as specified by the associated -dihedral\_coeff command. +dihedral_coeff command. ---------- diff --git a/doc/src/dihedral_fourier.rst b/doc/src/dihedral_fourier.rst index eef6172ffd..ad5f1f6586 100644 --- a/doc/src/dihedral_fourier.rst +++ b/doc/src/dihedral_fourier.rst @@ -73,7 +73,7 @@ Restrictions """""""""""" This angle style can only be used if LAMMPS was built with the -USER\_MISC package. See the :doc:`Build package ` doc +USER_MISC package. See the :doc:`Build package ` doc page for more info. Related commands diff --git a/doc/src/dihedral_hybrid.rst b/doc/src/dihedral_hybrid.rst index 764077359d..9fe4478f67 100644 --- a/doc/src/dihedral_hybrid.rst +++ b/doc/src/dihedral_hybrid.rst @@ -32,10 +32,10 @@ boundary (of dihedral type 2) could be computed with a *helix* potential. The assignment of dihedral type to style is made via the :doc:`dihedral_coeff ` command or in the data file. -In the dihedral\_coeff commands, the name of a dihedral style must be +In the dihedral_coeff commands, the name of a dihedral style must be added after the dihedral type, with the remaining coefficients being those appropriate to that style. In the example above, the 2 -dihedral\_coeff commands set dihedrals of dihedral type 1 to be +dihedral_coeff commands set dihedrals of dihedral type 1 to be computed with a *harmonic* potential with coefficients 6.0, 1, 3 for K, d, n. All other dihedral types (2-N) are computed with a *helix* potential with coefficients 10, 10, 10 for A, B, C. @@ -74,7 +74,7 @@ input script, since AngleTorsion (or EndBondTorsion, etc) coefficients need not be specified at all for dihedral types that are not *class2*\ . A dihedral style of *none* with no additional coefficients can be used -in place of a dihedral style, either in a input script dihedral\_coeff +in place of a dihedral style, either in a input script dihedral_coeff command or in the data file, if you desire to turn off interactions for specific dihedral types. @@ -89,7 +89,7 @@ for more info. Unlike other dihedral styles, the hybrid dihedral style does not store dihedral coefficient info for individual sub-styles in a :doc:`binary restart files `. Thus when restarting a simulation from a -restart file, you need to re-specify dihedral\_coeff commands. +restart file, you need to re-specify dihedral_coeff commands. Related commands """""""""""""""" diff --git a/doc/src/dihedral_nharmonic.rst b/doc/src/dihedral_nharmonic.rst index 87125a4918..9ce464f5f6 100644 --- a/doc/src/dihedral_nharmonic.rst +++ b/doc/src/dihedral_nharmonic.rst @@ -67,7 +67,7 @@ Restrictions """""""""""" This angle style can only be used if LAMMPS was built with the -USER\_MISC package. See the :doc:`Build package ` doc +USER_MISC package. See the :doc:`Build package ` doc page for more info. Related commands diff --git a/doc/src/dihedral_quadratic.rst b/doc/src/dihedral_quadratic.rst index affa53b0bc..bdc5f79559 100644 --- a/doc/src/dihedral_quadratic.rst +++ b/doc/src/dihedral_quadratic.rst @@ -68,7 +68,7 @@ Restrictions """""""""""" This angle style can only be used if LAMMPS was built with the -USER\_MISC package. See the :doc:`Build package ` doc +USER_MISC package. See the :doc:`Build package ` doc page for more info. Related commands diff --git a/doc/src/dihedral_spherical.rst b/doc/src/dihedral_spherical.rst index a156b86a03..67919aa77f 100644 --- a/doc/src/dihedral_spherical.rst +++ b/doc/src/dihedral_spherical.rst @@ -89,7 +89,7 @@ Restrictions """""""""""" This dihedral style can only be used if LAMMPS was built with the -USER\_MISC package. See the :doc:`Build package ` doc +USER_MISC package. See the :doc:`Build package ` doc page for more info. Related commands diff --git a/doc/src/dihedral_style.rst b/doc/src/dihedral_style.rst index ad9cc11da3..bf3cf4902a 100644 --- a/doc/src/dihedral_style.rst +++ b/doc/src/dihedral_style.rst @@ -38,11 +38,11 @@ a data or restart file or via the :doc:`dihedral_coeff ` command. All dihedral potentials store their coefficient data in binary restart -files which means dihedral\_style and +files which means dihedral_style and :doc:`dihedral_coeff ` commands do not need to be re-specified in an input script that restarts a simulation. See the :doc:`read_restart ` command for details on how to do -this. The one exception is that dihedral\_style *hybrid* only stores +this. The one exception is that dihedral_style *hybrid* only stores the list of sub-styles in the restart file; dihedral coefficients need to be re-specified. @@ -87,7 +87,7 @@ the style to display the formula it computes and coefficients specified by the associated :doc:`dihedral_coeff ` command. Click on the style to display the formula it computes, any additional -arguments specified in the dihedral\_style command, and coefficients +arguments specified in the dihedral_style command, and coefficients specified by the associated :doc:`dihedral_coeff ` command. @@ -135,4 +135,4 @@ Related commands Default """"""" -dihedral\_style none +dihedral_style none diff --git a/doc/src/dihedral_table.rst b/doc/src/dihedral_table.rst index dfa4b1c75d..112716a240 100644 --- a/doc/src/dihedral_table.rst +++ b/doc/src/dihedral_table.rst @@ -127,7 +127,7 @@ strange numerical behavior can occur in the large remaining gap. The parameter "N" is required and its value is the number of table entries that follow. Note that this may be different than the N specified in the :doc:`dihedral_style table ` command. -Let *Ntable* is the number of table entries requested dihedral\_style +Let *Ntable* is the number of table entries requested dihedral_style command, and let *Nfile* be the parameter following "N" in the tabulated file ("30" in the sparse example above). What LAMMPS does is a preliminary interpolation by creating splines using the *Nfile* @@ -197,12 +197,12 @@ instructions on how to use the accelerated styles effectively. **Restart info:** -This dihedral style writes the settings for the "dihedral\_style table" -command to :doc:`binary restart files `, so a dihedral\_style +This dihedral style writes the settings for the "dihedral_style table" +command to :doc:`binary restart files `, so a dihedral_style command does not need to specified in an input script that reads a restart file. However, the coefficient information is not stored in the restart file, since it is tabulated in the potential files. Thus, -dihedral\_coeff commands do need to be specified in the restart input +dihedral_coeff commands do need to be specified in the restart input script. Restrictions diff --git a/doc/src/dihedral_table_cut.rst b/doc/src/dihedral_table_cut.rst index 2015146eaf..ae2fcd1f77 100644 --- a/doc/src/dihedral_table_cut.rst +++ b/doc/src/dihedral_table_cut.rst @@ -148,7 +148,7 @@ strange numerical behavior can occur in the large remaining gap. The parameter "N" is required and its value is the number of table entries that follow. Note that this may be different than the N specified in the :doc:`dihedral_style table ` command. -Let *Ntable* is the number of table entries requested dihedral\_style +Let *Ntable* is the number of table entries requested dihedral_style command, and let *Nfile* be the parameter following "N" in the tabulated file ("30" in the sparse example above). What LAMMPS does is a preliminary interpolation by creating splines using the *Nfile* @@ -198,12 +198,12 @@ that matches the specified keyword. **Restart info:** -This dihedral style writes the settings for the "dihedral\_style table/cut" -command to :doc:`binary restart files `, so a dihedral\_style +This dihedral style writes the settings for the "dihedral_style table/cut" +command to :doc:`binary restart files `, so a dihedral_style command does not need to specified in an input script that reads a restart file. However, the coefficient information is not stored in the restart file, since it is tabulated in the potential files. Thus, -dihedral\_coeff commands do need to be specified in the restart input +dihedral_coeff commands do need to be specified in the restart input script. Restrictions diff --git a/doc/src/dihedral_zero.rst b/doc/src/dihedral_zero.rst index 0dc1578e5c..7d8dcd496a 100644 --- a/doc/src/dihedral_zero.rst +++ b/doc/src/dihedral_zero.rst @@ -33,7 +33,7 @@ command. If no dihedral style is defined, this command cannot be used. The optional *nocoeff* flag allows to read data files with a DihedralCoeff -section for any dihedral style. Similarly, any dihedral\_coeff commands +section for any dihedral style. Similarly, any dihedral_coeff commands will only be checked for the dihedral type number and the rest ignored. Note that the :doc:`dihedral_coeff ` command must be diff --git a/doc/src/displace_atoms.rst b/doc/src/displace_atoms.rst index 214164d776..efc6f9230b 100644 --- a/doc/src/displace_atoms.rst +++ b/doc/src/displace_atoms.rst @@ -59,7 +59,7 @@ The *move* style displaces the group of atoms by the specified 3d displacement vector. Any of the 3 quantities defining the vector components can be specified as an equal-style or atom-style :doc:`variable `. If the value is a variable, it should be -specified as v\_name, where name is the variable name. In this case, +specified as v_name, where name is the variable name. In this case, the variable will be evaluated, and its value(s) used for the displacement(s). The scale factor implied by the *units* keyword will also be applied to the variable result. diff --git a/doc/src/dump.rst b/doc/src/dump.rst index 2f1c58158f..c842d5fafe 100644 --- a/doc/src/dump.rst +++ b/doc/src/dump.rst @@ -262,10 +262,10 @@ the 3 tilt factors will be included on each of the 3 following lines. This bounding box is convenient for many visualization programs. The meaning of the 6 character flags for "xx yy zz" is the same as above. -Note that the first two numbers on each line are now xlo\_bound instead +Note that the first two numbers on each line are now xlo_bound instead of xlo, etc, since they represent a bounding box. See the :doc:`Howto triclinic ` doc page for a geometric description of triclinic boxes, as defined by LAMMPS, simple formulas for how the -6 bounding box extents (xlo\_bound,xhi\_bound,etc) are calculated from +6 bounding box extents (xlo_bound,xhi_bound,etc) are calculated from the triclinic parameters, and how to transform those parameters to and from other commonly used triclinic representations. @@ -280,7 +280,7 @@ scaled format (from 0 to 1). I.e. an x value of 0.25 means the atom is at a location 1/4 of the distance from xlo to xhi of the box boundaries. The format can be changed to unscaled coords via the :doc:`dump_modify ` settings. Image flags can also be -added for each atom via dump\_modify. +added for each atom via dump_modify. Style *custom* allows you to specify a list of atom attributes to be written to the dump file for each atom. Possible attributes are @@ -502,7 +502,7 @@ between processor, there is no guarantee that the same index will be used for the same info (e.g. a particular bond) in successive snapshots. -The *c\_ID* and *c\_ID[I]* attributes allow local vectors or arrays +The *c_ID* and *c_ID[I]* attributes allow local vectors or arrays calculated by a :doc:`compute ` to be output. The ID in the attribute should be replaced by the actual ID of the compute that has been defined previously in the input script. See the @@ -515,20 +515,20 @@ opposed to local quantities, cannot be output in a dump local command. Instead, global quantities can be output by the :doc:`thermo_style custom ` command, and per-atom quantities can be output by the dump custom command. -If *c\_ID* is used as a attribute, then the local vector calculated by -the compute is printed. If *c\_ID[I]* is used, then I must be in the +If *c_ID* is used as a attribute, then the local vector calculated by +the compute is printed. If *c_ID[I]* is used, then I must be in the range from 1-M, which will print the Ith column of the local array with M columns calculated by the compute. See the discussion above for how I can be specified with a wildcard asterisk to effectively specify multiple values. -The *f\_ID* and *f\_ID[I]* attributes allow local vectors or arrays +The *f_ID* and *f_ID[I]* attributes allow local vectors or arrays calculated by a :doc:`fix ` to be output. The ID in the attribute should be replaced by the actual ID of the fix that has been defined previously in the input script. -If *f\_ID* is used as a attribute, then the local vector calculated by -the fix is printed. If *f\_ID[I]* is used, then I must be in the +If *f_ID* is used as a attribute, then the local vector calculated by +the fix is printed. If *f_ID[I]* is used, then I must be in the range from 1-M, which will print the Ith column of the local with M columns calculated by the fix. See the discussion above for how I can be specified with a wildcard asterisk to effectively specify multiple @@ -612,7 +612,7 @@ The *tqx*\ , *tqy*\ , *tqz* attributes are for finite-size particles that can sustain a rotational torque due to interactions with other particles. -The *c\_ID* and *c\_ID[I]* attributes allow per-atom vectors or arrays +The *c_ID* and *c_ID[I]* attributes allow per-atom vectors or arrays calculated by a :doc:`compute ` to be output. The ID in the attribute should be replaced by the actual ID of the compute that has been defined previously in the input script. See the @@ -626,14 +626,14 @@ command. Instead, global quantities can be output by the :doc:`thermo_style custom ` command, and local quantities can be output by the dump local command. -If *c\_ID* is used as a attribute, then the per-atom vector calculated -by the compute is printed. If *c\_ID[I]* is used, then I must be in +If *c_ID* is used as a attribute, then the per-atom vector calculated +by the compute is printed. If *c_ID[I]* is used, then I must be in the range from 1-M, which will print the Ith column of the per-atom array with M columns calculated by the compute. See the discussion above for how I can be specified with a wildcard asterisk to effectively specify multiple values. -The *f\_ID* and *f\_ID[I]* attributes allow vector or array per-atom +The *f_ID* and *f_ID[I]* attributes allow vector or array per-atom quantities calculated by a :doc:`fix ` to be output. The ID in the attribute should be replaced by the actual ID of the fix that has been defined previously in the input script. The :doc:`fix ave/atom ` command is one that calculates per-atom @@ -642,14 +642,14 @@ any :doc:`compute `, :doc:`fix `, or atom-style :doc:`variable `, this allows those time-averaged results to be written to a dump file. -If *f\_ID* is used as a attribute, then the per-atom vector calculated -by the fix is printed. If *f\_ID[I]* is used, then I must be in the +If *f_ID* is used as a attribute, then the per-atom vector calculated +by the fix is printed. If *f_ID[I]* is used, then I must be in the range from 1-M, which will print the Ith column of the per-atom array with M columns calculated by the fix. See the discussion above for how I can be specified with a wildcard asterisk to effectively specify multiple values. -The *v\_name* attribute allows per-atom vectors calculated by a +The *v_name* attribute allows per-atom vectors calculated by a :doc:`variable ` to be output. The name in the attribute should be replaced by the actual name of the variable that has been defined previously in the input script. Only an atom-style variable @@ -660,7 +660,7 @@ invoke other computes, fixes, or variables when they are evaluated, so this is a very general means of creating quantities to output to a dump file. -The *d\_name* and *i\_name* attributes allow to output custom per atom +The *d_name* and *i_name* attributes allow to output custom per atom floating point or integer properties that are managed by :doc:`fix property/atom `. @@ -674,7 +674,7 @@ Restrictions """""""""""" To write gzipped dump files, you must either compile LAMMPS with the --DLAMMPS\_GZIP option or use the styles from the COMPRESS package. +-DLAMMPS_GZIP option or use the styles from the COMPRESS package. See the :doc:`Build settings ` doc page for details. The *atom/gz*\ , *cfg/gz*\ , *custom/gz*\ , and *xyz/gz* styles are part of diff --git a/doc/src/dump_adios.rst b/doc/src/dump_adios.rst index ba09b9e6ed..e1b0fe000a 100644 --- a/doc/src/dump_adios.rst +++ b/doc/src/dump_adios.rst @@ -42,11 +42,11 @@ ADIOS-BP files are binary, portable and self-describing. .. _adios: https://github.com/ornladios/ADIOS2 -**Use from write\_dump:** +**Use from write_dump:** It is possible to use these dump styles with the :doc:`write_dump ` command. In this case, the sub-intervals -must not be set at all. The write\_dump command can be used to +must not be set at all. The write_dump command can be used to create a new file at each individual dump. .. code-block:: LAMMPS @@ -61,7 +61,7 @@ Restrictions The number of atoms per snapshot CAN change with the adios style. When using the ADIOS tool 'bpls' to list the content of a .bp file, -bpls will print *\__* for the size of the output table indicating that +bpls will print *__* for the size of the output table indicating that its size is changing every step. The *atom/adios* and *custom/adios* dump styles are part of the USER-ADIOS diff --git a/doc/src/dump_h5md.rst b/doc/src/dump_h5md.rst index 6b6b4cf88e..de44572307 100644 --- a/doc/src/dump_h5md.rst +++ b/doc/src/dump_h5md.rst @@ -33,8 +33,8 @@ Note that at least one element must be specified and image may only be present if position is specified first. For the elements *position*\ , *velocity*\ , *force* and *species*\ , a -sub-interval may be specified to write the data only every N\_element -iterations of the dump (i.e. every N\*N\_element time steps). This is +sub-interval may be specified to write the data only every N_element +iterations of the dump (i.e. every N\*N_element time steps). This is specified by this option directly following the element declaration: .. parsed-literal:: @@ -58,15 +58,15 @@ Dump a snapshot of atom coordinates every N timesteps in the HDF5 files are binary, portable and self-describing. This dump style will write only one file, on the root node. -Several dumps may write to the same file, by using file\_from and +Several dumps may write to the same file, by using file_from and referring to a previously defined dump. Several groups may also be stored within the same file by defining several dumps. A dump that -refers (via *file\_from*) to an already open dump ID and that concerns -another particle group must specify *create\_group yes*. +refers (via *file_from*) to an already open dump ID and that concerns +another particle group must specify *create_group yes*. .. _h5md: http://nongnu.org/h5md/ -Each data element is written every N\*N\_element steps. For *image*\ , no +Each data element is written every N\*N_element steps. For *image*\ , no sub-interval is needed as it must be present at the same interval as *position*\ . *image* must be given after *position* in any case. The box information (edges in each dimension) is stored at the same @@ -79,13 +79,13 @@ every N steps. timesteps when neighbor lists are rebuilt, the coordinates of an atom written to a dump file may be slightly outside the simulation box. -**Use from write\_dump:** +**Use from write_dump:** It is possible to use this dump style with the :doc:`write_dump ` command. In this case, the sub-intervals -must not be set at all. The write\_dump command can be used either to +must not be set at all. The write_dump command can be used either to create a new file or to add current data to an existing dump file by -using the *file\_from* keyword. +using the *file_from* keyword. Typically, the *species* data is fixed. The following two commands store the position data every 100 timesteps, with the image data, and @@ -124,7 +124,7 @@ Related commands ---------- -.. _h5md\_cpc: +.. _h5md_cpc: **(de Buyl)** de Buyl, Colberg and Hofling, H5MD: A structured, efficient, and portable file format for molecular data, diff --git a/doc/src/dump_image.rst b/doc/src/dump_image.rst index d4efc983eb..fabe2643b1 100644 --- a/doc/src/dump_image.rst +++ b/doc/src/dump_image.rst @@ -140,7 +140,7 @@ created. The JPEG and PNG files are binary; PPM has a text mode header followed by binary data. JPEG images have lossy compression; PNG has lossless compression; and PPM files are uncompressed but can be compressed with gzip, if LAMMPS has been compiled with --DLAMMPS\_GZIP and a ".gz" suffix is used. +-DLAMMPS_GZIP and a ".gz" suffix is used. Similarly, the format of the resulting movie is chosen with the *movie* dump style. This is handled by the underlying FFmpeg converter @@ -151,7 +151,7 @@ framerate can be set using the :doc:`dump_modify ` command. To write out JPEG and PNG format files, you must build LAMMPS with support for the corresponding JPEG or PNG library. To convert images -into movies, LAMMPS has to be compiled with the -DLAMMPS\_FFMPEG +into movies, LAMMPS has to be compiled with the -DLAMMPS_FFMPEG flag. See the :doc:`Build settings ` doc page for details. @@ -193,7 +193,7 @@ atoms rendered in the image. They can be any atom attribute defined for the :doc:`dump custom ` command, including *type* and *element*\ . This includes per-atom quantities calculated by a :doc:`compute `, :doc:`fix `, or :doc:`variable `, -which are prefixed by "c\_", "f\_", or "v\_" respectively. Note that the +which are prefixed by "c_", "f_", or "v_" respectively. Note that the *diameter* setting can be overridden with a numeric value applied to all atoms by the optional *adiam* keyword. @@ -218,7 +218,7 @@ diameter 1.0. This mapping can be changed by the :doc:`dump_modify adiam `_ visualization package. @@ -428,7 +428,7 @@ they control how the simulation box appears in the image. All of the *view*\ , *center*\ , *up*\ , *zoom*\ , and *persp* values can be specified as numeric quantities, whose meaning is explained below. -Any of them can also be specified as an :doc:`equal-style variable `, by using v\_name as the value, where "name" is +Any of them can also be specified as an :doc:`equal-style variable `, by using v_name as the value, where "name" is the variable name. In this case the variable will be evaluated on the timestep each image is created to create a new value. If the equal-style variable is time-dependent, this is a means of changing @@ -541,7 +541,7 @@ A series of JPEG, PNG, or PPM images can be converted into a movie file and then played as a movie using commonly available tools. Using dump style *movie* automates this step and avoids the intermediate step of writing (many) image snapshot file. But LAMMPS has to be -compiled with -DLAMMPS\_FFMPEG and an FFmpeg executable have to be +compiled with -DLAMMPS_FFMPEG and an FFmpeg executable have to be installed. To manually convert JPEG, PNG or PPM files into an animated GIF or @@ -627,12 +627,12 @@ which could then be output into dump files. Restrictions """""""""""" -To write JPEG images, you must use the -DLAMMPS\_JPEG switch when +To write JPEG images, you must use the -DLAMMPS_JPEG switch when building LAMMPS and link with a JPEG library. To write PNG images, you -must use the -DLAMMPS\_PNG switch when building LAMMPS and link with a +must use the -DLAMMPS_PNG switch when building LAMMPS and link with a PNG library. -To write *movie* dumps, you must use the -DLAMMPS\_FFMPEG switch when +To write *movie* dumps, you must use the -DLAMMPS_FFMPEG switch when building LAMMPS and have the FFmpeg executable available on the machine where LAMMPS is being run. Typically it's name is lowercase, i.e. ffmpeg. diff --git a/doc/src/dump_modify.rst b/doc/src/dump_modify.rst index c9582775dc..465f92ecfb 100644 --- a/doc/src/dump_modify.rst +++ b/doc/src/dump_modify.rst @@ -139,7 +139,7 @@ As explained on the :doc:`dump ` doc page, the *atom/mpiio*\ , syntax and in the format of the dump files they create, to the corresponding styles without "mpiio", except the single dump file they produce is written in parallel via the MPI-IO library. Thus if a -dump\_modify option below is valid for the *atom* style, it is also +dump_modify option below is valid for the *atom* style, it is also valid for the *atom/mpiio* style, and similarly for the other styles which allow for use of MPI-IO. @@ -163,7 +163,7 @@ The *at* keyword only applies to the *netcdf* dump style. It can only be used if the *append yes* keyword is also used. The *N* argument is the index of which frame to append to. A negative value can be specified for *N*\ , which means a frame counted from the end of the -file. The *at* keyword can only be used if the dump\_modify command is +file. The *at* keyword can only be used if the dump_modify command is before the first command that causes dump snapshots to be output, e.g. a :doc:`run ` or :doc:`minimize ` command. Once the dump file has been opened, this keyword has no further effect. @@ -221,7 +221,7 @@ The *every* keyword changes the dump frequency originally specified by the :doc:`dump ` command to a new value. The every keyword can be specified in one of two ways. It can be a numeric value in which case it must be > 0. Or it can be an :doc:`equal-style variable `, -which should be specified as v\_name, where name is the variable name. +which should be specified as v_name, where name is the variable name. In this case, the variable is evaluated at the beginning of a run to determine the next timestep at which a dump snapshot will be written @@ -270,7 +270,7 @@ in file tmp.times: from the file is not a value greater than the current timestep. Thus if you wanted output on steps 0,15,100 of a 100-timestep run, the file should contain the values 15,100,101 and you should also use the - dump\_modify first command. Any final value > 100 could be used in + dump_modify first command. Any final value > 100 could be used in place of 101. ---------- @@ -332,7 +332,7 @@ settings, reverting all values to their default format. values. However, when specifying the *line* option or *format M string* option for those values, you should specify a format string appropriate for an 8-byte signed integer, e.g. one with "%ld", if - LAMMPS was compiled with the -DLAMMPS\_BIGBIG option for 8-byte IDs. + LAMMPS was compiled with the -DLAMMPS_BIGBIG option for 8-byte IDs. .. note:: @@ -350,7 +350,7 @@ settings, reverting all values to their default format. dump_modify 1 format "%d %0.0f %0.0f" will output the two atom IDs for atoms in each bond as integers. If -the dump\_modify command were omitted, they would appear as +the dump_modify command were omitted, they would appear as floating-point values, assuming they were large integers (more than 6 digits). The "index" keyword should use the "%d" format since it is not generated by a compute or fix, and is stored internally as an @@ -461,7 +461,7 @@ The *refresh* keyword only applies to the dump *custom*\ , *cfg*\ , *image*\ , and *movie* styles. It allows an "incremental" dump file to be written, by refreshing a compute that is used as a threshold for determining which atoms are included in a dump snapshot. The -specified *c\_ID* gives the ID of the compute. It is prefixed by "c\_" +specified *c_ID* gives the ID of the compute. It is prefixed by "c_" to indicate a compute, which is the only current option. At some point, other options may be added, e.g. fixes or variables. @@ -503,7 +503,7 @@ Angstroms to be output on a given snapshot (assuming metal units). However, note that when an atom is output, we also need to update the reference position for that atom to its new coordinates. So that it will not be output in every snapshot thereafter. That reference -position is stored by :doc:`compute displace/atom `. So the dump\_modify +position is stored by :doc:`compute displace/atom `. So the dump_modify *refresh* option triggers a call to compute displace/atom at the end of every dump to perform that update. The *refresh check* option shown as part of the :doc:`compute displace/atom ` command enables the compute @@ -511,17 +511,17 @@ to respond to the call from the dump command, and update the appropriate reference positions. This is done be defining an :doc:`atom-style variable `, *check* in this example, which calculates a Boolean value (0 or 1) for each atom, based on the same -criterion used by dump\_modify thresh. +criterion used by dump_modify thresh. See the :doc:`compute displace/atom ` command for more details, including an example of how to produce output that includes an initial snapshot with the reference position of all atoms. Note that only computes with a *refresh* option will work with -dump\_modify refresh. See individual compute doc pages for details. +dump_modify refresh. See individual compute doc pages for details. Currently, only compute displace/atom supports this option. Others may be added at some point. If you use a compute that doesn't support -refresh operations, LAMMPS will not complain; dump\_modify refresh will +refresh operations, LAMMPS will not complain; dump_modify refresh will simply do nothing. ---------- @@ -720,7 +720,7 @@ all types from 1 to N. A leading asterisk means all types from 1 to n The specified *color* can be a single color which is any of the 140 pre-defined colors (see below) or a color name defined by the -dump\_modify color option. Or it can be two or more colors separated +dump_modify color option. Or it can be two or more colors separated by a "/" character, e.g. red/green/blue. In the former case, that color is assigned to all the specified atom types. In the latter case, the list of colors are assigned in a round-robin fashion to each @@ -797,7 +797,7 @@ The *N* setting is how many entries follow. The format of the entries depends on whether the color map style is continuous, discrete or sequential. In all cases the *color* setting can be any of the 140 pre-defined colors (see below) or a color name defined by the -dump\_modify color option. +dump_modify color option. For continuous color maps, each entry has a *value* and a *color*\ . The *value* is either a number within the range of values or *min* or @@ -871,7 +871,7 @@ mapped to one of the colors, even if there are 1000s of molecules. The *backcolor* sets the background color of the images. The color name can be any of the 140 pre-defined colors (see below) or a color -name defined by the dump\_modify color option. +name defined by the dump_modify color option. ---------- @@ -891,7 +891,7 @@ all types from 1 to N. A leading asterisk means all types from 1 to n The specified *color* can be a single color which is any of the 140 pre-defined colors (see below) or a color name defined by the -dump\_modify color option. Or it can be two or more colors separated +dump_modify color option. Or it can be two or more colors separated by a "/" character, e.g. red/green/blue. In the former case, that color is assigned to all the specified bond types. In the latter case, the list of colors are assigned in a round-robin fashion to each @@ -931,14 +931,14 @@ sub-domain boundaries. See the "dump image box" command for how to specify that a box be drawn via the *box* keyword, and the sub-domain boundaries via the *subbox* keyword. The color name can be any of the 140 pre-defined colors (see below) or a color name defined by the -dump\_modify color option. +dump_modify color option. ---------- The *color* keyword allows definition of a new color name, in addition to the 140-predefined colors (see below), and associates 3 red/green/blue RGB values with that color name. The color name can -then be used with any other dump\_modify keyword that takes a color +then be used with any other dump_modify keyword that takes a color name as a value. The RGB values should each be floating point values between 0.0 and 1.0 inclusive. @@ -1013,7 +1013,7 @@ The option defaults are ---------- These are the standard 109 element names that LAMMPS pre-defines for -use with the :doc:`dump image ` and dump\_modify commands. +use with the :doc:`dump image ` and dump_modify commands. * 1-10 = "H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne" * 11-20 = "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca" @@ -1030,8 +1030,8 @@ use with the :doc:`dump image ` and dump\_modify commands. ---------- These are the 140 colors that LAMMPS pre-defines for use with the -:doc:`dump image ` and dump\_modify commands. Additional -colors can be defined with the dump\_modify color command. The 3 +:doc:`dump image ` and dump_modify commands. Additional +colors can be defined with the dump_modify color command. The 3 numbers listed for each name are the RGB (red/green/blue) values. Divide each value by 255 to get the equivalent 0.0 to 1.0 value. diff --git a/doc/src/dump_vtk.rst b/doc/src/dump_vtk.rst index e5264b783c..4f607c4fdd 100644 --- a/doc/src/dump_vtk.rst +++ b/doc/src/dump_vtk.rst @@ -76,7 +76,7 @@ For the *vtk* style, sorting is off by default. See the The dimensions of the simulation box are written to a separate file for each snapshot (either in legacy VTK or XML format depending on the -format of the main dump file) with the suffix *\_boundingBox* appended +format of the main dump file) with the suffix *_boundingBox* appended to the given dump filename. For an orthogonal simulation box this information is saved as a @@ -134,8 +134,8 @@ in order with some post-processing tools. If a "%" character appears in the filename, then each of P processors writes a portion of the dump file, and the "%" character is replaced with the processor ID from 0 to P-1 preceded by an underscore character. -For example, tmp.dump%.vtp becomes tmp.dump\_0.vtp, tmp.dump\_1.vtp, ... -tmp.dump\_P-1.vtp, etc. This creates smaller files and can be a fast +For example, tmp.dump%.vtp becomes tmp.dump_0.vtp, tmp.dump_1.vtp, ... +tmp.dump_P-1.vtp, etc. This creates smaller files and can be a fast mode of output on parallel machines that support parallel I/O for output. By default, P = the number of processors meaning one file per @@ -150,7 +150,7 @@ processor 0 does write files. Note that using the "\*" and "%" characters together can produce a large number of small dump files! -If *dump\_modify binary* is used, the dump file (or files, if "\*" or +If *dump_modify binary* is used, the dump file (or files, if "\*" or "%" is also used) is written in binary format. A binary dump file will be about the same size as a text version, but will typically write out much faster. diff --git a/doc/src/dynamical_matrix.rst b/doc/src/dynamical_matrix.rst index d1ebe67694..c4ceed64e6 100644 --- a/doc/src/dynamical_matrix.rst +++ b/doc/src/dynamical_matrix.rst @@ -73,7 +73,7 @@ Related commands :doc:`fix phonon ` :doc:`compute hma ` uses an analytic formulation of the -Hessian provided by a pair_style's Pair::single\_hessian() function, +Hessian provided by a pair_style's Pair::single_hessian() function, if implemented. Default diff --git a/doc/src/fix.rst b/doc/src/fix.rst index b6088376bc..263ce9991c 100644 --- a/doc/src/fix.rst +++ b/doc/src/fix.rst @@ -103,11 +103,11 @@ discussed below, it can be referenced via the following bracket notation, where ID is the ID of the fix: +-------------+--------------------------------------------+ -| f\_ID | entire scalar, vector, or array | +| f_ID | entire scalar, vector, or array | +-------------+--------------------------------------------+ -| f\_ID[I] | one element of vector, one column of array | +| f_ID[I] | one element of vector, one column of array | +-------------+--------------------------------------------+ -| f\_ID[I][J] | one element of array | +| f_ID[I][J] | one element of array | +-------------+--------------------------------------------+ In other words, using one bracket reduces the dimension of the @@ -119,7 +119,7 @@ or array. Note that commands and :doc:`variables ` which use fix quantities typically do not allow for all kinds, e.g. a command may require a vector of values, not a scalar. This means there is no -ambiguity about referring to a fix quantity as f\_ID even if it +ambiguity about referring to a fix quantity as f_ID even if it produces, for example, both a scalar and vector. The doc pages for various commands explain the details. @@ -146,7 +146,7 @@ e.g. temperature. Extensive means the value scales with the number of atoms in the simulation, e.g. total rotational kinetic energy. :doc:`Thermodynamic output ` will normalize extensive values by the number of atoms in the system, depending on the -"thermo\_modify norm" setting. It will not normalize intensive values. +"thermo_modify norm" setting. It will not normalize intensive values. If a fix value is accessed in another way, e.g. by a :doc:`variable `, you may want to know whether it is an intensive or extensive value. See the doc page for individual fixes diff --git a/doc/src/fix_adapt.rst b/doc/src/fix_adapt.rst index eafc4710f3..eab8f92639 100644 --- a/doc/src/fix_adapt.rst +++ b/doc/src/fix_adapt.rst @@ -121,11 +121,11 @@ meaning of these parameters: +---------------------------------------------------------------------+--------------------------------------------------+-------------+ | :doc:`born ` | a,b,c | type pairs | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ -| :doc:`born/coul/long, born/coul/msm ` | coulombic\_cutoff | type global | +| :doc:`born/coul/long, born/coul/msm ` | coulombic_cutoff | type global | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ | :doc:`buck ` | a,c | type pairs | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ -| :doc:`buck/coul/long, buck/coul/msm ` | coulombic\_cutoff | type global | +| :doc:`buck/coul/long, buck/coul/msm ` | coulombic_cutoff | type global | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ | :doc:`buck/mdf ` | a,c | type pairs | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ @@ -135,11 +135,11 @@ meaning of these parameters: +---------------------------------------------------------------------+--------------------------------------------------+-------------+ | :doc:`coul/debye ` | scale | type pairs | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ -| :doc:`coul/dsf ` | coulombic\_cutoff | type global | +| :doc:`coul/dsf ` | coulombic_cutoff | type global | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ -| :doc:`coul/long, coul/msm ` | coulombic\_cutoff, scale | type pairs | +| :doc:`coul/long, coul/msm ` | coulombic_cutoff, scale | type pairs | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ -| :doc:`coul/long/soft ` | scale, lambda, coulombic\_cutoff | type pairs | +| :doc:`coul/long/soft ` | scale, lambda, coulombic_cutoff | type pairs | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ | :doc:`eam, eam/alloy, eam/fs ` | scale | type pairs | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ @@ -149,17 +149,17 @@ meaning of these parameters: +---------------------------------------------------------------------+--------------------------------------------------+-------------+ | :doc:`lj/class2 ` | epsilon,sigma | type pairs | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ -| :doc:`lj/class2/coul/cut, lj/class2/coul/long ` | epsilon,sigma,coulombic\_cutoff | type pairs | +| :doc:`lj/class2/coul/cut, lj/class2/coul/long ` | epsilon,sigma,coulombic_cutoff | type pairs | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ | :doc:`lj/cut ` | epsilon,sigma | type pairs | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ -| :doc:`lj/cut/coul/cut, lj/cut/coul/long, lj/cut/coul/msm ` | epsilon,sigma,coulombic\_cutoff | type pairs | +| :doc:`lj/cut/coul/cut, lj/cut/coul/long, lj/cut/coul/msm ` | epsilon,sigma,coulombic_cutoff | type pairs | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ -| :doc:`lj/cut/coul/cut/soft, lj/cut/coul/long/soft ` | epsilon,sigma,lambda,coulombic\_cutoff | type pairs | +| :doc:`lj/cut/coul/cut/soft, lj/cut/coul/long/soft ` | epsilon,sigma,lambda,coulombic_cutoff | type pairs | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ | :doc:`lj/cut/coul/dsf ` | cutoff | type global | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ -| :doc:`lj/cut/tip4p/cut ` | epsilon,sigma,coulombic\_cutoff | type pairs | +| :doc:`lj/cut/tip4p/cut ` | epsilon,sigma,coulombic_cutoff | type pairs | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ | :doc:`lj/cut/soft ` | epsilon,sigma,lambda | type pairs | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ @@ -171,7 +171,7 @@ meaning of these parameters: +---------------------------------------------------------------------+--------------------------------------------------+-------------+ | :doc:`lubricate ` | mu | global | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ -| :doc:`mie/cut ` | epsilon,sigma,gamma\_repulsive,gamma\_attractive | type pairs | +| :doc:`mie/cut ` | epsilon,sigma,gamma_repulsive,gamma_attractive | type pairs | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ | :doc:`morse, morse/smooth/linear ` | D0,R0,alpha | type pairs | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ @@ -179,19 +179,19 @@ meaning of these parameters: +---------------------------------------------------------------------+--------------------------------------------------+-------------+ | :doc:`nm/cut ` | E0,R0,m,n | type pairs | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ -| :doc:`nm/cut/coul/cut, nm/cut/coul/long ` | E0,R0,m,n,coulombic\_cutoff | type pairs | +| :doc:`nm/cut/coul/cut, nm/cut/coul/long ` | E0,R0,m,n,coulombic_cutoff | type pairs | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ | :doc:`reax/c ` | chi, eta, gamma | type global | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ -| :doc:`spin/dmi ` | coulombic\_cutoff | type global | +| :doc:`spin/dmi ` | coulombic_cutoff | type global | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ -| :doc:`spin/exchange ` | coulombic\_cutoff | type global | +| :doc:`spin/exchange ` | coulombic_cutoff | type global | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ -| :doc:`spin/magelec ` | coulombic\_cutoff | type global | +| :doc:`spin/magelec ` | coulombic_cutoff | type global | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ -| :doc:`spin/neel ` | coulombic\_cutoff | type global | +| :doc:`spin/neel ` | coulombic_cutoff | type global | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ -| :doc:`table ` | table\_cutoff | type pairs | +| :doc:`table ` | table_cutoff | type pairs | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ | :doc:`ufm ` | epsilon,sigma | type pairs | +---------------------------------------------------------------------+--------------------------------------------------+-------------+ @@ -247,10 +247,10 @@ be a sub-style name. You must specify I,J arguments that correspond to type pair values defined (via the :doc:`pair_coeff ` command) for that sub-style. -The *v\_name* argument for keyword *pair* is the name of an +The *v_name* argument for keyword *pair* is the name of an :doc:`equal-style variable ` which will be evaluated each time this fix is invoked to set the parameter to a new value. It should be -specified as v\_name, where name is the variable name. Equal-style +specified as v_name, where name is the variable name. Equal-style variables can specify formulas with various mathematical functions, and include :doc:`thermo_style ` command keywords for the simulation box parameters and timestep and elapsed time. Thus it is @@ -284,9 +284,9 @@ from 1 to N. A leading asterisk means all types from 1 to n (inclusive). A trailing asterisk means all types from n to N (inclusive). A middle asterisk means all types from m to n (inclusive). -Currently *bond* does not support bond\_style hybrid nor bond\_style +Currently *bond* does not support bond_style hybrid nor bond_style hybrid/overlay as bond styles. The only bonds that currently are -working with fix\_adapt are +working with fix_adapt are +---------------------------------+-------+------------+ | :doc:`gromos ` | k, r0 | type bonds | @@ -313,10 +313,10 @@ current list of atom parameters that can be varied by this fix: * charge = charge on particle * diameter = diameter of particle -The *v\_name* argument of the *atom* keyword is the name of an +The *v_name* argument of the *atom* keyword is the name of an :doc:`equal-style variable ` which will be evaluated each time this fix is invoked to set the parameter to a new value. It should be -specified as v\_name, where name is the variable name. See the +specified as v_name, where name is the variable name. See the discussion above describing the formulas associated with equal-style variables. The new value is assigned to the corresponding attribute for all atoms in the fix group. @@ -343,7 +343,7 @@ over the course of a 1000-step simulation: ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_adapt_fep.rst b/doc/src/fix_adapt_fep.rst index a9183123e0..ee44d8904f 100644 --- a/doc/src/fix_adapt_fep.rst +++ b/doc/src/fix_adapt_fep.rst @@ -217,10 +217,10 @@ be a sub-style name. You must specify I,J arguments that correspond to type pair values defined (via the :doc:`pair_coeff ` command) for that sub-style. -The *v\_name* argument for keyword *pair* is the name of an +The *v_name* argument for keyword *pair* is the name of an :doc:`equal-style variable ` which will be evaluated each time this fix is invoked to set the parameter to a new value. It should be -specified as v\_name, where name is the variable name. Equal-style +specified as v_name, where name is the variable name. Equal-style variables can specify formulas with various mathematical functions, and include :doc:`thermo_style ` command keywords for the simulation box parameters and timestep and elapsed time. Thus it is @@ -262,10 +262,10 @@ The *I* argument indicates which atom types are affected. A wild-card asterisk can be used in place of or in conjunction with the I argument to set the coefficients for multiple atom types. -The *v\_name* argument of the *atom* keyword is the name of an +The *v_name* argument of the *atom* keyword is the name of an :doc:`equal-style variable ` which will be evaluated each time this fix is invoked to set the parameter to a new value. It should be -specified as v\_name, where name is the variable name. See the +specified as v_name, where name is the variable name. See the discussion above describing the formulas associated with equal-style variables. The new value is assigned to the corresponding attribute for all atoms in the fix group. @@ -289,7 +289,7 @@ parameters on the outermost rRESPA level. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_addforce.rst b/doc/src/fix_addforce.rst index c33e77409e..a7403ef7ab 100644 --- a/doc/src/fix_addforce.rst +++ b/doc/src/fix_addforce.rst @@ -50,7 +50,7 @@ a channel. Any of the 3 quantities defining the force components can be specified as an equal-style or atom-style :doc:`variable `, namely *fx*\ , *fy*\ , *fz*\ . If the value is a variable, it should be specified as -v\_name, where name is the variable name. In this case, the variable +v_name, where name is the variable name. In this case, the variable will be evaluated each timestep, and its value(s) used to determine the force component. @@ -98,7 +98,7 @@ one or more variables, and you are performing energy minimization via the "minimize" command. The keyword specifies the name of an atom-style :doc:`variable ` which is used to compute the energy of each atom as function of its position. Like variables used -for *fx*\ , *fy*\ , *fz*\ , the energy variable is specified as v\_name, +for *fx*\ , *fy*\ , *fz*\ , the energy variable is specified as v_name, where name is the variable name. Note that when the *energy* keyword is used during an energy @@ -131,7 +131,7 @@ instructions on how to use the accelerated styles effectively. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_addtorque.rst b/doc/src/fix_addtorque.rst index ba90008153..2b5a7ce8ce 100644 --- a/doc/src/fix_addtorque.rst +++ b/doc/src/fix_addtorque.rst @@ -39,7 +39,7 @@ This command can be used to drive a group of atoms into rotation. Any of the 3 quantities defining the torque components can be specified as an equal-style :doc:`variable `, namely *Tx*\ , *Ty*\ , *Tz*\ . If the value is a variable, it should be specified as -v\_name, where name is the variable name. In this case, the variable +v_name, where name is the variable name. In this case, the variable will be evaluated each timestep, and its value used to determine the torque component. @@ -50,7 +50,7 @@ time. Thus it is easy to specify a time-dependent torque. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_append_atoms.rst b/doc/src/fix_append_atoms.rst index 3f746424c6..6246787075 100644 --- a/doc/src/fix_append_atoms.rst +++ b/doc/src/fix_append_atoms.rst @@ -86,7 +86,7 @@ define the lattice spacings. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_atc.rst b/doc/src/fix_atc.rst index 3322fda7e7..6903275310 100644 --- a/doc/src/fix_atc.rst +++ b/doc/src/fix_atc.rst @@ -12,7 +12,7 @@ Syntax * fixID = name of fix * group = name of group fix is to be applied -* type = *thermal* or *two\_temperature* or *hardy* or *field* +* type = *thermal* or *two_temperature* or *hardy* or *field* .. parsed-literal:: @@ -21,7 +21,7 @@ Syntax *hardy* = on-the-fly post-processing using kernel localization functions (see "related" section for possible fields) *field* = on-the-fly post-processing using mesh-based localization functions (see "related" section for possible fields) -* parameter\_file = name of the file with material parameters. Note: Neither hardy nor field requires a parameter file +* parameter_file = name of the file with material parameters. Note: Neither hardy nor field requires a parameter file Examples """""""" @@ -36,7 +36,7 @@ Examples Description """"""""""" -This fix is the beginning to creating a coupled FE/MD simulation and/or an on-the-fly estimation of continuum fields. The coupled versions of this fix do Verlet integration and the post-processing does not. After instantiating this fix, several other fix\_modify commands will be needed to set up the problem, e.g. define the finite element mesh and prescribe initial and boundary conditions. +This fix is the beginning to creating a coupled FE/MD simulation and/or an on-the-fly estimation of continuum fields. The coupled versions of this fix do Verlet integration and the post-processing does not. After instantiating this fix, several other fix_modify commands will be needed to set up the problem, e.g. define the finite element mesh and prescribe initial and boundary conditions. .. image:: JPG/atc_nanotube.jpg :align: center @@ -113,7 +113,7 @@ Note coupling and post-processing can be combined in the same simulations using ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. The :doc:`fix_modify ` options relevant to this fix are listed below. No global scalar or vector or @@ -125,7 +125,7 @@ This fix is not invoked during :doc:`energy minimization `. Restrictions """""""""""" -Thermal and two\_temperature (coupling) types use a Verlet time-integration algorithm. The hardy type does not contain its own time-integrator and must be used with a separate fix that does contain one, e.g. nve, nvt, etc. In addition, currently: +Thermal and two_temperature (coupling) types use a Verlet time-integration algorithm. The hardy type does not contain its own time-integrator and must be used with a separate fix that does contain one, e.g. nve, nvt, etc. In addition, currently: * the coupling is restricted to thermal physics * the FE computations are done in serial on each processor. @@ -135,7 +135,7 @@ Related commands After specifying this fix in your input script, several other :doc:`fix_modify ` commands are used to setup the problem, e.g. define the finite element mesh and prescribe initial and boundary conditions. -*fix\_modify* commands for setup: +*fix_modify* commands for setup: * `fix_modify AtC mesh create `_ * `fix_modify AtC mesh quadrature `_ @@ -156,7 +156,7 @@ After specifying this fix in your input script, several other :doc:`fix_modify < * `fix_modify AtC internal_element_set `_ * `fix_modify AtC decomposition `_ -*fix\_modify* commands for boundary and initial conditions: +*fix_modify* commands for boundary and initial conditions: * `fix_modify AtC initial `_ * `fix_modify AtC fix `_ @@ -166,7 +166,7 @@ After specifying this fix in your input script, several other :doc:`fix_modify < * `fix_modify AtC source `_ * `fix_modify AtC remove_source `_ -*fix\_modify* commands for control and filtering: +*fix_modify* commands for control and filtering: * `fix_modify AtC control `_ * `fix_modify AtC control thermal `_ @@ -182,7 +182,7 @@ After specifying this fix in your input script, several other :doc:`fix_modify < * `fix_modify AtC extrinsic exchange `_ * `fix_modify AtC poisson_solver `_ -*fix\_modify* commands for output: +*fix_modify* commands for output: * `fix_modify AtC output `_ * `fix_modify AtC output nodeset `_ @@ -193,7 +193,7 @@ After specifying this fix in your input script, several other :doc:`fix_modify < * `fix_modify AtC write_restart `_ * `fix_modify AtC read_restart `_ -*fix\_modify* commands for post-processing: +*fix_modify* commands for post-processing: * `fix_modify AtC kernel `_ * `fix_modify AtC fields `_ @@ -205,7 +205,7 @@ After specifying this fix in your input script, several other :doc:`fix_modify < * `fix_modify AtC sample_frequency `_ * `fix_modify AtC set `_ -miscellaneous *fix\_modify* commands: +miscellaneous *fix_modify* commands: * `fix_modify AtC atom_element_map `_ * `fix_modify AtC atom_weight `_ diff --git a/doc/src/fix_atom_swap.rst b/doc/src/fix_atom_swap.rst index 4c40aa2f09..a87fdadf83 100644 --- a/doc/src/fix_atom_swap.rst +++ b/doc/src/fix_atom_swap.rst @@ -141,7 +141,7 @@ you MUST enable the :doc:`fix_modify ` *energy* option for that fix. The doc pages for individual :doc:`fix ` commands specify if this should be done. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the state of the fix to :doc:`binary restart files `. This includes information about the random number generator seed, the next timestep for MC exchanges, the number diff --git a/doc/src/fix_ave_atom.rst b/doc/src/fix_ave_atom.rst index e22e6cf7c2..40c61239cb 100644 --- a/doc/src/fix_ave_atom.rst +++ b/doc/src/fix_ave_atom.rst @@ -16,7 +16,7 @@ Syntax * Nrepeat = # of times to use input values for calculating averages * Nfreq = calculate averages every this many timesteps one or more input values can be listed -* value = x, y, z, vx, vy, vz, fx, fy, fz, c\_ID, c\_ID[i], f\_ID, f\_ID[i], v\_name +* value = x, y, z, vx, vy, vz, fx, fy, fz, c_ID, c_ID[i], f_ID, f_ID[i], v_name .. parsed-literal:: @@ -121,7 +121,7 @@ an input value from that compute. which can be provided by the :doc:`compute property/atom ` command via its xu,yu,zu attributes. -If a value begins with "c\_", a compute ID must follow which has been +If a value begins with "c_", a compute ID must follow which has been previously defined in the input script. If no bracketed term is appended, the per-atom vector calculated by the compute is used. If a bracketed term containing an index I is appended, the Ith column of @@ -130,7 +130,7 @@ write code for their own compute styles and :doc:`add them to LAMMPS `. be specified with a wildcard asterisk to effectively specify multiple values. -If a value begins with "f\_", a fix ID must follow which has been +If a value begins with "f_", a fix ID must follow which has been previously defined in the input script. If no bracketed term is appended, the per-atom vector calculated by the fix is used. If a bracketed term containing an index I is appended, the Ith column of @@ -141,7 +141,7 @@ write code for their own fix styles and :doc:`add them to LAMMPS `. See specified with a wildcard asterisk to effectively specify multiple values. -If a value begins with "v\_", a variable name must follow which has +If a value begins with "v_", a variable name must follow which has been previously defined in the input script as an :doc:`atom-style variable ` Variables of style *atom* can reference thermodynamic keywords, or invoke other computes, fixes, or variables when they are evaluated, so this is a very general means of generating @@ -149,7 +149,7 @@ per-atom quantities to time average. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global scalar or vector quantities are diff --git a/doc/src/fix_ave_chunk.rst b/doc/src/fix_ave_chunk.rst index fe610449cb..34116a56a2 100644 --- a/doc/src/fix_ave_chunk.rst +++ b/doc/src/fix_ave_chunk.rst @@ -17,7 +17,7 @@ Syntax * Nfreq = calculate averages every this many timesteps * chunkID = ID of :doc:`compute chunk/atom ` command * one or more input values can be listed -* value = vx, vy, vz, fx, fy, fz, density/mass, density/number, temp, c\_ID, c\_ID[I], f\_ID, f\_ID[I], v\_name +* value = vx, vy, vz, fx, fy, fz, density/mass, density/number, temp, c_ID, c_ID[I], f_ID, f_ID[I], v_name .. parsed-literal:: @@ -265,7 +265,7 @@ of atoms to calculate their temperature. The compute allows the center-of-mass velocity of each chunk to be subtracted before calculating the temperature; this fix does not. -If a value begins with "c\_", a compute ID must follow which has been +If a value begins with "c_", a compute ID must follow which has been previously defined in the input script. If no bracketed integer is appended, the per-atom vector calculated by the compute is used. If a bracketed integer is appended, the Ith column of the per-atom array @@ -274,7 +274,7 @@ their own compute styles and :doc:`add them to LAMMPS `. See the discussion above for how I can be specified with a wildcard asterisk to effectively specify multiple values. -If a value begins with "f\_", a fix ID must follow which has been +If a value begins with "f_", a fix ID must follow which has been previously defined in the input script. If no bracketed integer is appended, the per-atom vector calculated by the fix is used. If a bracketed integer is appended, the Ith column of the per-atom array @@ -285,7 +285,7 @@ own fix styles and :doc:`add them to LAMMPS `. See the discussion above for how I can be specified with a wildcard asterisk to effectively specify multiple values. -If a value begins with "v\_", a variable name must follow which has +If a value begins with "v_", a variable name must follow which has been previously defined in the input script. Variables of style *atom* can reference thermodynamic keywords and various per-atom attributes, or invoke other computes, fixes, or variables when they @@ -426,7 +426,7 @@ By default, these header lines are as follows: In the first line, ID and name are replaced with the fix-ID and group name. The second line describes the two values that are printed at the first of each section of output. In the third line the values are -replaced with the appropriate value names, e.g. fx or c\_myCompute[2]. +replaced with the appropriate value names, e.g. fx or c_myCompute[2]. The words in parenthesis only appear with corresponding columns if the chunk style specified for the :doc:`compute chunk/atom ` command supports them. The OrigID @@ -456,7 +456,7 @@ dimensions. Those values are always in distance :doc:`units `. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. diff --git a/doc/src/fix_ave_correlate.rst b/doc/src/fix_ave_correlate.rst index d559efc123..c921e8e55b 100644 --- a/doc/src/fix_ave_correlate.rst +++ b/doc/src/fix_ave_correlate.rst @@ -16,7 +16,7 @@ Syntax * Nrepeat = # of correlation time windows to accumulate * Nfreq = calculate time window averages every this many timesteps * one or more input values can be listed -* value = c\_ID, c\_ID[N], f\_ID, f\_ID[N], v\_name +* value = c_ID, c_ID[N], f_ID, f_ID[N], v_name .. parsed-literal:: @@ -169,7 +169,7 @@ default, then *Nfreq* >= (\ *Nrepeat*\ -1)\*\ *Nevery* is required. ---------- -If a value begins with "c\_", a compute ID must follow which has been +If a value begins with "c_", a compute ID must follow which has been previously defined in the input script. If no bracketed term is appended, the global scalar calculated by the compute is used. If a bracketed term is appended, the Ith element of the global vector @@ -185,7 +185,7 @@ or :doc:`fix temp/rescale `. See the doc pages for these commands which give the IDs of these computes. Users can also write code for their own compute styles and :doc:`add them to LAMMPS `. -If a value begins with "f\_", a fix ID must follow which has been +If a value begins with "f_", a fix ID must follow which has been previously defined in the input script. If no bracketed term is appended, the global scalar calculated by the fix is used. If a bracketed term is appended, the Ith element of the global vector @@ -197,7 +197,7 @@ Note that some fixes only produce their values on certain timesteps, which must be compatible with *Nevery*\ , else an error will result. Users can also write code for their own fix styles and :doc:`add them to LAMMPS `. -If a value begins with "v\_", a variable name must follow which has +If a value begins with "v_", a variable name must follow which has been previously defined in the input script. Only equal-style or vector-style variables can be referenced; the latter requires a bracketed term to specify the Ith element of the vector calculated by @@ -310,7 +310,7 @@ included in the variable formula or via the *prefactor* keyword. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. diff --git a/doc/src/fix_ave_correlate_long.rst b/doc/src/fix_ave_correlate_long.rst index 9416f42f1c..affa7df127 100644 --- a/doc/src/fix_ave_correlate_long.rst +++ b/doc/src/fix_ave_correlate_long.rst @@ -15,7 +15,7 @@ Syntax * Nevery = use input values every this many timesteps * Nfreq = save state of the time correlation functions every this many timesteps * one or more input values can be listed -* value = c\_ID, c\_ID[N], f\_ID, f\_ID[N], v\_name +* value = c_ID, c_ID[N], f_ID, f_ID[N], v_name .. parsed-literal:: @@ -110,7 +110,7 @@ corresponds to about 10 KB. For the meaning of the additional optional keywords, see the :doc:`fix ave/correlate ` doc page. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** Contrary to :doc:`fix ave/correlate ` this fix does **not** provide access to its internal data to various output @@ -118,7 +118,7 @@ options. Since this fix in intended for the calculation of time correlation functions over very long MD simulations, the information about this fix is written automatically to binary restart files, so that the time correlation calculation can continue in subsequent -simulations. None of the fix\_modify options are relevant to this fix. +simulations. None of the fix_modify options are relevant to this fix. No parameter of this fix can be used with the start/stop keywords of the run command. This fix is not invoked during energy minimization. diff --git a/doc/src/fix_ave_histo.rst b/doc/src/fix_ave_histo.rst index 3482df3703..b9437834f0 100644 --- a/doc/src/fix_ave_histo.rst +++ b/doc/src/fix_ave_histo.rst @@ -21,7 +21,7 @@ Syntax * lo,hi = lo/hi bounds within which to histogram * Nbin = # of histogram bins * one or more input values can be listed -* value = x, y, z, vx, vy, vz, fx, fy, fz, c\_ID, c\_ID[N], f\_ID, f\_ID[N], v\_name +* value = x, y, z, vx, vy, vz, fx, fy, fz, c_ID, c_ID[N], f_ID, f_ID[N], v_name .. parsed-literal:: @@ -176,7 +176,7 @@ self-explanatory. Note that other atom attributes can be used as inputs to this fix by using the :doc:`compute property/atom ` command and then specifying an input value from that compute. -If a value begins with "c\_", a compute ID must follow which has been +If a value begins with "c_", a compute ID must follow which has been previously defined in the input script. If *mode* = scalar, then if no bracketed term is appended, the global scalar calculated by the compute is used. If a bracketed term is appended, the Ith element of @@ -196,7 +196,7 @@ or :doc:`fix temp/rescale `. See the doc pages for these commands which give the IDs of these computes. Users can also write code for their own compute styles and :doc:`add them to LAMMPS `. -If a value begins with "f\_", a fix ID must follow which has been +If a value begins with "f_", a fix ID must follow which has been previously defined in the input script. If *mode* = scalar, then if no bracketed term is appended, the global scalar calculated by the fix is used. If a bracketed term is appended, the Ith element of the @@ -212,7 +212,7 @@ Note that some fixes only produce their values on certain timesteps, which must be compatible with *Nevery*\ , else an error will result. Users can also write code for their own fix styles and :doc:`add them to LAMMPS `. -If a value begins with "v\_", a variable name must follow which has +If a value begins with "v_", a variable name must follow which has been previously defined in the input script. If *mode* = scalar, then only equal-style or vector-style variables can be used, which both produce global values. In this mode, a vector-style variable requires @@ -329,7 +329,7 @@ the histogram. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. diff --git a/doc/src/fix_ave_time.rst b/doc/src/fix_ave_time.rst index 778a04f21c..9d121488cc 100644 --- a/doc/src/fix_ave_time.rst +++ b/doc/src/fix_ave_time.rst @@ -16,7 +16,7 @@ Syntax * Nrepeat = # of times to use input values for calculating averages * Nfreq = calculate averages every this many timesteps * one or more input values can be listed -* value = c\_ID, c\_ID[N], f\_ID, f\_ID[N], v\_name +* value = c_ID, c_ID[N], f_ID, f_ID[N], v_name .. parsed-literal:: @@ -155,7 +155,7 @@ averaging is done; values are simply generated on timesteps ---------- -If a value begins with "c\_", a compute ID must follow which has been +If a value begins with "c_", a compute ID must follow which has been previously defined in the input script. If *mode* = scalar, then if no bracketed term is appended, the global scalar calculated by the compute is used. If a bracketed term is appended, the Ith element of @@ -173,7 +173,7 @@ not in your input script, but by :doc:`thermodynamic output ` or o the doc pages for these commands which give the IDs of these computes. Users can also write code for their own compute styles and :doc:`add them to LAMMPS `. -If a value begins with "f\_", a fix ID must follow which has been +If a value begins with "f_", a fix ID must follow which has been previously defined in the input script. If *mode* = scalar, then if no bracketed term is appended, the global scalar calculated by the fix is used. If a bracketed term is appended, the Ith element of the @@ -188,7 +188,7 @@ Note that some fixes only produce their values on certain timesteps, which must be compatible with *Nevery*\ , else an error will result. Users can also write code for their own fix styles and :doc:`add them to LAMMPS `. -If a value begins with "v\_", a variable name must follow which has +If a value begins with "v_", a variable name must follow which has been previously defined in the input script. If *mode* = scalar, then only equal-style or vector-style variables can be used, which both produce global values. In this mode, a vector-style variable requires @@ -304,7 +304,7 @@ appropriate fields from the fix ave/time command. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. diff --git a/doc/src/fix_aveforce.rst b/doc/src/fix_aveforce.rst index 69debca1dd..437c5caaa7 100644 --- a/doc/src/fix_aveforce.rst +++ b/doc/src/fix_aveforce.rst @@ -55,7 +55,7 @@ average value without adding in any additional force. Any of the 3 quantities defining the force components can be specified as an equal-style :doc:`variable `, namely *fx*\ , *fy*\ , *fz*\ . -If the value is a variable, it should be specified as v\_name, where +If the value is a variable, it should be specified as v_name, where name is the variable name. In this case, the variable will be evaluated each timestep, and its value used to determine the average force. @@ -91,7 +91,7 @@ instructions on how to use the accelerated styles effectively. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_balance.rst b/doc/src/fix_balance.rst index 052abb2a76..13fdf6b1c7 100644 --- a/doc/src/fix_balance.rst +++ b/doc/src/fix_balance.rst @@ -362,7 +362,7 @@ each processor, instead of 4, and "SQUARES" replaced by "CUBES". ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. diff --git a/doc/src/fix_bocs.rst b/doc/src/fix_bocs.rst index 175c33e4c0..5315aa81a1 100644 --- a/doc/src/fix_bocs.rst +++ b/doc/src/fix_bocs.rst @@ -44,8 +44,8 @@ The first half of the command mimics a standard fix npt command: The two differences are replacing *npt* with *bocs*\ , and replacing *iso*\ /\ *aniso*\ /\ *etc* with *cgiso*\ . The rest of the command details what form you would like to use for -the pressure correction equation. The choices are: *analytic*\ , *linear\_spline*, -or *cubic\_spline*. +the pressure correction equation. The choices are: *analytic*\ , *linear_spline*, +or *cubic_spline*. With either spline method, the only argument that needs to follow it is the name of a file that contains the desired pressure correction @@ -71,8 +71,8 @@ With the *analytic* option, the arguments are as follows: ... analytic V_avg N_particles N_coeff Coeff_1 Coeff_2 ... Coeff_N -Note that *V\_avg* and *Coeff\_i* should all be in the proper units, e.g. if you -are using *units real*\ , *V\_avg* should be in cubic angstroms, and the +Note that *V_avg* and *Coeff_i* should all be in the proper units, e.g. if you +are using *units real*\ , *V_avg* should be in cubic angstroms, and the coefficients should all be in atmospheres \* cubic angstroms. Restrictions @@ -86,9 +86,9 @@ pressure coupling in 3 dimensions. By default, LAMMPS will still report the normal value for the pressure if the pressure is printed via a *thermo* command, or if the pressures are written to a file every so often. In order to have LAMMPS report the -modified pressure, you must include the *thermo\_modify* command given in +modified pressure, you must include the *thermo_modify* command given in the examples. For the last argument in the command, you should put -XXXX\_press, where XXXX is the ID given to the fix bocs command (in the +XXXX_press, where XXXX is the ID given to the fix bocs command (in the example, the ID of the fix bocs command is 1 ). This fix is part of the USER-BOCS package. It is only enabled if diff --git a/doc/src/fix_bond_break.rst b/doc/src/fix_bond_break.rst index c4488574dc..3994b58b12 100644 --- a/doc/src/fix_bond_break.rst +++ b/doc/src/fix_bond_break.rst @@ -115,7 +115,7 @@ You can dump out snapshots of the current bond topology via the :doc:`dump local ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. diff --git a/doc/src/fix_bond_create.rst b/doc/src/fix_bond_create.rst index 42c94fb9bc..0c48a800c9 100644 --- a/doc/src/fix_bond_create.rst +++ b/doc/src/fix_bond_create.rst @@ -216,7 +216,7 @@ You can dump out snapshots of the current bond topology via the :doc:`dump local ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. diff --git a/doc/src/fix_bond_react.rst b/doc/src/fix_bond_react.rst index 3d9101d20b..8daa52a73d 100644 --- a/doc/src/fix_bond_react.rst +++ b/doc/src/fix_bond_react.rst @@ -18,7 +18,7 @@ Syntax * bond/react = style name of this fix command * the common keyword/values may be appended directly after 'bond/react' * this applies to all reaction specifications (below) -* common\_keyword = *stabilization* +* common_keyword = *stabilization* .. parsed-literal:: @@ -36,9 +36,9 @@ Syntax * Rmax = bonding pair atoms must be separated by less than Rmax to initiate reaction (distance units) * template-ID(pre-reacted) = ID of a molecule template containing pre-reaction topology * template-ID(post-reacted) = ID of a molecule template containing post-reaction topology -* map\_file = name of file specifying corresponding atom-IDs in the pre- and post-reacted templates +* map_file = name of file specifying corresponding atom-IDs in the pre- and post-reacted templates * zero or more individual keyword/value pairs may be appended to each react argument -* individual\_keyword = *prob* or *max\_rxn* or *stabilize\_steps* or *update\_edges* +* individual_keyword = *prob* or *max_rxn* or *stabilize_steps* or *update_edges* .. parsed-literal:: @@ -110,7 +110,7 @@ The *stabilization* keyword enables reaction site stabilization. Reaction site stabilization is performed by including reacting atoms in an internally-created fix :doc:`nve/limit ` time integrator for a set number of timesteps given by the -*stabilize\_steps* keyword. While reacting atoms are being time +*stabilize_steps* keyword. While reacting atoms are being time integrated by the internal nve/limit, they are prevented from being involved in any new reactions. The *xmax* value keyword should typically be set to the maximum distance that non-reacting atoms move @@ -123,7 +123,7 @@ automatically thermostatted by an internally-created :doc:`nve/limit ` integrator. The second group contains all atoms currently not involved in a reaction. This group should be used by a thermostat in order to time integrate the system. The name -of this group of non-reacting atoms is created by appending '\_REACT' +of this group of non-reacting atoms is created by appending '_REACT' to the group-ID argument of the *stabilization* keyword, as shown in the second example above. @@ -139,8 +139,8 @@ command creates a :doc:`dynamic group ` that is initialized to include all atoms. If the group-ID is that of an existing static group, the group is used as the parent group of new, internally-created dynamic group. In both cases, this new dynamic -group is named by appending '\_REACT' to the group-ID, e.g. -nvt\_grp\_REACT. By specifying an existing group, you may thermostat +group is named by appending '_REACT' to the group-ID, e.g. +nvt_grp_REACT. By specifying an existing group, you may thermostat constant-topology parts of your system separately. The dynamic group contains only atoms not involved in a reaction at a given timestep, and therefore should be used by a subsequent system-wide time @@ -285,7 +285,7 @@ Edges' and allows for forcing the update of a specific atom's atomic charge. The first column is the ID of an atom near the edge of the pre-reacted molecule template, and the value of the second column is either 'none' or 'charges.' Further details are provided in the -discussion of the 'update\_edges' keyword. The fifth optional section +discussion of the 'update_edges' keyword. The fifth optional section begins with the keyword 'Constraints' and lists additional criteria that must be satisfied in order for the reaction to occur. Currently, there are four types of constraints available, as discussed below. @@ -422,9 +422,9 @@ actually occurs. The fraction setting must be a value between 0.0 and 1.0. A uniform random number between 0.0 and 1.0 is generated and the eligible reaction only occurs if the random number is less than the fraction. Up to N reactions are permitted to occur, as optionally -specified by the *max\_rxn* keyword. +specified by the *max_rxn* keyword. -The *stabilize\_steps* keyword allows for the specification of how many +The *stabilize_steps* keyword allows for the specification of how many timesteps a reaction site is stabilized before being returned to the overall system thermostat. In order to produce the most physical behavior, this 'reaction site equilibration time' should be tuned to @@ -435,7 +435,7 @@ individually tuned for each fix reaction step. Note that in some situations, decreasing rather than increasing this parameter will result in an increase in stability. -The *update\_edges* keyword can increase the number of atoms whose +The *update_edges* keyword can increase the number of atoms whose atomic charges are updated, when the pre-reaction template contains edge atoms. When the value is set to 'charges,' all atoms' atomic charges are updated to those specified by the post-reaction template, @@ -461,7 +461,7 @@ such as small rings, that may be otherwise indistinguishable. Optionally, you can enforce additional behaviors on reacting atoms. For example, it may be beneficial to force reacting atoms to remain at a certain temperature. For this, you can use the internally-created -dynamic group named "bond\_react\_MASTER\_group", which consists of all +dynamic group named "bond_react_MASTER_group", which consists of all atoms currently involved in a reaction. For example, adding the following command would add an additional thermostat to the group of all currently-reacting atoms: @@ -487,7 +487,7 @@ local command. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** Cumulative reaction counts for each reaction are written to :doc:`binary restart files `. These values are associated with the reaction name (react-ID). Additionally, internally-created per-atom @@ -528,8 +528,8 @@ Related commands Default """"""" -The option defaults are stabilization = no, prob = 1.0, stabilize\_steps = 60, -update\_edges = none +The option defaults are stabilization = no, prob = 1.0, stabilize_steps = 60, +update_edges = none ---------- diff --git a/doc/src/fix_bond_swap.rst b/doc/src/fix_bond_swap.rst index 773bceb6e7..9427b0e780 100644 --- a/doc/src/fix_bond_swap.rst +++ b/doc/src/fix_bond_swap.rst @@ -129,17 +129,17 @@ appended and the group for the new compute is "all", so that the temperature of the entire system is used. Note that this is NOT the compute used by thermodynamic output (see -the :doc:`thermo_style ` command) with ID = *thermo\_temp*. +the :doc:`thermo_style ` command) with ID = *thermo_temp*. This means you can change the attributes of this fix's temperature (e.g. its degrees-of-freedom) via the :doc:`compute_modify ` command or print this temperature during thermodynamic output via the :doc:`thermo_style custom ` command using the appropriate compute-ID. -It also means that changing attributes of *thermo\_temp* will have no +It also means that changing attributes of *thermo_temp* will have no effect on this fix. ---------- -**Restart, fix\_modify, thermo output, run start/stop, minimize info:** +**Restart, fix_modify, thermo output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. Because the state of the random number generator is not saved in restart files, this means you cannot do "exact" @@ -174,7 +174,7 @@ This fix is part of the MC package. It is only enabled if LAMMPS was built with that package. See the :doc:`Build package ` doc page for more info. -The settings of the "special\_bond" command must be 0,1,1 in order to +The settings of the "special_bond" command must be 0,1,1 in order to use this fix, which is typical of bead-spring chains with FENE or harmonic bonds. This means that pairwise interactions between bonded atoms are turned off, but are turned on between atoms two or three diff --git a/doc/src/fix_box_relax.rst b/doc/src/fix_box_relax.rst index b7e5c5bb4c..7786a8faef 100644 --- a/doc/src/fix_box_relax.rst +++ b/doc/src/fix_box_relax.rst @@ -269,7 +269,7 @@ from a restart file. Because pressure is often a very sensitive function of volume, it can be difficult for the minimizer to equilibrate the system the desired pressure with high precision, particularly for solids. Some - techniques that seem to help are (a) use the "min\_modify line + techniques that seem to help are (a) use the "min_modify line quadratic" option when minimizing with box relaxations, (b) minimize several times in succession if need be, to drive the pressure closer to the target pressure, (c) relax the atom positions before relaxing @@ -292,23 +292,23 @@ as if these commands had been issued: compute fix-ID_press group-ID pressure fix-ID_temp virial See the :doc:`compute temp ` and :doc:`compute pressure ` commands for details. Note that the -IDs of the new computes are the fix-ID + underscore + "temp" or fix\_ID +IDs of the new computes are the fix-ID + underscore + "temp" or fix_ID + underscore + "press", and the group for the new computes is the same as the fix group. Also note that the pressure compute does not include a kinetic component. Note that these are NOT the computes used by thermodynamic output (see -the :doc:`thermo_style ` command) with ID = *thermo\_temp* -and *thermo\_press*. This means you can change the attributes of this +the :doc:`thermo_style ` command) with ID = *thermo_temp* +and *thermo_press*. This means you can change the attributes of this fix's temperature or pressure via the :doc:`compute_modify ` command or print this temperature or pressure during thermodynamic output via the :doc:`thermo_style custom ` command using the appropriate compute-ID. -It also means that changing attributes of *thermo\_temp* or -*thermo\_press* will have no effect on this fix. +It also means that changing attributes of *thermo_temp* or +*thermo_press* will have no effect on this fix. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. @@ -323,7 +323,7 @@ minimization, most likely in an undesirable way. .. note:: If both the *temp* and *press* keywords are used in a single - thermo\_modify command (or in two separate commands), then the order in + thermo_modify command (or in two separate commands), then the order in which the keywords are specified is important. Note that a :doc:`pressure compute ` defines its own temperature compute as an argument when it is specified. The *temp* keyword will override this (for the pressure compute being used by fix box/relax), but only if the diff --git a/doc/src/fix_client_md.rst b/doc/src/fix_client_md.rst index 2e7f04f01c..2e0cf84cc5 100644 --- a/doc/src/fix_client_md.rst +++ b/doc/src/fix_client_md.rst @@ -40,7 +40,7 @@ for the interacting particles to LAMMPS, so it can complete the timestep. Note that the server code can be a quantum code, or another classical -MD code which encodes a force field (pair\_style in LAMMPS lingo) which +MD code which encodes a force field (pair_style in LAMMPS lingo) which LAMMPS does not have. In the quantum case, this fix is a mechanism for running *ab initio* MD with quantum forces. @@ -66,7 +66,7 @@ LAMMPS and another code in tandem to perform a coupled simulation. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_cmap.rst b/doc/src/fix_cmap.rst index b2ce4d79ad..6f68d97c59 100644 --- a/doc/src/fix_cmap.rst +++ b/doc/src/fix_cmap.rst @@ -44,7 +44,7 @@ specified should contain the CMAP parameters for a particular version of the CHARMM force field. Two such files are including in the lammps/potentials directory: charmm22.cmap and charmm36.cmap. -The data file read by the "read\_data" must contain the topology of all +The data file read by the "read_data" must contain the topology of all the CMAP interactions, similar to the topology data for bonds, angles, dihedrals, etc. Specially it should have a line like this in its header section: @@ -71,7 +71,7 @@ interaction; it is an index into the CMAP force field file. The remaining 5 columns are the atom IDs of the atoms in the two 4-atom dihedrals that overlap to create the CMAP 5-body interaction. Note that the "crossterm" and "CMAP" keywords for the header and body -sections match those specified in the read\_data command following the +sections match those specified in the read_data command following the data file name; see the :doc:`read_data ` doc page for more details. @@ -90,7 +90,7 @@ the note below about how to include the CMAP energy when performing an ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the list of CMAP cross-terms to :doc:`binary restart files `. See the :doc:`read_restart ` command for info on how to re-specify a fix in an input script that reads a diff --git a/doc/src/fix_colvars.rst b/doc/src/fix_colvars.rst index af778b2207..20315624d6 100644 --- a/doc/src/fix_colvars.rst +++ b/doc/src/fix_colvars.rst @@ -90,7 +90,7 @@ fix that thermostats all atoms in the fix colvars group. This will be used to provide the colvars module with the current thermostat target temperature. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the current status of the colvars module into :doc:`binary restart files `. This is in addition to the text @@ -101,12 +101,12 @@ The :doc:`fix_modify ` *energy* option is supported by this fix to add the energy change from the biasing force added by the fix to the system's potential energy as part of :doc:`thermodynamic output `. -The *fix\_modify configfile * option allows to add settings +The *fix_modify configfile * option allows to add settings from an additional config file to the colvars module. This option can only be used, after the system has been initialized with a :doc:`run ` command. -The *fix\_modify config * option allows to add settings +The *fix_modify config * option allows to add settings from inline strings. Those have to fit on a single line when enclosed in a pair of double quotes ("), or can span multiple lines when bracketed by a pair of triple double quotes (""", like python embedded documentation). diff --git a/doc/src/fix_controller.rst b/doc/src/fix_controller.rst index 3d14bdee08..45ff47f868 100644 --- a/doc/src/fix_controller.rst +++ b/doc/src/fix_controller.rst @@ -17,7 +17,7 @@ Syntax * Kp = proportional gain in PID equation (unitless) * Ki = integral gain in PID equation (unitless) * Kd = derivative gain in PID equation (unitless) -* pvar = process variable of form c\_ID, c\_ID[I], f\_ID, f\_ID[I], or v\_name +* pvar = process variable of form c_ID, c_ID[I], f_ID, f_ID[I], or v_name .. parsed-literal:: @@ -152,7 +152,7 @@ The process variable *pvar* can be specified as the output of a :doc:`variable `. In each case, the compute, fix, or variable must produce a global quantity, not a per-atom or local quantity. -If *pvar* begins with "c\_", a compute ID must follow which has been +If *pvar* begins with "c_", a compute ID must follow which has been previously defined in the input script and which generates a global scalar or vector. See the individual :doc:`compute ` doc page for details. If no bracketed integer is appended, the scalar @@ -160,7 +160,7 @@ calculated by the compute is used. If a bracketed integer is appended, the Ith value of the vector calculated by the compute is used. Users can also write code for their own compute styles and :doc:`add them to LAMMPS `. -If *pvar* begins with "f\_", a fix ID must follow which has been +If *pvar* begins with "f_", a fix ID must follow which has been previously defined in the input script and which generates a global scalar or vector. See the individual :doc:`fix ` doc page for details. Note that some fixes only produce their values on certain @@ -170,7 +170,7 @@ is appended, the scalar calculated by the fix is used. If a bracketed integer is appended, the Ith value of the vector calculated by the fix is used. Users can also write code for their own fix style and :doc:`add them to LAMMPS `. -If *pvar* begins with "v\_", a variable name must follow which has been +If *pvar* begins with "v_", a variable name must follow which has been previously defined in the input script. Only equal-style variables can be referenced. See the :doc:`variable ` command for details. Note that variables of style *equal* define a formula which @@ -183,14 +183,14 @@ The target value *setpoint* for the process variable must be a numeric value, in whatever units *pvar* is defined for. The control variable *cvar* must be the name of an :doc:`internal-style variable ` previously defined in the input script. Note -that it is not specified with a "v\_" prefix, just the name of the +that it is not specified with a "v_" prefix, just the name of the variable. It must be an internal-style variable, because this fix updates its value directly. Note that other commands can use an equal-style versus internal-style variable interchangeably. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** Currently, no information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. diff --git a/doc/src/fix_deform.rst b/doc/src/fix_deform.rst index 7001b2304e..75fc6cc5c9 100644 --- a/doc/src/fix_deform.rst +++ b/doc/src/fix_deform.rst @@ -581,7 +581,7 @@ by including their suffix, or you can use the :doc:`-suffix command-line switch See the :doc:`Speed packages ` doc page for more instructions on how to use the accelerated styles effectively. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix will restore the initial box settings from :doc:`binary restart files `, which allows the fix to be properly continue deformation, when using the start/stop options of the :doc:`run ` diff --git a/doc/src/fix_deposit.rst b/doc/src/fix_deposit.rst index c379dcd9b0..31df74ce9b 100644 --- a/doc/src/fix_deposit.rst +++ b/doc/src/fix_deposit.rst @@ -163,7 +163,7 @@ command which also appears in your input script. If you wish the new rigid molecules (and other rigid molecules) to be thermostatted correctly via :doc:`fix rigid/small/nvt ` or :doc:`fix rigid/small/npt `, then you need to use the - "fix\_modify dynamic/dof yes" command for the rigid fix. This is to + "fix_modify dynamic/dof yes" command for the rigid fix. This is to inform that fix that the molecule count will vary dynamically. If you wish to insert molecules via the *mol* keyword, that will have @@ -271,7 +271,7 @@ units of distance or velocity. the :doc:`compute_modify dynamic yes ` command for the temperature compute you are using. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the state of the deposition to :doc:`binary restart files `. This includes information about how many particles have been deposited, the random number generator seed, the diff --git a/doc/src/fix_dpd_energy.rst b/doc/src/fix_dpd_energy.rst index f7dc52fbe6..0eeb8f9478 100644 --- a/doc/src/fix_dpd_energy.rst +++ b/doc/src/fix_dpd_energy.rst @@ -41,9 +41,9 @@ This fix must be used with the :doc:`pair_style dpd/fdt/energy ` com Note that numerous variants of DPD can be specified by choosing an appropriate combination of the integrator and :doc:`pair_style dpd/fdt/energy ` command. DPD under isoenergetic conditions -can be specified by using fix *dpd/energy*\ , fix *nve* and pair\_style +can be specified by using fix *dpd/energy*\ , fix *nve* and pair_style *dpd/fdt/energy*\ . DPD under isoenthalpic conditions can -be specified by using fix *dpd/energy*\ , fix *nph* and pair\_style +be specified by using fix *dpd/energy*\ , fix *nph* and pair_style *dpd/fdt/energy*\ . Examples of each DPD variant are provided in the examples/USER/dpd directory. diff --git a/doc/src/fix_dpd_source.rst b/doc/src/fix_dpd_source.rst index 8a2cd885ee..5ea1c85fb4 100644 --- a/doc/src/fix_dpd_source.rst +++ b/doc/src/fix_dpd_source.rst @@ -64,7 +64,7 @@ cuboid domain to apply the source flux to. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_drag.rst b/doc/src/fix_drag.rst index 74d98d7a40..792d4725cc 100644 --- a/doc/src/fix_drag.rst +++ b/doc/src/fix_drag.rst @@ -38,7 +38,7 @@ application. This command can be used to steer one or more atoms to a new location in the simulation. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_drude_transform.rst b/doc/src/fix_drude_transform.rst index 7a17ab98cf..607c161572 100644 --- a/doc/src/fix_drude_transform.rst +++ b/doc/src/fix_drude_transform.rst @@ -151,9 +151,9 @@ relative coordinates, are calculated using :doc:`compute temp/drude `. diff --git a/doc/src/fix_dt_reset.rst b/doc/src/fix_dt_reset.rst index e86d11ac94..861134f745 100644 --- a/doc/src/fix_dt_reset.rst +++ b/doc/src/fix_dt_reset.rst @@ -80,7 +80,7 @@ Note that the cumulative simulation time (in time units), which accounts for changes in the timestep size as a simulation proceeds, can be accessed by the :doc:`thermo_style time ` keyword. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. diff --git a/doc/src/fix_efield.rst b/doc/src/fix_efield.rst index 9084cbc2d6..0410803c13 100644 --- a/doc/src/fix_efield.rst +++ b/doc/src/fix_efield.rst @@ -43,7 +43,7 @@ external electric field. For charges, any of the 3 quantities defining the E-field components can be specified as an equal-style or atom-style :doc:`variable `, namely *ex*\ , *ey*\ , *ez*\ . If the value is a -variable, it should be specified as v\_name, where name is the variable +variable, it should be specified as v_name, where name is the variable name. In this case, the variable will be evaluated each timestep, and its value used to determine the E-field component. @@ -101,7 +101,7 @@ minimize the orientation of dipoles in an applied electric field. The *energy* keyword specifies the name of an atom-style :doc:`variable ` which is used to compute the energy of each atom as function of its position. Like variables used for *ex*\ , *ey*\ , -*ez*\ , the energy variable is specified as v\_name, where name is the +*ez*\ , the energy variable is specified as v_name, where name is the variable name. Note that when the *energy* keyword is used during an energy @@ -114,7 +114,7 @@ minimization will not converge properly. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_ehex.rst b/doc/src/fix_ehex.rst index 96eb94db01..4e2ea3a73d 100644 --- a/doc/src/fix_ehex.rst +++ b/doc/src/fix_ehex.rst @@ -99,7 +99,7 @@ velocity of that reservoir. The thermostatting force does not affect the center of mass velocities of the individual reservoirs and the entire simulation box. A derivation of the equations and details on the numerical implementation with velocity Verlet in LAMMPS can be -found in reference "(Wirnsberger)"#\_Wirnsberger. +found in reference "(Wirnsberger)"#_Wirnsberger. .. note:: @@ -163,7 +163,7 @@ constraints will be satisfied. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. diff --git a/doc/src/fix_electron_stopping.rst b/doc/src/fix_electron_stopping.rst index 5fea8a3d6d..cead9f7a12 100644 --- a/doc/src/fix_electron_stopping.rst +++ b/doc/src/fix_electron_stopping.rst @@ -129,7 +129,7 @@ scientific publications, experimental databases or by using of the impact parameter of the ion; these results can be used to derive the stopping power. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. @@ -159,7 +159,7 @@ The default is no limitation by region, and minneigh = 1. .. _elstopping: -**(electronic stopping)** Wikipedia - Electronic Stopping Power: https://en.wikipedia.org/wiki/Stopping\_power\_%28particle\_radiation%29 +**(electronic stopping)** Wikipedia - Electronic Stopping Power: https://en.wikipedia.org/wiki/Stopping_power_%28particle_radiation%29 .. _Nordlund98: @@ -175,7 +175,7 @@ The default is no limitation by region, and minneigh = 1. .. _CasP: -**(CasP)** CasP webpage: https://www.helmholtz-berlin.de/people/gregor-schiwietz/casp\_en.html +**(CasP)** CasP webpage: https://www.helmholtz-berlin.de/people/gregor-schiwietz/casp_en.html .. _PASS: diff --git a/doc/src/fix_enforce2d.rst b/doc/src/fix_enforce2d.rst index f775572720..d33dd25a61 100644 --- a/doc/src/fix_enforce2d.rst +++ b/doc/src/fix_enforce2d.rst @@ -52,7 +52,7 @@ instructions on how to use the accelerated styles effectively. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_eos_table.rst b/doc/src/fix_eos_table.rst index a21de28b04..3800aa0c53 100644 --- a/doc/src/fix_eos_table.rst +++ b/doc/src/fix_eos_table.rst @@ -28,8 +28,8 @@ Description """"""""""" Fix *eos/table* applies a tabulated mesoparticle equation of state to -relate the particle internal energy (u\_i) to the particle internal -temperature (dpdTheta\_i). +relate the particle internal energy (u_i) to the particle internal +temperature (dpdTheta_i). Fix *eos/table* creates interpolation tables of length *N* from internal energy values listed in a file as a function of internal diff --git a/doc/src/fix_evaporate.rst b/doc/src/fix_evaporate.rst index 8883940002..d6b9c6ae34 100644 --- a/doc/src/fix_evaporate.rst +++ b/doc/src/fix_evaporate.rst @@ -72,7 +72,7 @@ incur overhead due to the cost of building neighbor lists. :doc:`compute_modify dynamic yes ` command for the temperature compute you are using. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. diff --git a/doc/src/fix_external.rst b/doc/src/fix_external.rst index 01020d27b2..a77545d294 100644 --- a/doc/src/fix_external.rst +++ b/doc/src/fix_external.rst @@ -67,13 +67,13 @@ The arguments are as follows: Note that *timestep* is a "bigint" which is defined in src/lmptype.h, typically as a 64-bit integer. And *ids* is a pointer to type "tagint" which is typically a 32-bit integer unless LAMMPS is compiled with --DLAMMPS\_BIGBIG. For more info please see the :ref:`build settings +-DLAMMPS_BIGBIG. For more info please see the :ref:`build settings ` section of the manual. Finally, *fexternal* are the forces returned by the driver program. -The fix has a set\_callback() method which the external driver can call +The fix has a set_callback() method which the external driver can call to pass a pointer to its foo() function. See the -couple/lammps\_quest/lmpqst.cpp file in the LAMMPS distribution for an +couple/lammps_quest/lmpqst.cpp file in the LAMMPS distribution for an example of how this is done. This sample application performs classical MD using quantum forces computed by a density functional code `Quest `_. @@ -125,7 +125,7 @@ insure this energy setting is used appropriately in a minimization. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_ffl.rst b/doc/src/fix_ffl.rst index 837e1c310c..ac23175875 100644 --- a/doc/src/fix_ffl.rst +++ b/doc/src/fix_ffl.rst @@ -68,11 +68,11 @@ different numbers of processors. The flipping type *flip-type* can be chosen between 4 types described in :ref:`(Hijazi) `. The flipping operation occurs during the thermostatting -step and it flips the momenta of the atoms. If no\_flip is chosen, no flip +step and it flips the momenta of the atoms. If no_flip is chosen, no flip will be executed and the integration will be the same as a standard Langevin thermostat :ref:`(Bussi) `. The other flipping types are : rescale - hard - soft. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** The instantaneous values of the extended variables are written to :doc:`binary restart files `. Because the state of the random diff --git a/doc/src/fix_filter_corotate.rst b/doc/src/fix_filter_corotate.rst index 162b3c244b..1731ef94a2 100644 --- a/doc/src/fix_filter_corotate.rst +++ b/doc/src/fix_filter_corotate.rst @@ -60,7 +60,7 @@ If the clusters are chosen suitably, the :doc:`run_style respa ` is s ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about these fixes is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to these fixes. No global or per-atom quantities are diff --git a/doc/src/fix_flow_gauss.rst b/doc/src/fix_flow_gauss.rst index 9c1b6711e9..7b9e001bd3 100644 --- a/doc/src/fix_flow_gauss.rst +++ b/doc/src/fix_flow_gauss.rst @@ -68,7 +68,7 @@ other methods, such as the pump method :ref:`(Zhu) `. The pressure correction is discussed and described in :ref:`(Strong) `. For a complete example including the considerations discussed -above, see the examples/USER/flow\_gauss directory. +above, see the examples/USER/flow_gauss directory. .. note:: @@ -91,13 +91,13 @@ expensive than usual, so it is not performed by default. To invoke the work calculation, use the *energy* keyword. The :doc:`fix_modify ` *energy* option also invokes the work calculation, and overrides an *energy no* setting here. If neither -*energy yes* or *fix\_modify energy yes* are set, the global scalar +*energy yes* or *fix_modify energy yes* are set, the global scalar computed by the fix will return zero. .. note:: In order to check energy conservation, any other fixes that do - work on the system must have *fix\_modify energy yes* set as well. This + work on the system must have *fix_modify energy yes* set as well. This includes thermostat fixes and any constraints that hold the positions of wall atoms fixed, such as :doc:`fix spring/self `. @@ -111,12 +111,12 @@ computed at different rRESPA levels, then there must be a separate flow/gauss fix for each level. For example, if the flowing fluid and obstacle interact through pairwise and long-range Coulomb interactions, which are computed at rRESPA levels 3 and 4, respectively, then there must be two separate -flow/gauss fixes, one that specifies *fix\_modify respa 3* and one with -*fix\_modify respa 4*. +flow/gauss fixes, one that specifies *fix_modify respa 3* and one with +*fix_modify respa 4*. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix is part of the USER-MISC package. It is only enabled if LAMMPS was built with that package. See the :doc:`Build package ` doc page for more info. diff --git a/doc/src/fix_freeze.rst b/doc/src/fix_freeze.rst index cec9064aba..d6659dc8f8 100644 --- a/doc/src/fix_freeze.rst +++ b/doc/src/fix_freeze.rst @@ -56,7 +56,7 @@ instructions on how to use the accelerated styles effectively. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. diff --git a/doc/src/fix_gcmc.rst b/doc/src/fix_gcmc.rst index 01954a3639..77a0323000 100644 --- a/doc/src/fix_gcmc.rst +++ b/doc/src/fix_gcmc.rst @@ -169,7 +169,7 @@ at a random position within the current simulation cell or region, and new atom velocities are randomly chosen from the specified temperature distribution given by T. The effective temperature for new atom velocities can be increased or decreased using the optional keyword -*tfac\_insert* (see below). Relative coordinates for atoms in a +*tfac_insert* (see below). Relative coordinates for atoms in a molecule are taken from the template molecule provided by the user. The center of mass of the molecule is placed at the insertion point. The orientation of the molecule is chosen at random by rotating @@ -200,7 +200,7 @@ which also appears in your input script. If you wish the new rigid molecules (and other rigid molecules) to be thermostatted correctly via :doc:`fix rigid/small/nvt ` or :doc:`fix rigid/small/npt `, then you need to use the - "fix\_modify dynamic/dof yes" command for the rigid fix. This is to + "fix_modify dynamic/dof yes" command for the rigid fix. This is to inform that fix that the molecule count will vary dynamically. If you wish to insert molecules via the *mol* keyword, that will have @@ -247,13 +247,13 @@ as: \mu = \mu^{id} + \mu^{ex} -The second term mu\_ex is the excess chemical potential due to +The second term mu_ex is the excess chemical potential due to energetic interactions and is formally zero for the fictitious gas reservoir but is non-zero for interacting systems. So, while the chemical potential of the reservoir and the simulation cell are equal, -mu\_ex is not, and as a result, the densities of the two are generally -quite different. The first term mu\_id is the ideal gas contribution -to the chemical potential. mu\_id can be related to the density or +mu_ex is not, and as a result, the densities of the two are generally +quite different. The first term mu_id is the ideal gas contribution +to the chemical potential. mu_id can be related to the density or pressure of the fictitious gas reservoir by: .. math:: @@ -283,9 +283,9 @@ As an alternative to specifying mu directly, the ideal gas reservoir can be defined by its pressure *P* using the *pressure* keyword, in which case the user-specified chemical potential is ignored. The user may also specify the fugacity coefficient :math:`\phi` using the -*fugacity\_coeff* keyword, which defaults to unity. +*fugacity_coeff* keyword, which defaults to unity. -The *full\_energy* option means that the fix calculates the total +The *full_energy* option means that the fix calculates the total potential energy of the entire simulated system, instead of just the energy of the part that is changed. The total system energy before and after the proposed GCMC exchange or MC move @@ -296,7 +296,7 @@ in which case only partial energies are computed to determine the energy difference due to the proposed change. -The *full\_energy* option is needed for systems with complicated +The *full_energy* option is needed for systems with complicated potential energy calculations, including the following: * long-range electrostatics (kspace) @@ -306,18 +306,18 @@ potential energy calculations, including the following: * tail corrections * need to include potential energy contributions from other fixes -In these cases, LAMMPS will automatically apply the *full\_energy* +In these cases, LAMMPS will automatically apply the *full_energy* keyword and issue a warning message. -When the *mol* keyword is used, the *full\_energy* option also includes +When the *mol* keyword is used, the *full_energy* option also includes the intramolecular energy of inserted and deleted molecules, whereas -this energy is not included when *full\_energy* is not used. If this -is not desired, the *intra\_energy* keyword can be used to define an +this energy is not included when *full_energy* is not used. If this +is not desired, the *intra_energy* keyword can be used to define an amount of energy that is subtracted from the final energy when a molecule is inserted, and subtracted from the initial energy when a molecule is deleted. For molecules that have a non-zero intramolecular energy, this will ensure roughly the same behavior whether or not the -*full\_energy* option is used. +*full_energy* option is used. Inserted atoms and molecules are assigned random velocities based on the specified temperature *T*. Because the relative velocity of all @@ -325,10 +325,10 @@ atoms in the molecule is zero, this may result in inserted molecules that are systematically too cold. In addition, the intramolecular potential energy of the inserted molecule may cause the kinetic energy of the molecule to quickly increase or decrease after insertion. The -*tfac\_insert* keyword allows the user to counteract these effects by +*tfac_insert* keyword allows the user to counteract these effects by changing the temperature used to assign velocities to inserted atoms and molecules by a constant factor. For a particular application, some -experimentation may be required to find a value of *tfac\_insert* that +experimentation may be required to find a value of *tfac_insert* that results in inserted molecules that equilibrate quickly to the correct temperature. @@ -373,13 +373,13 @@ in the context of NVT dynamics. solution is to start a new simulation after the equilibrium density has been reached. -With some pair\_styles, such as :doc:`Buckingham `, +With some pair_styles, such as :doc:`Buckingham `, :doc:`Born-Mayer-Huggins ` and :doc:`ReaxFF `, two atoms placed close to each other may have an arbitrary large, negative potential energy due to the functional form of the potential. While these unphysical configurations are inaccessible to typical dynamical trajectories, they can be generated by Monte Carlo moves. The -*overlap\_cutoff* keyword suppresses these moves by effectively +*overlap_cutoff* keyword suppresses these moves by effectively assigning an infinite positive energy to all new configurations that place any pair of atoms closer than the specified overlap cutoff distance. @@ -395,7 +395,7 @@ The *group* keyword adds all inserted atoms to the adds all inserted atoms of the specified type to the :doc:`group ` of the group-ID value. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the state of the fix to :doc:`binary restart files `. This includes information about the random number generator seed, the next timestep for MC exchanges, the number @@ -438,7 +438,7 @@ This fix is part of the MC package. It is only enabled if LAMMPS was built with that package. See the :doc:`Build package ` doc page for more info. -Do not set "neigh\_modify once yes" or else this fix will never be +Do not set "neigh_modify once yes" or else this fix will never be called. Reneighboring is required. Can be run in parallel, but aspects of the GCMC part will not scale @@ -472,11 +472,11 @@ Related commands Default """"""" -The option defaults are mol = no, maxangle = 10, overlap\_cutoff = 0.0, -fugacity\_coeff = 1.0, intra\_energy = 0.0, tfac\_insert = 1.0. +The option defaults are mol = no, maxangle = 10, overlap_cutoff = 0.0, +fugacity_coeff = 1.0, intra_energy = 0.0, tfac_insert = 1.0. (Patomtrans, Pmoltrans, Pmolrotate) = (1, 0, 0) for mol = no and -(0, 1, 1) for mol = yes. full\_energy = no, -except for the situations where full\_energy is required, as +(0, 1, 1) for mol = yes. full_energy = no, +except for the situations where full_energy is required, as listed above. ---------- diff --git a/doc/src/fix_gld.rst b/doc/src/fix_gld.rst index d5e4fd6f4a..cb93804b1a 100644 --- a/doc/src/fix_gld.rst +++ b/doc/src/fix_gld.rst @@ -13,11 +13,11 @@ Syntax * ID, group-ID are documented in :doc:`fix ` command * gld = style name of this fix command * Tstart,Tstop = desired temperature at start/end of run (temperature units) -* N\_k = number of terms in the Prony series representation of the memory kernel +* N_k = number of terms in the Prony series representation of the memory kernel * seed = random number seed to use for white noise (positive integer) * series = *pprony* is presently the only available option -* c\_k = the weight of the kth term in the Prony series (mass per time units) -* tau\_k = the time constant of the kth term in the Prony series (time units) +* c_k = the weight of the kth term in the Prony series (mass per time units) +* tau_k = the time constant of the kth term in the Prony series (time units) * zero or more keyword/value pairs may be appended .. parsed-literal:: diff --git a/doc/src/fix_gle.rst b/doc/src/fix_gle.rst index d4eecaf903..fb6006d514 100644 --- a/doc/src/fix_gle.rst +++ b/doc/src/fix_gle.rst @@ -99,7 +99,7 @@ input matrix for :doc:`fix gle `. While the GLE scheme is more general, the form used by :doc:`fix gld ` can be more directly related to the representation of an implicit solvent environment. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** The instantaneous values of the extended variables are written to :doc:`binary restart files `. Because the state of the random diff --git a/doc/src/fix_gravity.rst b/doc/src/fix_gravity.rst index 06e9581f56..1d31384911 100644 --- a/doc/src/fix_gravity.rst +++ b/doc/src/fix_gravity.rst @@ -82,7 +82,7 @@ length is ignored. For 2d systems, the *z* component is ignored. Any of the quantities *magnitude*\ , *angle*\ , *phi*\ , *theta*\ , *x*\ , *y*\ , *z* which define the gravitational magnitude and direction, can be specified as an equal-style :doc:`variable `. If the value is -a variable, it should be specified as v\_name, where name is the +a variable, it should be specified as v_name, where name is the variable name. In this case, the variable will be evaluated each timestep, and its value used to determine the quantity. You should insure that the variable calculates a result in the appropriate units, @@ -116,7 +116,7 @@ instructions on how to use the accelerated styles effectively. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_grem.rst b/doc/src/fix_grem.rst index 95a15513d4..eef39c1ffc 100644 --- a/doc/src/fix_grem.rst +++ b/doc/src/fix_grem.rst @@ -83,7 +83,7 @@ to large temperature changes. Replicas are easily added where needed. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_halt.rst b/doc/src/fix_halt.rst index 25ec154ffb..97e5487adf 100644 --- a/doc/src/fix_halt.rst +++ b/doc/src/fix_halt.rst @@ -13,7 +13,7 @@ Syntax * ID, group-ID are documented in :doc:`fix ` command * halt = style name of this fix command * N = check halt condition every N steps -* attribute = *bondmax* or *tlimit* or v\_name +* attribute = *bondmax* or *tlimit* or v_name .. parsed-literal:: @@ -50,7 +50,7 @@ specified by the :doc:`run ` or :doc:`minimize ` command. The specified group-ID is ignored by this fix. The specified *attribute* can be one of the options listed above, -namely *bondmax* or *tlimit*\ , or an :doc:`equal-style variable ` referenced as *v\_name*, where "name" is the +namely *bondmax* or *tlimit*\ , or an :doc:`equal-style variable ` referenced as *v_name*, where "name" is the name of a variable that has been defined previously in the input script. @@ -66,7 +66,7 @@ using this method versus the timer command option. The first is that the clock starts at the beginning of the current run (not when the timer or fix command is specified), so that any setup time for the run is not included in the elapsed time. The second is that the timer -invocation and syncing across all processors (via MPI\_Allreduce) is +invocation and syncing across all processors (via MPI_Allreduce) is not performed once every *N* steps by this command. Instead it is performed (typically) only a small number of times and the elapsed times are used to predict when the end-of-the-run will be. Both of @@ -138,7 +138,7 @@ is printed; the run simply exits. The latter may be desirable for post-processing tools that extract thermodynamic information from log files. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_heat.rst b/doc/src/fix_heat.rst index cf046fe000..3412daf63c 100644 --- a/doc/src/fix_heat.rst +++ b/doc/src/fix_heat.rst @@ -72,8 +72,8 @@ time. In this case, each value is an "intensive" quantity, which need not be scaled with the number of atoms in the group. As mentioned above, the *eflux* parameter can be specified as an -equal-style or atom\_style :doc:`variable `. If the value is a -variable, it should be specified as v\_name, where name is the variable +equal-style or atom_style :doc:`variable `. If the value is a +variable, it should be specified as v_name, where name is the variable name. In this case, the variable will be evaluated each timestep, and its value(s) used to determine the flux. @@ -108,7 +108,7 @@ their velocities. Thus you must still use an integration fix not normally be used on atoms that have their temperature controlled by another fix - e.g. :doc:`fix nvt ` or :doc:`fix langevin ` fix. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. diff --git a/doc/src/fix_hyper_global.rst b/doc/src/fix_hyper_global.rst index 8ac25ede9b..c24d405b55 100644 --- a/doc/src/fix_hyper_global.rst +++ b/doc/src/fix_hyper_global.rst @@ -129,7 +129,7 @@ timesteps is simply t_{hyper} = \sum_{i=1,N} B-i \cdot dt where *dt* is the timestep size defined by the :doc:`timestep ` -command. The effective time acceleration due to GHD is thus t\_hyper / +command. The effective time acceleration due to GHD is thus t_hyper / N\*dt, where N\*dt is elapsed time for a normal MD run of N timesteps. Note that in GHD, the boost factor varies from timestep to timestep. @@ -176,7 +176,7 @@ time-accurate trajectory of the system. Note that if *Vmax* is set too small, the GHD simulation will run correctly. There will just be fewer events because the hyper time -(t\_hyper equation above) will be shorter. +(t_hyper equation above) will be shorter. .. note:: @@ -197,7 +197,7 @@ algorithm. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_hyper_local.rst b/doc/src/fix_hyper_local.rst index 5b837ee275..a8e7483dac 100644 --- a/doc/src/fix_hyper_local.rst +++ b/doc/src/fix_hyper_local.rst @@ -245,7 +245,7 @@ well for many solid-state systems. atoms move (between quenched states) to be considered an "event". It is an argument to the "compute event/displace" command used to detect events. By default the ghost communication distance is set by the - pair\_style cutoff, which will typically be < *Dcut*\ . The :doc:`comm_modify cutoff ` command should be used to override the ghost + pair_style cutoff, which will typically be < *Dcut*\ . The :doc:`comm_modify cutoff ` command should be used to override the ghost cutoff explicitly, e.g. .. code-block:: LAMMPS @@ -268,7 +268,7 @@ inverse of the alpha parameter discussed in The *Btarget* argument is the desired time boost factor (a value > 1) that all the atoms in the system will experience. The elapsed time -t\_hyper for an LHD simulation running for *N* timesteps is simply +t_hyper for an LHD simulation running for *N* timesteps is simply .. math:: @@ -293,7 +293,7 @@ is the specified temperature of the system Note that if *Btarget* is set smaller than this, the LHD simulation will run correctly. There will just be fewer events because the hyper -time (t\_hyper equation above) will be shorter. +time (t_hyper equation above) will be shorter. .. note:: @@ -365,7 +365,7 @@ enabled by these keywords. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_imd.rst b/doc/src/fix_imd.rst index 1db18e515f..fe54e5bf50 100644 --- a/doc/src/fix_imd.rst +++ b/doc/src/fix_imd.rst @@ -44,7 +44,7 @@ IMD protocol, as initially implemented in VMD and NAMD. Specifically it allows LAMMPS to connect an IMD client, for example the `VMD visualization program `_, so that it can monitor the progress of the simulation and interactively apply forces to selected atoms. -If LAMMPS is compiled with the pre-processor flag -DLAMMPS\_ASYNC\_IMD +If LAMMPS is compiled with the pre-processor flag -DLAMMPS_ASYNC_IMD then fix imd will use POSIX threads to spawn a IMD communication thread on MPI rank 0 in order to offload data reading and writing from the main execution thread and potentially lower the inferred @@ -137,7 +137,7 @@ screen output is active. .. _vrpnicms: http://sites.google.com/site/akohlmey/software/vrpn-icms -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global scalar or vector or per-atom diff --git a/doc/src/fix_indent.rst b/doc/src/fix_indent.rst index 945b28efdc..ef62506591 100644 --- a/doc/src/fix_indent.rst +++ b/doc/src/fix_indent.rst @@ -100,7 +100,7 @@ be specified as an equal-style :doc:`variable `, namely *x*\ , *y*\ , *z*\ , or *R*\ . Similarly, for a cylindrical indenter, any of *c1*\ , *c2*\ , or *R*\ , can be a variable. For a planar indenter, *pos* can be a variable. If the value is a variable, it should be specified as -v\_name, where name is the variable name. In this case, the variable +v_name, where name is the variable name. In this case, the variable will be evaluated each timestep, and its value used to define the indenter geometry. @@ -112,7 +112,7 @@ change as a function of time or span consecutive runs in a continuous fashion. For the latter, see the *start* and *stop* keywords of the :doc:`run ` command and the *elaplong* keyword of :doc:`thermo_style custom ` for details. -For example, if a spherical indenter's x-position is specified as v\_x, +For example, if a spherical indenter's x-position is specified as v_x, then this variable definition will keep it's center at a relative position in the simulation box, 1/4 of the way from the left edge to the right edge, even if the box size changes: @@ -129,7 +129,7 @@ from an initial position at 2.5 at a constant velocity of 5: variable x equal "2.5 + 5*elaplong*dt" variable x equal vdisplace(2.5,5) -If a spherical indenter's radius is specified as v\_r, then these +If a spherical indenter's radius is specified as v_r, then these variable definitions will grow the size of the indenter at a specified rate. @@ -176,7 +176,7 @@ contains *xlat*\ , *ylat*\ , *zlat* keywords of the variable k equal 100.0/xlat/xlat fix 1 all indent $k sphere ... -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_ipi.rst b/doc/src/fix_ipi.rst index 58049bc4ac..d60b25248d 100644 --- a/doc/src/fix_ipi.rst +++ b/doc/src/fix_ipi.rst @@ -69,7 +69,7 @@ If the cell varies too wildly, it may be advisable to re-initialize these interactions at each call. This behavior can be requested by setting the *reset* switch. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** There is no restart information associated with this fix, since all the dynamical parameters are dealt with by i-PI. diff --git a/doc/src/fix_langevin.rst b/doc/src/fix_langevin.rst index f282499bcc..7a45293db9 100644 --- a/doc/src/fix_langevin.rst +++ b/doc/src/fix_langevin.rst @@ -122,7 +122,7 @@ run from *Tstart* to *Tstop*\ . *Tstart* can be specified as an equal-style or atom-style :doc:`variable `. In this case, the *Tstop* setting is ignored. If the value is a variable, it should be specified as -v\_name, where name is the variable name. In this case, the variable +v_name, where name is the variable name. In this case, the variable will be evaluated each timestep, and its value used to determine the target temperature. @@ -173,8 +173,8 @@ The keyword *angmom* and *omega* keywords enable thermostatting of rotational degrees of freedom in addition to the usual translational degrees of freedom. This can only be done for finite-size particles. -A simulation using atom\_style sphere defines an omega for finite-size -spheres. A simulation using atom\_style ellipsoid defines a finite +A simulation using atom_style sphere defines an omega for finite-size +spheres. A simulation using atom_style ellipsoid defines a finite size and shape for aspherical particles and an angular momentum. The Langevin formulas for thermostatting the rotational degrees of freedom are the same as those above, where force is replaced by @@ -288,7 +288,7 @@ instructions on how to use the accelerated styles effectively. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. Because the state of the random number generator is not saved in restart files, this means you cannot do "exact" @@ -323,7 +323,7 @@ Restrictions """""""""""" For *gjf* do not choose damp=dt/2. *gjf* is not compatible -with run\_style respa. +with run_style respa. Related commands """""""""""""""" diff --git a/doc/src/fix_langevin_drude.rst b/doc/src/fix_langevin_drude.rst index bcfc4878a4..f361a88736 100644 --- a/doc/src/fix_langevin_drude.rst +++ b/doc/src/fix_langevin_drude.rst @@ -13,11 +13,11 @@ Syntax * ID, group-ID are documented in :doc:`fix ` command * langevin/drude = style name of this fix command * Tcom = desired temperature of the centers of mass (temperature units) -* damp\_com = damping parameter for the thermostat on centers of mass (time units) -* seed\_com = random number seed to use for white noise of the thermostat on centers of mass (positive integer) +* damp_com = damping parameter for the thermostat on centers of mass (time units) +* seed_com = random number seed to use for white noise of the thermostat on centers of mass (positive integer) * Tdrude = desired temperature of the Drude oscillators (temperature units) -* damp\_drude = damping parameter for the thermostat on Drude oscillators (time units) -* seed\_drude = random number seed to use for white noise of the thermostat on Drude oscillators (positive integer) +* damp_drude = damping parameter for the thermostat on Drude oscillators (time units) +* seed_drude = random number seed to use for white noise of the thermostat on Drude oscillators (positive integer) * zero or more keyword/value pairs may be appended * keyword = *zero* @@ -76,16 +76,16 @@ The Langevin forces are computed as .. math:: - F' = - \frac {M'} {\mathtt{damp\_com}}\, V' + F_r' + F' = - \frac {M'} {\mathtt{damp_com}}\, V' + F_r' .. math:: - f' = - \frac {m'} {\mathtt{damp\_drude}}\, v' + f_r' + f' = - \frac {m'} {\mathtt{damp_drude}}\, v' + f_r' :math:`F_r'` is a random force proportional to -:math:`\sqrt { \frac {2\, k_B \mathtt{Tcom}\, m'} {\mathrm dt\, \mathtt{damp\_com} } }`. +:math:`\sqrt { \frac {2\, k_B \mathtt{Tcom}\, m'} {\mathrm dt\, \mathtt{damp_com} } }`. :math:`f_r'` is a random force proportional to -:math:`\sqrt { \frac {2\, k_B \mathtt{Tdrude}\, m'} {\mathrm dt\, \mathtt{damp\_drude} } }`. +:math:`\sqrt { \frac {2\, k_B \mathtt{Tdrude}\, m'} {\mathrm dt\, \mathtt{damp_drude} } }`. Then the real forces acting on the particles are computed from the inverse transform: @@ -156,7 +156,7 @@ be used to thermostat the non-polarizable atoms. *Tdrude* is the (normally low) target temperature of the core-Drude particle pairs (dipoles). *Tcom* and *Tdrude* can be specified as an equal-style :doc:`variable `. If the value is a variable, it should be -specified as v\_name, where name is the variable name. In this case, +specified as v_name, where name is the variable name. In this case, the variable will be evaluated each timestep, and its value used to determine the target temperature. @@ -185,14 +185,14 @@ neighboring atoms. The optimal value probably depends on the temperature of the centers of mass and on the mass of the Drude particles. -*damp\_com* is the characteristic time for reaching thermal equilibrium +*damp_com* is the characteristic time for reaching thermal equilibrium of the centers of mass. For example, a value of 100.0 means to relax the temperature of the centers of mass in a timespan of (roughly) 100 time units (tau or fmsec or psec - see the :doc:`units ` -command). *damp\_drude* is the characteristic time for reaching +command). *damp_drude* is the characteristic time for reaching thermal equilibrium of the dipoles. It is typically a few timesteps. -The number *seed\_com* and *seed\_drude* are positive integers. They set +The number *seed_com* and *seed_drude* are positive integers. They set the seeds of the Marsaglia random number generators used for generating the random forces on centers of mass and on the dipoles. Each processor uses the input seed to generate its own unique @@ -247,16 +247,16 @@ Comments: :doc:`compute temp/drude ` * Contrary to the alternative thermostatting using Nose-Hoover thermostat fix *npt* and :doc:`fix drude/transform `, the - *fix\_modify* command is not required here, because the fix *nph* + *fix_modify* command is not required here, because the fix *nph* computes the global pressure even if its group is *ATOMS*\ . This is what we want. If we thermostatted *ATOMS* using *npt*\ , the pressure should be the global one, but the temperature should be only that of - the cores. That's why the command *fix\_modify* should be called in + the cores. That's why the command *fix_modify* should be called in that case. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. Because the state of the random number generator is not saved in restart files, this means you cannot do "exact" diff --git a/doc/src/fix_langevin_eff.rst b/doc/src/fix_langevin_eff.rst index 004a82f2aa..36768d25b2 100644 --- a/doc/src/fix_langevin_eff.rst +++ b/doc/src/fix_langevin_eff.rst @@ -65,7 +65,7 @@ The operation of this fix is exactly like that described by the thermostatting is also applied to the radial electron velocity for electron particles. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. Because the state of the random number generator is not diff --git a/doc/src/fix_langevin_spin.rst b/doc/src/fix_langevin_spin.rst index 7113f1459c..9a70cc1cd1 100644 --- a/doc/src/fix_langevin_spin.rst +++ b/doc/src/fix_langevin_spin.rst @@ -70,7 +70,7 @@ different numbers of processors. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. Because the state of the random number generator is not saved in restart files, this means you cannot do "exact" diff --git a/doc/src/fix_latte.rst b/doc/src/fix_latte.rst index beeec5a014..f1469153a7 100644 --- a/doc/src/fix_latte.rst +++ b/doc/src/fix_latte.rst @@ -104,7 +104,7 @@ larger system sizes and longer time scales ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_lb_fluid.rst b/doc/src/fix_lb_fluid.rst index 53fb0219d7..f450fdb8f0 100644 --- a/doc/src/fix_lb_fluid.rst +++ b/doc/src/fix_lb_fluid.rst @@ -18,7 +18,7 @@ Syntax * viscosity = the fluid viscosity (units of mass/(time\*length)). * density = the fluid density. * zero or more keyword/value pairs may be appended -* keyword = *setArea* or *setGamma* or *scaleGamma* or *dx* or *dm* or *a0* or *noise* or *calcforce* or *trilinear* or *D3Q19* or *read\_restart* or *write\_restart* or *zwall\_velocity* or *bodyforce* or *printfluid* +* keyword = *setArea* or *setGamma* or *scaleGamma* or *dx* or *dm* or *a0* or *noise* or *calcforce* or *trilinear* or *D3Q19* or *read_restart* or *write_restart* or *zwall_velocity* or *bodyforce* or *printfluid* .. parsed-literal:: @@ -153,9 +153,9 @@ t_{collision}` is a collision time, chosen such that :math:`\frac{\tau}{\Delta t_{collision}} = 1` (see :ref:`Mackay and Denniston ` for full details). In order to calculate :math:`m_u`, the fluid density is interpolated to the MD particle location, and -multiplied by a volume, node\_area * :math:`dx_{LB}`, where node\_area +multiplied by a volume, node_area * :math:`dx_{LB}`, where node_area represents the portion of the surface area of the composite object -associated with a given MD particle. By default, node\_area is set +associated with a given MD particle. By default, node_area is set equal to :math:`dx_{LB}^2`; however specific values for given atom types can be set using the *setArea* keyword. @@ -286,7 +286,7 @@ If the keyword *D3Q19* is used, the 19 velocity (D3Q19) lattice is used by the lattice-Boltzmann algorithm. By default, the 15 velocity (D3Q15) lattice is used. -If the keyword *write\_restart* is used, followed by a positive +If the keyword *write_restart* is used, followed by a positive integer, N, a binary restart file is printed every N LB timesteps. This restart file only contains information about the fluid. Therefore, a LAMMPS restart file should also be written in order to @@ -298,10 +298,10 @@ print out full details of the simulation. files may become quite large. In order to restart the fluid portion of the simulation, the keyword -*read\_restart* is specified, followed by the name of the binary -lb\_fluid restart file to be used. +*read_restart* is specified, followed by the name of the binary +lb_fluid restart file to be used. -If the *zwall\_velocity* keyword is used y-velocities are assigned to +If the *zwall_velocity* keyword is used y-velocities are assigned to the lower and upper walls. This keyword requires the presence of walls in the z-direction. This is set by assigning fixed boundary conditions in the z-direction. If fixed boundary conditions are @@ -319,16 +319,16 @@ screen every N timesteps. For further details, as well as descriptions and results of several test runs, see :ref:`Mackay et al. `. Please include a citation to -this paper if the lb\_fluid fix is used in work contributing to +this paper if the lb_fluid fix is used in work contributing to published research. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** Due to the large size of the fluid data, this fix writes it's own binary restart files, if requested, independent of the main LAMMPS -:doc:`binary restart files `; no information about *lb\_fluid* +:doc:`binary restart files `; no information about *lb_fluid* is written to the main LAMMPS :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this diff --git a/doc/src/fix_lb_momentum.rst b/doc/src/fix_lb_momentum.rst index 8a3ff8fcdf..a595ba2ce5 100644 --- a/doc/src/fix_lb_momentum.rst +++ b/doc/src/fix_lb_momentum.rst @@ -50,7 +50,7 @@ be changed by specifying the keyword *linear*\ , along with a set of three flags set to 0/1 in order to exclude/ include the corresponding dimension. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_lb_pc.rst b/doc/src/fix_lb_pc.rst index a7a3ddbccc..874ff21893 100644 --- a/doc/src/fix_lb_pc.rst +++ b/doc/src/fix_lb_pc.rst @@ -29,7 +29,7 @@ forces, using the integration algorithm described in :ref:`Mackay et al. ` has been set; do not use this integration algorithm if the force coupling constant has been set by default. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_lb_rigid_pc_sphere.rst b/doc/src/fix_lb_rigid_pc_sphere.rst index 9edebde0cc..42fb21ca69 100644 --- a/doc/src/fix_lb_rigid_pc_sphere.rst +++ b/doc/src/fix_lb_rigid_pc_sphere.rst @@ -82,7 +82,7 @@ the rigid fix (although it includes fewer optional arguments, and assumes the constituent atoms are point particles); see :doc:`fix rigid ` for a complete documentation. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about the *rigid* and *rigid/nve* fixes are written to :doc:`binary restart files `. diff --git a/doc/src/fix_lb_viscous.rst b/doc/src/fix_lb_viscous.rst index 9b1402af7a..6d7431c780 100644 --- a/doc/src/fix_lb_viscous.rst +++ b/doc/src/fix_lb_viscous.rst @@ -28,7 +28,7 @@ is to be used in place of that command when a lattice-Boltzmann fluid is present, and the user wishes to integrate the particle motion using one of the built in LAMMPS integrators. -This fix adds a force, F = - Gamma\*(velocity-fluid\_velocity), to each +This fix adds a force, F = - Gamma\*(velocity-fluid_velocity), to each atom, where Gamma is the force coupling constant described in the :doc:`fix lb/fluid ` command (which applies an equal and opposite force to the fluid). @@ -51,7 +51,7 @@ research. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** As described in the :doc:`fix viscous ` documentation: diff --git a/doc/src/fix_lineforce.rst b/doc/src/fix_lineforce.rst index e15286cbde..b02acfa9f4 100644 --- a/doc/src/fix_lineforce.rst +++ b/doc/src/fix_lineforce.rst @@ -32,7 +32,7 @@ plane perpendicular to the line. If the initial velocity of the atom is 0.0 (or along the line), then it should continue to move along the line thereafter. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_manifoldforce.rst b/doc/src/fix_manifoldforce.rst index 2847e26387..8cb9723277 100644 --- a/doc/src/fix_manifoldforce.rst +++ b/doc/src/fix_manifoldforce.rst @@ -34,7 +34,7 @@ adequately though. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored @@ -50,9 +50,9 @@ Restrictions This fix is part of the USER-MANIFOLD package. It is only enabled if LAMMPS was built with that package. See the :doc:`Build package ` doc page for more info. -Only use this with *min\_style hftn* or *min\_style quickmin*. If not, +Only use this with *min_style hftn* or *min_style quickmin*. If not, the constraints will not be satisfied very well at all. A warning is -generated if the *min\_style* is incompatible but no error. +generated if the *min_style* is incompatible but no error. ---------- diff --git a/doc/src/fix_meso.rst b/doc/src/fix_meso.rst index 631061244b..dc9f1cb991 100644 --- a/doc/src/fix_meso.rst +++ b/doc/src/fix_meso.rst @@ -31,7 +31,7 @@ internal variables such as SPH or DPDE. See `this PDF guide `_ to using SPH in LAMMPS. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_meso_move.rst b/doc/src/fix_meso_move.rst index a1be27abfe..a976c2de34 100644 --- a/doc/src/fix_meso_move.rst +++ b/doc/src/fix_meso_move.rst @@ -158,7 +158,7 @@ Rperp is a perpendicular vector from the rotation axis to the particle. The *variable* style allows the position and velocity components of each particle to be set by formulas specified via the :doc:`variable ` command. Each of the 6 variables is -specified as an argument to the fix as v\_name, where name is the +specified as an argument to the fix as v_name, where name is the variable name that is defined elsewhere in the input script. Each variable must be of either the *equal* or *atom* style. @@ -171,10 +171,10 @@ fix stores the original coordinates of each particle (see note below) so that per-atom quantity can be used in an atom-style variable formula. See the :doc:`variable ` command for details. -The first 3 variables (v\_dx,v\_dy,v\_dz) specified for the *variable* +The first 3 variables (v_dx,v_dy,v_dz) specified for the *variable* style are used to calculate a displacement from the particle's original position at the time the fix was specified. The second 3 variables -(v\_vx,v\_vy,v\_vz) specified are used to compute a velocity for each +(v_vx,v_vy,v_vz) specified are used to compute a velocity for each particle. Any of the 6 variables can be specified as NULL. If both the @@ -204,7 +204,7 @@ spacings can be different in x,y,z. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the original coordinates of moving particles to :doc:`binary restart files `, as well as the initial timestep, so that the motion can be continuous in a restarted simulation. See the diff --git a/doc/src/fix_meso_stationary.rst b/doc/src/fix_meso_stationary.rst index 4c6b35245c..89c30ece14 100644 --- a/doc/src/fix_meso_stationary.rst +++ b/doc/src/fix_meso_stationary.rst @@ -32,7 +32,7 @@ space. See `this PDF guide `_ to using SPH in LAMMPS. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_modify.rst b/doc/src/fix_modify.rst index 658ec5b249..604b63550c 100644 --- a/doc/src/fix_modify.rst +++ b/doc/src/fix_modify.rst @@ -41,7 +41,7 @@ Description Modify one or more parameters of a previously defined fix. Only specific fix styles support specific parameters. See the doc pages for individual fix commands for info on which ones support which -fix\_modify parameters. +fix_modify parameters. The *temp* keyword is used to determine how a fix computes temperature. The specified compute ID must have been previously @@ -65,8 +65,8 @@ system. The fix's global and per-atom energy is included in the calculation performed by the :doc:`compute pe ` or :doc:`compute pe/atom ` commands. See the :doc:`thermo_style ` command for info on how potential energy is output. For fixes that tally a global -energy, it can be printed by using the keyword f\_ID in the -thermo\_style custom command, where ID is the fix-ID of the appropriate +energy, it can be printed by using the keyword f_ID in the +thermo_style custom command, where ID is the fix-ID of the appropriate fix. .. note:: @@ -104,7 +104,7 @@ This is a number ranging from 1 to the number of levels. If the RESPA level is larger than the current maximum, the outermost level will be used, which is also the default setting. This default can be restored using a value of *0* for the RESPA level. The affected fix has to be -enabled to support this feature; if not, *fix\_modify* will report an +enabled to support this feature; if not, *fix_modify* will report an error. Active fixes with a custom RESPA level setting are reported with their specified level at the beginning of a r-RESPA run. diff --git a/doc/src/fix_momentum.rst b/doc/src/fix_momentum.rst index 6412ba8835..58fc9278a1 100644 --- a/doc/src/fix_momentum.rst +++ b/doc/src/fix_momentum.rst @@ -85,7 +85,7 @@ by including their suffix, or you can use the :doc:`-suffix command-line switch See the :doc:`Speed packages ` doc page for more instructions on how to use the accelerated styles effectively. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_move.rst b/doc/src/fix_move.rst index e5aab1259f..e9ebbd726b 100644 --- a/doc/src/fix_move.rst +++ b/doc/src/fix_move.rst @@ -157,7 +157,7 @@ atom's motion and rotation over time. The *variable* style allows the position and velocity components of each atom to be set by formulas specified via the :doc:`variable ` command. Each of the 6 variables is -specified as an argument to the fix as v\_name, where name is the +specified as an argument to the fix as v_name, where name is the variable name that is defined elsewhere in the input script. Each variable must be of either the *equal* or *atom* style. @@ -170,10 +170,10 @@ fix stores the original coordinates of each atom (see note below) so that per-atom quantity can be used in an atom-style variable formula. See the :doc:`variable ` command for details. -The first 3 variables (v\_dx,v\_dy,v\_dz) specified for the *variable* +The first 3 variables (v_dx,v_dy,v_dz) specified for the *variable* style are used to calculate a displacement from the atom's original position at the time the fix was specified. The second 3 variables -(v\_vx,v\_vy,v\_vz) specified are used to compute a velocity for each +(v_vx,v_vy,v_vz) specified are used to compute a velocity for each atom. Any of the 6 variables can be specified as NULL. If both the @@ -203,7 +203,7 @@ spacings can be different in x,y,z. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the original coordinates of moving atoms to :doc:`binary restart files `, as well as the initial timestep, so that the motion can be continuous in a restarted simulation. See the diff --git a/doc/src/fix_msst.rst b/doc/src/fix_msst.rst index 7531ab50de..b76af36bb8 100644 --- a/doc/src/fix_msst.rst +++ b/doc/src/fix_msst.rst @@ -105,8 +105,8 @@ timestep. To do this, the fix creates its own computes of style "temp" See the :doc:`compute temp ` and :doc:`compute pressure ` commands for details. Note that the IDs of the -new computes are the fix-ID + "_MSST\_temp" or "MSST\_press" or -"_MSST\_pe". The group for the new computes is "all". +new computes are the fix-ID + "_MSST_temp" or "MSST_press" or +"_MSST_pe". The group for the new computes is "all". ---------- @@ -122,7 +122,7 @@ timestepping. DFTB+ will communicate its info to LAMMPS via that fix. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the state of all internal variables to :doc:`binary restart files `. See the :doc:`read_restart ` @@ -143,12 +143,12 @@ equations. See also :doc:`thermo_style ` command. The global vector contains four values in this order: -[\ *dhugoniot*\ , *drayleigh*\ , *lagrangian\_speed*, *lagrangian\_position*] +[\ *dhugoniot*\ , *drayleigh*\ , *lagrangian_speed*, *lagrangian_position*] 1. *dhugoniot* is the departure from the Hugoniot (temperature units). 2. *drayleigh* is the departure from the Rayleigh line (pressure units). -3. *lagrangian\_speed* is the laboratory-frame Lagrangian speed (particle velocity) of the computational cell (velocity units). -4. *lagrangian\_position* is the computational cell position in the reference frame moving at the shock speed. This is usually a good estimate of distance of the computational cell behind the shock front. +3. *lagrangian_speed* is the laboratory-frame Lagrangian speed (particle velocity) of the computational cell (velocity units). +4. *lagrangian_position* is the computational cell position in the reference frame moving at the shock speed. This is usually a good estimate of distance of the computational cell behind the shock front. To print these quantities to the log file with descriptive column headers, the following LAMMPS commands are suggested: diff --git a/doc/src/fix_mvv_dpd.rst b/doc/src/fix_mvv_dpd.rst index bdae316a13..77ca08e0c5 100644 --- a/doc/src/fix_mvv_dpd.rst +++ b/doc/src/fix_mvv_dpd.rst @@ -76,7 +76,7 @@ addition to position and velocity, and must be used with the ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_neb.rst b/doc/src/fix_neb.rst index 308f8891c4..3612192d5b 100644 --- a/doc/src/fix_neb.rst +++ b/doc/src/fix_neb.rst @@ -75,10 +75,10 @@ roughly in the direction of (Ri+i - Ri-1); see the coordinates of replica I; Ri-1 and Ri+1 are the coordinates of its neighbor replicas. The term (Grad(V) dot T') is used to remove the component of the gradient parallel to the path which would tend to -distribute the replica unevenly along the path. Fnudge\_parallel is an +distribute the replica unevenly along the path. Fnudge_parallel is an artificial nudging force which is applied only in the tangent direction and which maintains the equal spacing between replicas (see -below for more information). Fnudge\_perp is an optional artificial +below for more information). Fnudge_perp is an optional artificial spring which is applied in a direction perpendicular to the tangent direction and which prevent the paths from forming acute kinks (see below for more information). @@ -203,7 +203,7 @@ Finally, note that the last replica may never reach the target energy if it is stuck in a local minima which has a larger energy than the target energy. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_neb_spin.rst b/doc/src/fix_neb_spin.rst index 1f89a4b665..93729ac96f 100644 --- a/doc/src/fix_neb_spin.rst +++ b/doc/src/fix_neb_spin.rst @@ -47,7 +47,7 @@ The nudging forces are calculated as explained in :ref:`(BessarabB) `). See this reference for more explanation about their expression. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_nh.rst b/doc/src/fix_nh.rst index 214ec9c3e9..6927b47fcb 100644 --- a/doc/src/fix_nh.rst +++ b/doc/src/fix_nh.rst @@ -41,7 +41,7 @@ Syntax fix ID group-ID style_name keyword value ... * ID, group-ID are documented in :doc:`fix ` command -* style\_name = *nvt* or *npt* or *nph* +* style_name = *nvt* or *npt* or *nph* * one or more keyword/value pairs may be appended .. parsed-literal:: @@ -456,17 +456,17 @@ for the entire system. In the case of fix nph, the temperature compute is not used for thermostatting, but just for a kinetic-energy contribution to the pressure. See the :doc:`compute temp ` and :doc:`compute pressure ` commands for details. Note that the IDs of the new computes are the -fix-ID + underscore + "temp" or fix\_ID + underscore + "press". +fix-ID + underscore + "temp" or fix_ID + underscore + "press". Note that these are NOT the computes used by thermodynamic output (see -the :doc:`thermo_style ` command) with ID = *thermo\_temp* -and *thermo\_press*. This means you can change the attributes of these +the :doc:`thermo_style ` command) with ID = *thermo_temp* +and *thermo_press*. This means you can change the attributes of these fix's temperature or pressure via the :doc:`compute_modify ` command. Or you can print this temperature or pressure during thermodynamic output via the :doc:`thermo_style custom ` command using the appropriate -compute-ID. It also means that changing attributes of *thermo\_temp* -or *thermo\_press* will have no effect on this fix. +compute-ID. It also means that changing attributes of *thermo_temp* +or *thermo_press* will have no effect on this fix. Like other fixes that perform thermostatting, fix nvt and fix npt can be used with :doc:`compute commands ` that calculate a @@ -564,7 +564,7 @@ instructions on how to use the accelerated styles effectively. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** These fixes writes the state of all the thermostat and barostat variables to :doc:`binary restart files `. See the @@ -584,7 +584,7 @@ compute temperature on a subset of atoms. .. note:: If both the *temp* and *press* keywords are used in a single - thermo\_modify command (or in two separate commands), then the order in + thermo_modify command (or in two separate commands), then the order in which the keywords are specified is important. Note that a :doc:`pressure compute ` defines its own temperature compute as an argument when it is specified. The *temp* keyword will override this (for the pressure compute being used by fix npt), but only if the @@ -619,21 +619,21 @@ simulation, otherwise its value is 3. The order of values in the global vector and their meaning is as follows. The notation means there are tchain values for eta, followed -by tchain for eta\_dot, followed by ndof for omega, etc: +by tchain for eta_dot, followed by ndof for omega, etc: * eta[tchain] = particle thermostat displacements (unitless) -* eta\_dot[tchain] = particle thermostat velocities (1/time units) +* eta_dot[tchain] = particle thermostat velocities (1/time units) * omega[ndof] = barostat displacements (unitless) -* omega\_dot[ndof] = barostat velocities (1/time units) +* omega_dot[ndof] = barostat velocities (1/time units) * etap[pchain] = barostat thermostat displacements (unitless) -* etap\_dot[pchain] = barostat thermostat velocities (1/time units) -* PE\_eta[tchain] = potential energy of each particle thermostat displacement (energy units) -* KE\_eta\_dot[tchain] = kinetic energy of each particle thermostat velocity (energy units) -* PE\_omega[ndof] = potential energy of each barostat displacement (energy units) -* KE\_omega\_dot[ndof] = kinetic energy of each barostat velocity (energy units) -* PE\_etap[pchain] = potential energy of each barostat thermostat displacement (energy units) -* KE\_etap\_dot[pchain] = kinetic energy of each barostat thermostat velocity (energy units) -* PE\_strain[1] = scalar strain energy (energy units) +* etap_dot[pchain] = barostat thermostat velocities (1/time units) +* PE_eta[tchain] = potential energy of each particle thermostat displacement (energy units) +* KE_eta_dot[tchain] = kinetic energy of each particle thermostat velocity (energy units) +* PE_omega[ndof] = potential energy of each barostat displacement (energy units) +* KE_omega_dot[ndof] = kinetic energy of each barostat velocity (energy units) +* PE_etap[pchain] = potential energy of each barostat thermostat displacement (energy units) +* KE_etap_dot[pchain] = kinetic energy of each barostat thermostat velocity (energy units) +* PE_strain[1] = scalar strain energy (energy units) These fixes can ramp their external temperature and pressure over multiple runs, using the *start* and *stop* keywords of the diff --git a/doc/src/fix_nh_eff.rst b/doc/src/fix_nh_eff.rst index 2d6b542edf..b5fecf279f 100644 --- a/doc/src/fix_nh_eff.rst +++ b/doc/src/fix_nh_eff.rst @@ -17,7 +17,7 @@ Syntax fix ID group-ID style_name keyword value ... * ID, group-ID are documented in :doc:`fix ` command -* style\_name = *nvt/eff* or *npt/eff* or *nph/eff* +* style_name = *nvt/eff* or *npt/eff* or *nph/eff* .. parsed-literal:: @@ -85,7 +85,7 @@ to the temperature or kinetic energy from the electron radial velocity. .. note:: there are two different pressures that can be reported for eFF - when defining the pair\_style (see :doc:`pair eff/cut ` to + when defining the pair_style (see :doc:`pair eff/cut ` to understand these settings), one (default) that considers electrons do not contribute radial virial components (i.e. electrons treated as incompressible 'rigid' spheres) and one that does. The radial @@ -105,7 +105,7 @@ to the temperature or kinetic energy from the electron radial velocity. the user must allow for these degrees of freedom to equilibrate (i.e. equi-partitioning of energy) through time integration. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** See the doc page for the :doc:`fix nvt, npt, and nph ` commands for details. diff --git a/doc/src/fix_nh_uef.rst b/doc/src/fix_nh_uef.rst index 251b1675b9..27851d89a1 100644 --- a/doc/src/fix_nh_uef.rst +++ b/doc/src/fix_nh_uef.rst @@ -14,9 +14,9 @@ Syntax fix ID group-ID style_name erate edot_x edot_y temp Tstart Tstop Tdamp keyword value ... * ID, group-ID are documented in :doc:`fix ` command -* style\_name = *nvt/uef* or *npt/uef* +* style_name = *nvt/uef* or *npt/uef* * *Tstart*\ , *Tstop*\ , and *Tdamp* are documented in the :doc:`fix npt ` command -* *edot\_x* and *edot\_y* are the strain rates in the x and y directions (1/(time units)) +* *edot_x* and *edot_y* are the strain rates in the x and y directions (1/(time units)) * one or more keyword/value pairs may be appended .. parsed-literal:: @@ -57,10 +57,10 @@ Note that NEMD simulations of a continuously strained system can be performed using the :doc:`fix deform `, :doc:`fix nvt/sllod `, and :doc:`compute temp/deform ` commands. The applied flow field is set by the *eps* keyword. The values -*edot\_x* and *edot\_y* correspond to the strain rates in the xx and yy +*edot_x* and *edot_y* correspond to the strain rates in the xx and yy directions. It is implicitly assumed that the flow field is traceless, and therefore the strain rate in the zz direction is eqal -to -(*edot\_x* + *edot\_y*). +to -(*edot_x* + *edot_y*). .. note:: @@ -169,9 +169,9 @@ issued: See the :doc:`compute temp/uef ` and :doc:`compute pressure/uef ` commands for details. Note that the IDs of the new computes are the fix-ID + underscore + "temp" -or fix\_ID + underscore + "press". +or fix_ID + underscore + "press". -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** The fix writes the state of all the thermostat and barostat variables, as well as the cumulative strain applied, to :doc:`binary restart files `. See the :doc:`read_restart ` command @@ -221,7 +221,7 @@ Default The default keyword values specific to this fix are exy = xyz, strain = 0 0. The remaining defaults are the same as for *fix -npt*\ \_fix\_nh.html except tchain = 1. The reason for this change is +npt*\ _fix_nh.html except tchain = 1. The reason for this change is given in :doc:`fix nvt/sllod `. ---------- diff --git a/doc/src/fix_nph_asphere.rst b/doc/src/fix_nph_asphere.rst index c3f2904301..76670f1c30 100644 --- a/doc/src/fix_nph_asphere.rst +++ b/doc/src/fix_nph_asphere.rst @@ -67,18 +67,18 @@ this, the fix creates its own computes of style "temp/asphere" and compute fix-ID_press all pressure fix-ID_temp See the :doc:`compute temp/asphere ` and :doc:`compute pressure ` commands for details. Note that the -IDs of the new computes are the fix-ID + underscore + "temp" or fix\_ID +IDs of the new computes are the fix-ID + underscore + "temp" or fix_ID + underscore + "press", and the group for the new computes is "all" since pressure is computed for the entire system. Note that these are NOT the computes used by thermodynamic output (see -the :doc:`thermo_style ` command) with ID = *thermo\_temp* -and *thermo\_press*. This means you can change the attributes of this +the :doc:`thermo_style ` command) with ID = *thermo_temp* +and *thermo_press*. This means you can change the attributes of this fix's temperature or pressure via the :doc:`compute_modify ` command or print this temperature or pressure during thermodynamic output via the :doc:`thermo_style custom ` command using the appropriate compute-ID. -It also means that changing attributes of *thermo\_temp* or -*thermo\_press* will have no effect on this fix. +It also means that changing attributes of *thermo_temp* or +*thermo_press* will have no effect on this fix. ---------- @@ -100,7 +100,7 @@ by including their suffix, or you can use the :doc:`-suffix command-line switch See the :doc:`Speed packages ` doc page for more instructions on how to use the accelerated styles effectively. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the state of the Nose/Hoover barostat to :doc:`binary restart files `. See the :doc:`read_restart ` command for info on how to re-specify a fix in an input script that @@ -146,6 +146,6 @@ shape attribute. Related commands """""""""""""""" -:doc:`fix nph `, :doc:`fix nve\_asphere `, :doc:`fix nvt\_asphere `, :doc:`fix npt\_asphere `, :doc:`fix_modify ` +:doc:`fix nph `, :doc:`fix nve_asphere `, :doc:`fix nvt_asphere `, :doc:`fix npt_asphere `, :doc:`fix_modify ` **Default:** none diff --git a/doc/src/fix_nph_body.rst b/doc/src/fix_nph_body.rst index d2d7542467..c2f6097fef 100644 --- a/doc/src/fix_nph_body.rst +++ b/doc/src/fix_nph_body.rst @@ -64,18 +64,18 @@ this, the fix creates its own computes of style "temp/body" and compute fix-ID_press all pressure fix-ID_temp See the :doc:`compute temp/body ` and :doc:`compute pressure ` commands for details. Note that the -IDs of the new computes are the fix-ID + underscore + "temp" or fix\_ID +IDs of the new computes are the fix-ID + underscore + "temp" or fix_ID + underscore + "press", and the group for the new computes is "all" since pressure is computed for the entire system. Note that these are NOT the computes used by thermodynamic output (see -the :doc:`thermo_style ` command) with ID = *thermo\_temp* -and *thermo\_press*. This means you can change the attributes of this +the :doc:`thermo_style ` command) with ID = *thermo_temp* +and *thermo_press*. This means you can change the attributes of this fix's temperature or pressure via the :doc:`compute_modify ` command or print this temperature or pressure during thermodynamic output via the :doc:`thermo_style custom ` command using the appropriate compute-ID. -It also means that changing attributes of *thermo\_temp* or -*thermo\_press* will have no effect on this fix. +It also means that changing attributes of *thermo_temp* or +*thermo_press* will have no effect on this fix. ---------- @@ -97,7 +97,7 @@ by including their suffix, or you can use the :doc:`-suffix command-line switch See the :doc:`Speed packages ` doc page for more instructions on how to use the accelerated styles effectively. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the state of the Nose/Hoover barostat to :doc:`binary restart files `. See the :doc:`read_restart ` command for info on how to re-specify a fix in an input script that @@ -139,6 +139,6 @@ command. Related commands """""""""""""""" -:doc:`fix nph `, :doc:`fix nve\_body `, :doc:`fix nvt\_body `, :doc:`fix npt\_body `, :doc:`fix_modify ` +:doc:`fix nph `, :doc:`fix nve_body `, :doc:`fix nvt_body `, :doc:`fix npt_body `, :doc:`fix_modify ` **Default:** none diff --git a/doc/src/fix_nph_sphere.rst b/doc/src/fix_nph_sphere.rst index d71593e4b1..d1e5bfd701 100644 --- a/doc/src/fix_nph_sphere.rst +++ b/doc/src/fix_nph_sphere.rst @@ -80,18 +80,18 @@ this, the fix creates its own computes of style "temp/sphere" and compute fix-ID_press all pressure fix-ID_temp See the :doc:`compute temp/sphere ` and :doc:`compute pressure ` commands for details. Note that the -IDs of the new computes are the fix-ID + underscore + "temp" or fix\_ID +IDs of the new computes are the fix-ID + underscore + "temp" or fix_ID + underscore + "press", and the group for the new computes is "all" since pressure is computed for the entire system. Note that these are NOT the computes used by thermodynamic output (see -the :doc:`thermo_style ` command) with ID = *thermo\_temp* -and *thermo\_press*. This means you can change the attributes of this +the :doc:`thermo_style ` command) with ID = *thermo_temp* +and *thermo_press*. This means you can change the attributes of this fix's temperature or pressure via the :doc:`compute_modify ` command or print this temperature or pressure during thermodynamic output via the :doc:`thermo_style custom ` command using the appropriate compute-ID. -It also means that changing attributes of *thermo\_temp* or -*thermo\_press* will have no effect on this fix. +It also means that changing attributes of *thermo_temp* or +*thermo_press* will have no effect on this fix. ---------- @@ -113,7 +113,7 @@ by including their suffix, or you can use the :doc:`-suffix command-line switch See the :doc:`Speed packages ` doc page for more instructions on how to use the accelerated styles effectively. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the state of the Nose/Hoover barostat to :doc:`binary restart files `. See the :doc:`read_restart ` command for info on how to re-specify a fix in an input script that @@ -158,7 +158,7 @@ defined by the :doc:`dimension ` keyword. Related commands """""""""""""""" -:doc:`fix nph `, :doc:`fix nve\_sphere `, :doc:`fix nvt\_sphere `, :doc:`fix npt\_sphere `, +:doc:`fix nph `, :doc:`fix nve_sphere `, :doc:`fix nvt_sphere `, :doc:`fix npt_sphere `, :doc:`fix_modify ` **Default:** none diff --git a/doc/src/fix_nphug.rst b/doc/src/fix_nphug.rst index fb64966291..fed73f6315 100644 --- a/doc/src/fix_nphug.rst +++ b/doc/src/fix_nphug.rst @@ -100,7 +100,7 @@ When the system reaches a stable equilibrium, the value of :math:`\Delta` should fluctuate about zero. The values of :math:`E_0`, :math:`V_0`, and :math:`P_0` are the instantaneous values at the start of -the simulation. These can be overridden using the fix\_modify keywords *e0*\ , +the simulation. These can be overridden using the fix_modify keywords *e0*\ , *v0*\ , and *p0* described below. ---------- @@ -129,19 +129,19 @@ as if one of these two sets of commands had been issued: compute fix-ID_press all pressure fix-ID_temp See the :doc:`compute temp ` and :doc:`compute pressure ` commands for details. Note that the -IDs of the new computes are the fix-ID + underscore + "temp" or fix\_ID +IDs of the new computes are the fix-ID + underscore + "temp" or fix_ID + underscore + "press". The group for the new computes is "all" since pressure is computed for the entire system. Note that these are NOT the computes used by thermodynamic output (see -the :doc:`thermo_style ` command) with ID = *thermo\_temp* -and *thermo\_press*. This means you can change the attributes of this +the :doc:`thermo_style ` command) with ID = *thermo_temp* +and *thermo_press*. This means you can change the attributes of this fix's temperature or pressure via the :doc:`compute_modify ` command or print this temperature or pressure during thermodynamic output via the :doc:`thermo_style custom ` command using the appropriate compute-ID. -It also means that changing attributes of *thermo\_temp* or -*thermo\_press* will have no effect on this fix. +It also means that changing attributes of *thermo_temp* or +*thermo_press* will have no effect on this fix. ---------- @@ -165,7 +165,7 @@ instructions on how to use the accelerated styles effectively. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the values of :math:`E_0`, :math:`V_0`, and :math:`P_0`, as well as the state of all the thermostat and barostat variables to diff --git a/doc/src/fix_npt_asphere.rst b/doc/src/fix_npt_asphere.rst index 644e10ee1e..aac88c551e 100644 --- a/doc/src/fix_npt_asphere.rst +++ b/doc/src/fix_npt_asphere.rst @@ -75,18 +75,18 @@ this, the fix creates its own computes of style "temp/asphere" and compute fix-ID_press all pressure fix-ID_temp See the :doc:`compute temp/asphere ` and :doc:`compute pressure ` commands for details. Note that the -IDs of the new computes are the fix-ID + underscore + "temp" or fix\_ID +IDs of the new computes are the fix-ID + underscore + "temp" or fix_ID + underscore + "press", and the group for the new computes is "all" since pressure is computed for the entire system. Note that these are NOT the computes used by thermodynamic output (see -the :doc:`thermo_style ` command) with ID = *thermo\_temp* -and *thermo\_press*. This means you can change the attributes of this +the :doc:`thermo_style ` command) with ID = *thermo_temp* +and *thermo_press*. This means you can change the attributes of this fix's temperature or pressure via the :doc:`compute_modify ` command or print this temperature or pressure during thermodynamic output via the :doc:`thermo_style custom ` command using the appropriate compute-ID. -It also means that changing attributes of *thermo\_temp* or -*thermo\_press* will have no effect on this fix. +It also means that changing attributes of *thermo_temp* or +*thermo_press* will have no effect on this fix. Like other fixes that perform thermostatting, this fix can be used with :doc:`compute commands ` that calculate a temperature @@ -122,7 +122,7 @@ by including their suffix, or you can use the :doc:`-suffix command-line switch See the :doc:`Speed packages ` doc page for more instructions on how to use the accelerated styles effectively. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the state of the Nose/Hoover thermostat and barostat to :doc:`binary restart files `. See the @@ -171,6 +171,6 @@ shape attribute. Related commands """""""""""""""" -:doc:`fix npt `, :doc:`fix nve\_asphere `, :doc:`fix nvt\_asphere `, :doc:`fix_modify ` +:doc:`fix npt `, :doc:`fix nve_asphere `, :doc:`fix nvt_asphere `, :doc:`fix_modify ` **Default:** none diff --git a/doc/src/fix_npt_body.rst b/doc/src/fix_npt_body.rst index 1a6caebb79..120437eeab 100644 --- a/doc/src/fix_npt_body.rst +++ b/doc/src/fix_npt_body.rst @@ -72,18 +72,18 @@ this, the fix creates its own computes of style "temp/body" and compute fix-ID_press all pressure fix-ID_temp See the :doc:`compute temp/body ` and :doc:`compute pressure ` commands for details. Note that the -IDs of the new computes are the fix-ID + underscore + "temp" or fix\_ID +IDs of the new computes are the fix-ID + underscore + "temp" or fix_ID + underscore + "press", and the group for the new computes is "all" since pressure is computed for the entire system. Note that these are NOT the computes used by thermodynamic output (see -the :doc:`thermo_style ` command) with ID = *thermo\_temp* -and *thermo\_press*. This means you can change the attributes of this +the :doc:`thermo_style ` command) with ID = *thermo_temp* +and *thermo_press*. This means you can change the attributes of this fix's temperature or pressure via the :doc:`compute_modify ` command or print this temperature or pressure during thermodynamic output via the :doc:`thermo_style custom ` command using the appropriate compute-ID. -It also means that changing attributes of *thermo\_temp* or -*thermo\_press* will have no effect on this fix. +It also means that changing attributes of *thermo_temp* or +*thermo_press* will have no effect on this fix. Like other fixes that perform thermostatting, this fix can be used with :doc:`compute commands ` that calculate a temperature @@ -119,7 +119,7 @@ by including their suffix, or you can use the :doc:`-suffix command-line switch See the :doc:`Speed packages ` doc page for more instructions on how to use the accelerated styles effectively. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the state of the Nose/Hoover thermostat and barostat to :doc:`binary restart files `. See the @@ -164,6 +164,6 @@ command. Related commands """""""""""""""" -:doc:`fix npt `, :doc:`fix nve\_body `, :doc:`fix nvt\_body `, :doc:`fix_modify ` +:doc:`fix npt `, :doc:`fix nve_body `, :doc:`fix nvt_body `, :doc:`fix_modify ` **Default:** none diff --git a/doc/src/fix_npt_cauchy.rst b/doc/src/fix_npt_cauchy.rst index d548002f0e..5e0188c574 100644 --- a/doc/src/fix_npt_cauchy.rst +++ b/doc/src/fix_npt_cauchy.rst @@ -11,7 +11,7 @@ Syntax fix ID group-ID style_name keyword value ... * ID, group-ID are documented in :doc:`fix ` command -* style\_name = *npt/cauchy* +* style_name = *npt/cauchy* * one or more keyword/value pairs may be appended * keyword = *temp* or *iso* or *aniso* or *tri* or *x* or *y* or *z* or *xy* or *yz* or *xz* or *couple* or *tchain* or *pchain* or *mtk* or *tloop* or *ploop* or *nreset* or *drag* or *dilate* or *scalexy* or *scaleyz* or *scalexz* or *flip* or *fixedpoint* or *update* @@ -389,17 +389,17 @@ as if one of these sets of commands had been issued: The group for both the new temperature and pressure compute is "all" since pressure is computed for the entire system. See the :doc:`compute temp ` and :doc:`compute pressure ` commands for details. Note that the IDs of the new computes are the -fix-ID + underscore + "temp" or fix\_ID + underscore + "press". +fix-ID + underscore + "temp" or fix_ID + underscore + "press". Note that these are NOT the computes used by thermodynamic output (see -the :doc:`thermo_style ` command) with ID = *thermo\_temp* -and *thermo\_press*. This means you can change the attributes of these +the :doc:`thermo_style ` command) with ID = *thermo_temp* +and *thermo_press*. This means you can change the attributes of these fix's temperature or pressure via the :doc:`compute_modify ` command. Or you can print this temperature or pressure during thermodynamic output via the :doc:`thermo_style custom ` command using the appropriate -compute-ID. It also means that changing attributes of *thermo\_temp* -or *thermo\_press* will have no effect on this fix. +compute-ID. It also means that changing attributes of *thermo_temp* +or *thermo_press* will have no effect on this fix. Like other fixes that perform thermostatting, fix npt/cauchy can be used with :doc:`compute commands ` that calculate a @@ -467,7 +467,7 @@ of the underlying non-Hamiltonian equations of motion. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the state of all the thermostat and barostat variables to :doc:`binary restart files `. See the @@ -487,7 +487,7 @@ compute temperature on a subset of atoms. .. note:: If both the *temp* and *press* keywords are used in a single - thermo\_modify command (or in two separate commands), then the order in + thermo_modify command (or in two separate commands), then the order in which the keywords are specified is important. Note that a :doc:`pressure compute ` defines its own temperature compute as an argument when it is specified. The *temp* keyword will override this (for the pressure compute being used by fix npt), but only if the @@ -522,21 +522,21 @@ simulation, otherwise its value is 3. The order of values in the global vector and their meaning is as follows. The notation means there are tchain values for eta, followed -by tchain for eta\_dot, followed by ndof for omega, etc: +by tchain for eta_dot, followed by ndof for omega, etc: * eta[tchain] = particle thermostat displacements (unitless) -* eta\_dot[tchain] = particle thermostat velocities (1/time units) +* eta_dot[tchain] = particle thermostat velocities (1/time units) * omega[ndof] = barostat displacements (unitless) -* omega\_dot[ndof] = barostat velocities (1/time units) +* omega_dot[ndof] = barostat velocities (1/time units) * etap[pchain] = barostat thermostat displacements (unitless) -* etap\_dot[pchain] = barostat thermostat velocities (1/time units) -* PE\_eta[tchain] = potential energy of each particle thermostat displacement (energy units) -* KE\_eta\_dot[tchain] = kinetic energy of each particle thermostat velocity (energy units) -* PE\_omega[ndof] = potential energy of each barostat displacement (energy units) -* KE\_omega\_dot[ndof] = kinetic energy of each barostat velocity (energy units) -* PE\_etap[pchain] = potential energy of each barostat thermostat displacement (energy units) -* KE\_etap\_dot[pchain] = kinetic energy of each barostat thermostat velocity (energy units) -* PE\_strain[1] = scalar strain energy (energy units) +* etap_dot[pchain] = barostat thermostat velocities (1/time units) +* PE_eta[tchain] = potential energy of each particle thermostat displacement (energy units) +* KE_eta_dot[tchain] = kinetic energy of each particle thermostat velocity (energy units) +* PE_omega[ndof] = potential energy of each barostat displacement (energy units) +* KE_omega_dot[ndof] = kinetic energy of each barostat velocity (energy units) +* PE_etap[pchain] = potential energy of each barostat thermostat displacement (energy units) +* KE_etap_dot[pchain] = kinetic energy of each barostat thermostat velocity (energy units) +* PE_strain[1] = scalar strain energy (energy units) This fix can ramp its external temperature and pressure over multiple runs, using the *start* and *stop* keywords of the @@ -581,7 +581,7 @@ the set values and the final true (Cauchy) stresses can be considerable. The *cauchystat* keyword modifies the barostat as per Miller et -al. (Miller)\_"#nc-Miller" so that the Cauchy stress is controlled. +al. (Miller)_"#nc-Miller" so that the Cauchy stress is controlled. *alpha* is the non-dimensional parameter, typically set to 0.001 or 0.01 that determines how aggressively the algorithm drives the system towards the set Cauchy stresses. Larger values of *alpha* will modify diff --git a/doc/src/fix_npt_sphere.rst b/doc/src/fix_npt_sphere.rst index 48fdbd90fb..2def29ae47 100644 --- a/doc/src/fix_npt_sphere.rst +++ b/doc/src/fix_npt_sphere.rst @@ -88,18 +88,18 @@ this, the fix creates its own computes of style "temp/sphere" and compute fix-ID_press all pressure fix-ID_temp See the :doc:`compute temp/sphere ` and :doc:`compute pressure ` commands for details. Note that the -IDs of the new computes are the fix-ID + underscore + "temp" or fix\_ID +IDs of the new computes are the fix-ID + underscore + "temp" or fix_ID + underscore + "press", and the group for the new computes is "all" since pressure is computed for the entire system. Note that these are NOT the computes used by thermodynamic output (see -the :doc:`thermo_style ` command) with ID = *thermo\_temp* -and *thermo\_press*. This means you can change the attributes of this +the :doc:`thermo_style ` command) with ID = *thermo_temp* +and *thermo_press*. This means you can change the attributes of this fix's temperature or pressure via the :doc:`compute_modify ` command or print this temperature or pressure during thermodynamic output via the :doc:`thermo_style custom ` command using the appropriate compute-ID. -It also means that changing attributes of *thermo\_temp* or -*thermo\_press* will have no effect on this fix. +It also means that changing attributes of *thermo_temp* or +*thermo_press* will have no effect on this fix. Like other fixes that perform thermostatting, this fix can be used with :doc:`compute commands ` that calculate a temperature @@ -135,7 +135,7 @@ by including their suffix, or you can use the :doc:`-suffix command-line switch See the :doc:`Speed packages ` doc page for more instructions on how to use the accelerated styles effectively. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the state of the Nose/Hoover thermostat and barostat to :doc:`binary restart files `. See the @@ -183,6 +183,6 @@ defined by the :doc:`dimension ` keyword. Related commands """""""""""""""" -:doc:`fix npt `, :doc:`fix nve\_sphere `, :doc:`fix nvt\_sphere `, :doc:`fix npt\_asphere `, :doc:`fix_modify ` +:doc:`fix npt `, :doc:`fix nve_sphere `, :doc:`fix nvt_sphere `, :doc:`fix npt_asphere `, :doc:`fix_modify ` **Default:** none diff --git a/doc/src/fix_nve.rst b/doc/src/fix_nve.rst index 367cdd5552..8089ad094d 100644 --- a/doc/src/fix_nve.rst +++ b/doc/src/fix_nve.rst @@ -59,7 +59,7 @@ instructions on how to use the accelerated styles effectively. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_nve_asphere.rst b/doc/src/fix_nve_asphere.rst index deda3ded70..f231330831 100644 --- a/doc/src/fix_nve_asphere.rst +++ b/doc/src/fix_nve_asphere.rst @@ -34,7 +34,7 @@ trajectory consistent with the microcanonical ensemble. This fix differs from the :doc:`fix nve ` command, which assumes point particles and only updates their position and velocity. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_nve_asphere_noforce.rst b/doc/src/fix_nve_asphere_noforce.rst index 675e3b6684..b518781d6c 100644 --- a/doc/src/fix_nve_asphere_noforce.rst +++ b/doc/src/fix_nve_asphere_noforce.rst @@ -35,7 +35,7 @@ Dynamics, since the velocity and angular momentum are updated by the ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_nve_awpmd.rst b/doc/src/fix_nve_awpmd.rst index 07f98a6a34..45bb002617 100644 --- a/doc/src/fix_nve_awpmd.rst +++ b/doc/src/fix_nve_awpmd.rst @@ -33,7 +33,7 @@ the electron wave functions are also updated. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_nve_body.rst b/doc/src/fix_nve_body.rst index 96134e2974..ad68abb0d4 100644 --- a/doc/src/fix_nve_body.rst +++ b/doc/src/fix_nve_body.rst @@ -32,7 +32,7 @@ particles. This fix differs from the :doc:`fix nve ` command, which assumes point particles and only updates their position and velocity. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_nve_eff.rst b/doc/src/fix_nve_eff.rst index 57cfc6cd14..78e6352b6e 100644 --- a/doc/src/fix_nve_eff.rst +++ b/doc/src/fix_nve_eff.rst @@ -30,7 +30,7 @@ system trajectory consistent with the microcanonical ensemble. The operation of this fix is exactly like that described by the :doc:`fix nve ` command, except that the radius and radial velocity of electrons are also updated. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_nve_limit.rst b/doc/src/fix_nve_limit.rst index d600eb4e66..98d691d6b9 100644 --- a/doc/src/fix_nve_limit.rst +++ b/doc/src/fix_nve_limit.rst @@ -60,7 +60,7 @@ very large for overlapped configurations. that need this fix, then turn fix shake on when doing normal dynamics with a fixed-size timestep. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. diff --git a/doc/src/fix_nve_line.rst b/doc/src/fix_nve_line.rst index 208759116b..d47bf34f61 100644 --- a/doc/src/fix_nve_line.rst +++ b/doc/src/fix_nve_line.rst @@ -32,7 +32,7 @@ segment particles. This fix differs from the :doc:`fix nve ` command, which assumes point particles and only updates their position and velocity. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_nve_manifold_rattle.rst b/doc/src/fix_nve_manifold_rattle.rst index 3e8ee059a0..1caedf88e1 100644 --- a/doc/src/fix_nve_manifold_rattle.rst +++ b/doc/src/fix_nve_manifold_rattle.rst @@ -49,7 +49,7 @@ parameters, see the :doc:`Howto manifold ` doc page. Note that the particles must initially be close to the manifold in question. If not, RATTLE will not be able to iterate until the constraint is satisfied, and an error is generated. For simple -manifolds this can be achieved with *region* and *create\_atoms* +manifolds this can be achieved with *region* and *create_atoms* commands, but for more complex surfaces it might be more useful to write a script. @@ -69,7 +69,7 @@ conserved. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_nve_noforce.rst b/doc/src/fix_nve_noforce.rst index 0bc2624ce2..d45648694a 100644 --- a/doc/src/fix_nve_noforce.rst +++ b/doc/src/fix_nve_noforce.rst @@ -37,7 +37,7 @@ unchanged, and can thus be printed by the :doc:`dump ` command or queried with an equal-style :doc:`variable ` that uses the fcm() group function to compute the total force on the group of atoms. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_nve_sphere.rst b/doc/src/fix_nve_sphere.rst index c92605aa28..753e40cd15 100644 --- a/doc/src/fix_nve_sphere.rst +++ b/doc/src/fix_nve_sphere.rst @@ -90,7 +90,7 @@ instructions on how to use the accelerated styles effectively. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_nve_spin.rst b/doc/src/fix_nve_spin.rst index 4ba1f945da..143ddb2426 100644 --- a/doc/src/fix_nve_spin.rst +++ b/doc/src/fix_nve_spin.rst @@ -62,7 +62,7 @@ package. See the :doc:`Build package ` doc page for more info. To use the spin algorithm, it is necessary to define a map with -the atom\_modify command. Typically, by adding the command: +the atom_modify command. Typically, by adding the command: .. code-block:: LAMMPS diff --git a/doc/src/fix_nve_tri.rst b/doc/src/fix_nve_tri.rst index 0b0a48249a..f5fdb7cc7d 100644 --- a/doc/src/fix_nve_tri.rst +++ b/doc/src/fix_nve_tri.rst @@ -33,7 +33,7 @@ using triangular particles. This fix differs from the :doc:`fix nve ` command, which assumes point particles and only updates their position and velocity. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_nvk.rst b/doc/src/fix_nvk.rst index aafeb1fde7..415e3256b4 100644 --- a/doc/src/fix_nvk.rst +++ b/doc/src/fix_nvk.rst @@ -39,7 +39,7 @@ energy prior to this fix. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_nvt_asphere.rst b/doc/src/fix_nvt_asphere.rst index 4db500e279..6004de2e60 100644 --- a/doc/src/fix_nvt_asphere.rst +++ b/doc/src/fix_nvt_asphere.rst @@ -63,12 +63,12 @@ underscore + "temp", and the group for the new compute is the same as the fix group. Note that this is NOT the compute used by thermodynamic output (see -the :doc:`thermo_style ` command) with ID = *thermo\_temp*. +the :doc:`thermo_style ` command) with ID = *thermo_temp*. This means you can change the attributes of this fix's temperature (e.g. its degrees-of-freedom) via the :doc:`compute_modify ` command or print this temperature during thermodynamic output via the :doc:`thermo_style custom ` command using the appropriate compute-ID. -It also means that changing attributes of *thermo\_temp* will have no +It also means that changing attributes of *thermo_temp* will have no effect on this fix. Like other fixes that perform thermostatting, this fix can be used @@ -105,7 +105,7 @@ by including their suffix, or you can use the :doc:`-suffix command-line switch See the :doc:`Speed packages ` doc page for more instructions on how to use the accelerated styles effectively. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the state of the Nose/Hoover thermostat to :doc:`binary restart files `. See the :doc:`read_restart ` command for info on how to re-specify a fix in an input script that @@ -147,6 +147,6 @@ shape attribute. Related commands """""""""""""""" -:doc:`fix nvt `, :doc:`fix nve\_asphere `, :doc:`fix npt\_asphere `, :doc:`fix_modify ` +:doc:`fix nvt `, :doc:`fix nve_asphere `, :doc:`fix npt_asphere `, :doc:`fix_modify ` **Default:** none diff --git a/doc/src/fix_nvt_body.rst b/doc/src/fix_nvt_body.rst index 37dc4d1f0b..41d652a32d 100644 --- a/doc/src/fix_nvt_body.rst +++ b/doc/src/fix_nvt_body.rst @@ -60,12 +60,12 @@ underscore + "temp", and the group for the new compute is the same as the fix group. Note that this is NOT the compute used by thermodynamic output (see -the :doc:`thermo_style ` command) with ID = *thermo\_temp*. +the :doc:`thermo_style ` command) with ID = *thermo_temp*. This means you can change the attributes of this fix's temperature (e.g. its degrees-of-freedom) via the :doc:`compute_modify ` command or print this temperature during thermodynamic output via the :doc:`thermo_style custom ` command using the appropriate compute-ID. -It also means that changing attributes of *thermo\_temp* will have no +It also means that changing attributes of *thermo_temp* will have no effect on this fix. Like other fixes that perform thermostatting, this fix can be used @@ -102,7 +102,7 @@ by including their suffix, or you can use the :doc:`-suffix command-line switch See the :doc:`Speed packages ` doc page for more instructions on how to use the accelerated styles effectively. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the state of the Nose/Hoover thermostat to :doc:`binary restart files `. See the :doc:`read_restart ` command for info on how to re-specify a fix in an input script that @@ -140,6 +140,6 @@ command. Related commands """""""""""""""" -:doc:`fix nvt `, :doc:`fix nve\_body `, :doc:`fix npt\_body `, :doc:`fix_modify ` +:doc:`fix nvt `, :doc:`fix nve_body `, :doc:`fix npt_body `, :doc:`fix_modify ` **Default:** none diff --git a/doc/src/fix_nvt_manifold_rattle.rst b/doc/src/fix_nvt_manifold_rattle.rst index f7a14fa266..198208ca0d 100644 --- a/doc/src/fix_nvt_manifold_rattle.rst +++ b/doc/src/fix_nvt_manifold_rattle.rst @@ -49,7 +49,7 @@ parameters, see the :doc:`Howto manifold ` doc page. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_nvt_sllod.rst b/doc/src/fix_nvt_sllod.rst index e8f4b840d1..829bf8c634 100644 --- a/doc/src/fix_nvt_sllod.rst +++ b/doc/src/fix_nvt_sllod.rst @@ -95,12 +95,12 @@ underscore + "temp", and the group for the new compute is the same as the fix group. Note that this is NOT the compute used by thermodynamic output (see -the :doc:`thermo_style ` command) with ID = *thermo\_temp*. +the :doc:`thermo_style ` command) with ID = *thermo_temp*. This means you can change the attributes of this fix's temperature (e.g. its degrees-of-freedom) via the :doc:`compute_modify ` command or print this temperature during thermodynamic output via the :doc:`thermo_style custom ` command using the appropriate compute-ID. -It also means that changing attributes of *thermo\_temp* will have no +It also means that changing attributes of *thermo_temp* will have no effect on this fix. Like other fixes that perform thermostatting, this fix can be used @@ -137,7 +137,7 @@ by including their suffix, or you can use the :doc:`-suffix command-line switch See the :doc:`Speed packages ` doc page for more instructions on how to use the accelerated styles effectively. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the state of the Nose/Hoover thermostat to :doc:`binary restart files `. See the :doc:`read_restart ` command for info on how to re-specify a fix in an input script that diff --git a/doc/src/fix_nvt_sllod_eff.rst b/doc/src/fix_nvt_sllod_eff.rst index f2b3edd366..49ad9f608c 100644 --- a/doc/src/fix_nvt_sllod_eff.rst +++ b/doc/src/fix_nvt_sllod_eff.rst @@ -38,7 +38,7 @@ page), is performed with a :doc:`compute temp/deform/eff `. See the :doc:`read_restart ` command for info on how to re-specify a fix in an input script that diff --git a/doc/src/fix_nvt_sphere.rst b/doc/src/fix_nvt_sphere.rst index f9d5fd954f..95bb0a20c4 100644 --- a/doc/src/fix_nvt_sphere.rst +++ b/doc/src/fix_nvt_sphere.rst @@ -77,12 +77,12 @@ underscore + "temp", and the group for the new compute is the same as the fix group. Note that this is NOT the compute used by thermodynamic output (see -the :doc:`thermo_style ` command) with ID = *thermo\_temp*. +the :doc:`thermo_style ` command) with ID = *thermo_temp*. This means you can change the attributes of this fix's temperature (e.g. its degrees-of-freedom) via the :doc:`compute_modify ` command or print this temperature during thermodynamic output via the :doc:`thermo_style custom ` command using the appropriate compute-ID. -It also means that changing attributes of *thermo\_temp* will have no +It also means that changing attributes of *thermo_temp* will have no effect on this fix. Like other fixes that perform thermostatting, this fix can be used @@ -119,7 +119,7 @@ by including their suffix, or you can use the :doc:`-suffix command-line switch See the :doc:`Speed packages ` doc page for more instructions on how to use the accelerated styles effectively. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the state of the Nose/Hoover thermostat to :doc:`binary restart files `. See the :doc:`read_restart ` command for info on how to re-specify a fix in an input script that @@ -160,6 +160,6 @@ defined by the :doc:`dimension ` keyword. Related commands """""""""""""""" -:doc:`fix nvt `, :doc:`fix nve\_sphere `, :doc:`fix nvt\_asphere `, :doc:`fix npt\_sphere `, :doc:`fix_modify ` +:doc:`fix nvt `, :doc:`fix nve_sphere `, :doc:`fix nvt_asphere `, :doc:`fix npt_sphere `, :doc:`fix_modify ` **Default:** none diff --git a/doc/src/fix_oneway.rst b/doc/src/fix_oneway.rst index 6444776a6b..04186404e6 100644 --- a/doc/src/fix_oneway.rst +++ b/doc/src/fix_oneway.rst @@ -39,7 +39,7 @@ membrane, or as an implementation of Maxwell's demon. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_orient.rst b/doc/src/fix_orient.rst index 30e5f87ee9..8fdcc79ace 100644 --- a/doc/src/fix_orient.rst +++ b/doc/src/fix_orient.rst @@ -137,7 +137,7 @@ equal-and-opposite neighbors. A pair of orientation files for a Sigma=5 tilt boundary are shown below. A tutorial that can help for writing the orientation files is given in :ref:`(Wicaksono2) ` -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_phonon.rst b/doc/src/fix_phonon.rst index 6a6a8c6b96..4eed4efc5b 100644 --- a/doc/src/fix_phonon.rst +++ b/doc/src/fix_phonon.rst @@ -15,7 +15,7 @@ Syntax * N = measure the Green's function every this many timesteps * Noutput = output the dynamical matrix every this many measurements * Nwait = wait this many timesteps before measuring -* map\_file = *file* or *GAMMA* +* map_file = *file* or *GAMMA* .. parsed-literal:: @@ -131,14 +131,14 @@ provided by keyword *nasr* gives the total number of iterations. For a system whose unit cell has only one atom, *nasr* = 1 is sufficient; for other systems, *nasr* = 10 is typically sufficient. -The *map\_file* contains the mapping information between the lattice +The *map_file* contains the mapping information between the lattice indices and the atom IDs, which tells the code which atom sits at which lattice point; the lattice indices start from 0. An auxiliary code, `latgen `_, can be employed to generate the compatible map file for various crystals. In case one simulates a non-periodic system, where the whole simulation -box is treated as a unit cell, one can set *map\_file* as *GAMMA*\ , so +box is treated as a unit cell, one can set *map_file* as *GAMMA*\ , so that the mapping info will be generated internally and a file is not needed. In this case, the dynamical matrix at only the gamma-point will/can be evaluated. Please keep in mind that fix-phonon is designed @@ -150,12 +150,12 @@ The calculated dynamical matrix elements are written out in points in the log file is in the units of the basis vectors of the corresponding reciprocal lattice. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. The :doc:`fix_modify ` *temp* option is supported by this -fix. You can use it to change the temperature compute from thermo\_temp +fix. You can use it to change the temperature compute from thermo_temp to the one that reflects the true temperature of atoms in the group. No global scalar or vector or per-atom quantities are stored by this diff --git a/doc/src/fix_planeforce.rst b/doc/src/fix_planeforce.rst index a3df6bff14..c90a3b6bbe 100644 --- a/doc/src/fix_planeforce.rst +++ b/doc/src/fix_planeforce.rst @@ -32,7 +32,7 @@ force perpendicular to the plane. If the initial velocity of the atom is 0.0 (or in the plane), then it should continue to move in the plane thereafter. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_plumed.rst b/doc/src/fix_plumed.rst index 00886a95b3..aeef6cff50 100644 --- a/doc/src/fix_plumed.rst +++ b/doc/src/fix_plumed.rst @@ -75,7 +75,7 @@ correctly read and parsed. The names of the files in which the results are stored from the various analysis options performed by PLUMED will be specified by the user in the PLUMED input file. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** When performing a restart of a calculation that involves PLUMED you must include a RESTART command in the PLUMED input file as detailed in the diff --git a/doc/src/fix_poems.rst b/doc/src/fix_poems.rst index ec1d1335a5..1be7a90419 100644 --- a/doc/src/fix_poems.rst +++ b/doc/src/fix_poems.rst @@ -92,7 +92,7 @@ this context means a set of rigid bodies connected by joints. For computational efficiency, you should turn off pairwise and bond interactions within each rigid body, as they no longer contribute to -the motion. The "neigh\_modify exclude" and "delete\_bonds" commands +the motion. The "neigh_modify exclude" and "delete_bonds" commands can be used to do this if each rigid body is a group. For computational efficiency, you should only define one fix poems @@ -105,7 +105,7 @@ body contribution to the pressure virial is also accounted for. The latter is only correct if forces within the bodies have been turned off, and there is only a single fix poems defined. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_pour.rst b/doc/src/fix_pour.rst index ce89f6a227..26f1cd0eae 100644 --- a/doc/src/fix_pour.rst +++ b/doc/src/fix_pour.rst @@ -126,7 +126,7 @@ command which also appears in your input script. If you wish the new rigid molecules (and other rigid molecules) to be thermostatted correctly via :doc:`fix rigid/small/nvt ` or :doc:`fix rigid/small/npt `, then you need to use the - "fix\_modify dynamic/dof yes" command for the rigid fix. This is to + "fix_modify dynamic/dof yes" command for the rigid fix. This is to inform that fix that the molecule count will vary dynamically. If you wish to insert molecules via the *mol* keyword, that will have @@ -225,7 +225,7 @@ line or triangle particles with the insertion region. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. This means you must be careful when restarting a pouring simulation, when the restart file was written in the middle of diff --git a/doc/src/fix_precession_spin.rst b/doc/src/fix_precession_spin.rst index f7931c1b26..065f894926 100644 --- a/doc/src/fix_precession_spin.rst +++ b/doc/src/fix_precession_spin.rst @@ -130,7 +130,7 @@ Those styles can be combined within one single command line. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** By default, the energy associated to this fix is not added to the potential energy of the system. @@ -152,7 +152,7 @@ Restrictions The *precession/spin* style is part of the SPIN package. This style is only enabled if LAMMPS was built with this package, and if the -atom\_style "spin" was declared. See the :doc:`Build package ` doc page for more info. +atom_style "spin" was declared. See the :doc:`Build package ` doc page for more info. Related commands """""""""""""""" diff --git a/doc/src/fix_press_berendsen.rst b/doc/src/fix_press_berendsen.rst index a5dc37965c..215ef81b02 100644 --- a/doc/src/fix_press_berendsen.rst +++ b/doc/src/fix_press_berendsen.rst @@ -177,20 +177,20 @@ as if these commands had been issued: compute fix-ID_press group-ID pressure fix-ID_temp See the :doc:`compute temp ` and :doc:`compute pressure ` commands for details. Note that the -IDs of the new computes are the fix-ID + underscore + "temp" or fix\_ID +IDs of the new computes are the fix-ID + underscore + "temp" or fix_ID + underscore + "press", and the group for the new computes is the same as the fix group. Note that these are NOT the computes used by thermodynamic output (see -the :doc:`thermo_style ` command) with ID = *thermo\_temp* -and *thermo\_press*. This means you can change the attributes of this +the :doc:`thermo_style ` command) with ID = *thermo_temp* +and *thermo_press*. This means you can change the attributes of this fix's temperature or pressure via the :doc:`compute_modify ` command or print this temperature or pressure during thermodynamic output via the :doc:`thermo_style custom ` command using the appropriate compute-ID. -It also means that changing attributes of *thermo\_temp* or -*thermo\_press* will have no effect on this fix. +It also means that changing attributes of *thermo_temp* or +*thermo_press* will have no effect on this fix. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_print.rst b/doc/src/fix_print.rst index e3d64de8e7..82b26d4ef3 100644 --- a/doc/src/fix_print.rst +++ b/doc/src/fix_print.rst @@ -44,7 +44,7 @@ If it contains variables it must be enclosed in double quotes to insure they are not evaluated when the input script line is read, but will instead be evaluated each time the string is printed. -Instead of a numeric value, N can be specified as an :doc:`equal-style variable `, which should be specified as v\_name, where +Instead of a numeric value, N can be specified as an :doc:`equal-style variable `, which should be specified as v_name, where name is the variable name. In this case, the variable is evaluated at the beginning of a run to determine the **next** timestep at which the string will be written out. On that timestep, the variable will be @@ -89,7 +89,7 @@ keyword was used. By default, the title line is as follows: where ID is replaced with the fix-ID. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_propel_self.rst b/doc/src/fix_propel_self.rst index d67fd32deb..b6b5a6051f 100644 --- a/doc/src/fix_propel_self.rst +++ b/doc/src/fix_propel_self.rst @@ -44,7 +44,7 @@ such as proposed by :ref:`(Erdmann) `. For *mode* = *quat* the force is applied along the axis obtained by rotating the x-axis along the atom's quaternion. In other words, the force is along the x-axis in the atom's body frame. This mode requires -all atoms in the group to have a quaternion, so atom\_style should +all atoms in the group to have a quaternion, so atom_style should either be ellipsoid or body. In combination with Langevin thermostat for translation and rotation in the overdamped regime, the quaternion mode corresponds to the active Brownian particle model introduced by @@ -57,7 +57,7 @@ on through the *types* keyword. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. @@ -69,7 +69,7 @@ Restrictions In quat mode, this fix makes use of per-atom quaternions to take into account the fact that the orientation can rotate and hence the direction of the active force can change. The quat mode -of this fix only works with atom\_style ellipsoid. +of this fix only works with atom_style ellipsoid. Related commands """""""""""""""" diff --git a/doc/src/fix_property_atom.rst b/doc/src/fix_property_atom.rst index 63cdbd0701..f866ddf7a2 100644 --- a/doc/src/fix_property_atom.rst +++ b/doc/src/fix_property_atom.rst @@ -15,7 +15,7 @@ Syntax * ID, group-ID are documented in :doc:`fix ` command * property/atom = style name of this fix command -* vec1,vec2,... = *mol* or *q* or *rmass* or *i\_name* or *d\_name* +* vec1,vec2,... = *mol* or *q* or *rmass* or *i_name* or *d_name* .. parsed-literal:: @@ -84,7 +84,7 @@ In the future, we may add additional per-atom properties similar to by some atom styles, so they can be used by atom styles that do not define them. -More generally, the *i\_name* and *d\_name* vectors allow one or more +More generally, the *i_name* and *d_name* vectors allow one or more new custom per-atom properties to be defined. Each name must be unique and can use alphanumeric or underscore characters. These vectors can store whatever values you decide are useful in your @@ -197,7 +197,7 @@ properties in a completely general fashion. ---------- -For new atom properties specified as *i\_name* or *d\_name*, the +For new atom properties specified as *i_name* or *d_name*, the :doc:`compute property/atom ` command can access their values. This means that the values can be output via the :doc:`dump custom ` command, accessed by fixes like :doc:`fix ave/atom `, accessed by other computes like :doc:`compute reduce `, or used in :doc:`atom-style variables `. @@ -284,7 +284,7 @@ instructions on how to use the accelerated styles effectively. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the per-atom values it stores to :doc:`binary restart files `, so that the values can be restored when a simulation is restarted. See the :doc:`read_restart ` diff --git a/doc/src/fix_python_invoke.rst b/doc/src/fix_python_invoke.rst index 0144e3c4f7..94bad11f00 100644 --- a/doc/src/fix_python_invoke.rst +++ b/doc/src/fix_python_invoke.rst @@ -13,7 +13,7 @@ Syntax * ID, group-ID are ignored by this fix * python/invoke = style name of this fix command * N = execute every N steps -* callback = *post\_force* or *end\_of\_step* +* callback = *post_force* or *end_of_step* .. parsed-literal:: diff --git a/doc/src/fix_python_move.rst b/doc/src/fix_python_move.rst index af32106806..07f61c2b85 100644 --- a/doc/src/fix_python_move.rst +++ b/doc/src/fix_python_move.rst @@ -82,7 +82,7 @@ Examples for how to do this are in the *examples/python* folder. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_qbmsst.rst b/doc/src/fix_qbmsst.rst index 57a2c88fac..b7a4f49300 100644 --- a/doc/src/fix_qbmsst.rst +++ b/doc/src/fix_qbmsst.rst @@ -15,7 +15,7 @@ Syntax * dir = *x* or *y* or *z* * shockvel = shock velocity (strictly positive, velocity units) * zero or more keyword/value pairs may be appended -* keyword = *q* or *mu* or *p0* or *v0* or *e0* or *tscale* or *damp* or *seed*\ or *f\_max* or *N\_f* or *eta* or *beta* or *T\_init* +* keyword = *q* or *mu* or *p0* or *v0* or *e0* or *tscale* or *damp* or *seed*\ or *f_max* or *N_f* or *eta* or *beta* or *T_init* .. parsed-literal:: @@ -95,15 +95,15 @@ Hugoniot that is 40% lower than observed with classical molecular dynamics. It is highly recommended that the system be already in an equilibrium -state with a quantum thermal bath at temperature of *T\_init*. The fix -command :doc:`fix qtb ` at constant temperature *T\_init* could +state with a quantum thermal bath at temperature of *T_init*. The fix +command :doc:`fix qtb ` at constant temperature *T_init* could be used before applying this command to introduce self-consistent quantum nuclear effects into the initial state. The parameters *q*\ , *mu*\ , *e0*\ , *p0*\ , *v0* and *tscale* are described in the command :doc:`fix msst `. The values of *e0*\ , *p0*\ , or *v0* will be calculated on the first step if not specified. The -parameter of *damp*\ , *f\_max*, and *N\_f* are described in the command +parameter of *damp*\ , *f_max*, and *N_f* are described in the command :doc:`fix qtb `. The *fix qbmsst* command couples the shock system to a quantum thermal @@ -135,7 +135,7 @@ of the *damp* parameter. \frac{dT^{qm}}{dt} = \gamma\eta\sum^\beta_{l=1}\frac{E^{tot}(t-l\Delta t) - E^{tot}_0}{3\beta N k_B} -The parameter *T\_init* is the initial temperature of the quantum +The parameter *T_init* is the initial temperature of the quantum thermal bath and the system before shock loading. For all pressure styles, the simulation box stays orthorhombic in @@ -144,29 +144,29 @@ supported by LAMMPS, but are not implemented for QBMSST. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** Because the state of the random number generator is not written to :doc:`binary restart files `, this fix cannot be restarted "exactly" in an uninterrupted fashion. However, in a statistical sense, a restarted simulation should produce similar behaviors of the system as if it is not interrupted. To achieve such a restart, one -should write explicitly the same value for *q*\ , *mu*\ , *damp*\ , *f\_max*, -*N\_f*, *eta*\ , and *beta* and set *tscale* = 0 if the system is +should write explicitly the same value for *q*\ , *mu*\ , *damp*\ , *f_max*, +*N_f*, *eta*\ , and *beta* and set *tscale* = 0 if the system is compressed during the first run. The progress of the QBMSST can be monitored by printing the global scalar and global vector quantities computed by the fix. The global vector contains five values in this order: -[\ *dhugoniot*\ , *drayleigh*\ , *lagrangian\_speed*, *lagrangian\_position*, -*quantum\_temperature*] +[\ *dhugoniot*\ , *drayleigh*\ , *lagrangian_speed*, *lagrangian_position*, +*quantum_temperature*] 1. *dhugoniot* is the departure from the Hugoniot (temperature units). 2. *drayleigh* is the departure from the Rayleigh line (pressure units). -3. *lagrangian\_speed* is the laboratory-frame Lagrangian speed (particle velocity) of the computational cell (velocity units). -4. *lagrangian\_position* is the computational cell position in the reference frame moving at the shock speed. This is the distance of the computational cell behind the shock front. -5. *quantum\_temperature* is the temperature of the quantum thermal bath :math:`T^{qm}`. +3. *lagrangian_speed* is the laboratory-frame Lagrangian speed (particle velocity) of the computational cell (velocity units). +4. *lagrangian_position* is the computational cell position in the reference frame moving at the shock speed. This is the distance of the computational cell behind the shock front. +5. *quantum_temperature* is the temperature of the quantum thermal bath :math:`T^{qm}`. To print these quantities to the log file with descriptive column headers, the following LAMMPS commands are suggested. Here the @@ -185,7 +185,7 @@ also the :doc:`thermo_style ` command. variable T_qm equal f_fix_id[5] thermo_style custom step temp ke pe lz pzz etotal v_dhug v_dray v_lgr_vel v_lgr_pos v_T_qm f_fix_id -The global scalar under the entry f\_fix\_id is the quantity of thermo +The global scalar under the entry f_fix_id is the quantity of thermo energy as an extra part of :math:`E^{tot}`. This global scalar and the vector of 5 quantities can be accessed by various :doc:`output commands `. It is worth noting that the temp keyword @@ -218,8 +218,8 @@ Default """"""" The keyword defaults are q = 10, mu = 0, tscale = 0.01, damp = 1, seed -= 880302, f\_max = 200.0, N\_f = 100, eta = 1.0, beta = 100, and -T\_init=300.0. e0, p0, and v0 are calculated on the first step. += 880302, f_max = 200.0, N_f = 100, eta = 1.0, beta = 100, and +T_init=300.0. e0, p0, and v0 are calculated on the first step. ---------- diff --git a/doc/src/fix_qeq.rst b/doc/src/fix_qeq.rst index 418fc383b4..ea53fc2b2e 100644 --- a/doc/src/fix_qeq.rst +++ b/doc/src/fix_qeq.rst @@ -193,7 +193,7 @@ better on larger sizes, and *qeq/fire* is faster than *qeq/dynamic*\ . arbitrary choices of these parameters. We do not develop these QEq parameters. See the examples/qeq directory for some examples. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about these fixes is written to :doc:`binary restart files `. No global scalar or vector or per-atom quantities are stored by these fixes for access by various :doc:`output commands `. No parameter of these fixes can be used diff --git a/doc/src/fix_qeq_comb.rst b/doc/src/fix_qeq_comb.rst index 012f524b9e..c815ac7eb3 100644 --- a/doc/src/fix_qeq_comb.rst +++ b/doc/src/fix_qeq_comb.rst @@ -37,7 +37,7 @@ Description Perform charge equilibration (QeQ) in conjunction with the COMB (Charge-Optimized Many-Body) potential as described in -:ref:`(COMB\_1) ` and :ref:`(COMB\_2) `. It performs the charge +:ref:`(COMB_1) ` and :ref:`(COMB_2) `. It performs the charge equilibration portion of the calculation using the so-called QEq method, whereby the charge on each atom is adjusted to minimize the energy of the system. This fix can only be used with the COMB @@ -50,8 +50,8 @@ per-atom electronegativity (effective force on the charges). An electronegativity equalization calculation (or QEq) is performed in an iterative fashion, which in parallel requires communication at each iteration for processors to exchange charge information about nearby -atoms with each other. See :ref:`Rappe\_and\_Goddard ` and -:ref:`Rick\_and\_Stuart ` for details. +atoms with each other. See :ref:`Rappe_and_Goddard ` and +:ref:`Rick_and_Stuart ` for details. During a run, charge equilibration is performed every *Nevery* time steps. Charge equilibration is also always enforced on the first step @@ -85,7 +85,7 @@ instructions on how to use the accelerated styles effectively. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. @@ -121,21 +121,21 @@ No file output is performed. ---------- -.. _COMB\_1: +.. _COMB_1: -**(COMB\_1)** J. Yu, S. B. Sinnott, S. R. Phillpot, Phys Rev B, 75, 085311 (2007), +**(COMB_1)** J. Yu, S. B. Sinnott, S. R. Phillpot, Phys Rev B, 75, 085311 (2007), -.. _COMB\_2: +.. _COMB_2: -**(COMB\_2)** T.-R. Shan, B. D. Devine, T. W. Kemper, S. B. Sinnott, S. R. +**(COMB_2)** T.-R. Shan, B. D. Devine, T. W. Kemper, S. B. Sinnott, S. R. Phillpot, Phys Rev B, 81, 125328 (2010). -.. _Rappe\_and\_Goddard: +.. _Rappe_and_Goddard: -**(Rappe\_and\_Goddard)** A. K. Rappe, W. A. Goddard, J Phys Chem 95, 3358 +**(Rappe_and_Goddard)** A. K. Rappe, W. A. Goddard, J Phys Chem 95, 3358 (1991). -.. _Rick\_and\_Stuart: +.. _Rick_and_Stuart: -**(Rick\_and\_Stuart)** S. W. Rick, S. J. Stuart, B. J. Berne, J Chem Phys +**(Rick_and_Stuart)** S. W. Rick, S. J. Stuart, B. J. Berne, J Chem Phys 101, 16141 (1994). diff --git a/doc/src/fix_qeq_reax.rst b/doc/src/fix_qeq_reax.rst index 854dc01991..1c722606a7 100644 --- a/doc/src/fix_qeq_reax.rst +++ b/doc/src/fix_qeq_reax.rst @@ -71,7 +71,7 @@ The optional *dual* keyword allows to perform the optimization of the S and T matrices in parallel. This is only supported for the *qeq/reax/omp* style. Otherwise they are processed separately. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. No global scalar or vector or per-atom quantities are stored by this fix for access by various :doc:`output commands `. No parameter of this fix can be used diff --git a/doc/src/fix_qmmm.rst b/doc/src/fix_qmmm.rst index 889004b9f8..4eb45e490f 100644 --- a/doc/src/fix_qmmm.rst +++ b/doc/src/fix_qmmm.rst @@ -42,7 +42,7 @@ to be adapted if necessary before being finalized. Details about how to use this fix are currently documented in the description of the QM/MM interface code itself in lib/qmmm/README. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global scalar or vector or per-atom diff --git a/doc/src/fix_qtb.rst b/doc/src/fix_qtb.rst index 6980442c9c..6dfabcbaa7 100644 --- a/doc/src/fix_qtb.rst +++ b/doc/src/fix_qtb.rst @@ -13,7 +13,7 @@ Syntax * ID, group-ID are documented in :doc:`fix ` command * qtb = style name of this fix * zero or more keyword/value pairs may be appended -* keyword = *temp* or *damp* or *seed* or *f\_max* or *N\_f* +* keyword = *temp* or *damp* or *seed* or *f_max* or *N_f* .. parsed-literal:: @@ -109,23 +109,23 @@ to generate its own unique seed and its own stream of random numbers. Thus the dynamics of the system will not be identical on two runs on different numbers of processors. -The *f\_max* parameter truncate the noise frequency domain so that -vibrational modes with frequencies higher than *f\_max* will not be +The *f_max* parameter truncate the noise frequency domain so that +vibrational modes with frequencies higher than *f_max* will not be modulated. If we denote :math:`\Delta t` as the time interval for the -MD integration, *f\_max* is always reset by the code to make -:math:`\alpha = (int)(2` *f\_max* :math:`\Delta t)^{-1}` a +MD integration, *f_max* is always reset by the code to make +:math:`\alpha = (int)(2` *f_max* :math:`\Delta t)^{-1}` a positive integer and print out relative information. An appropriate -value for the cutoff frequency *f\_max* would be around 2~3 :math:`f_D`, +value for the cutoff frequency *f_max* would be around 2~3 :math:`f_D`, where :math:`f_D` is the Debye frequency. -The *N\_f* parameter is the frequency grid size, the number of points -from 0 to *f\_max* in the frequency domain that will be -sampled. 3*2\ *N\_f* per-atom random numbers are required +The *N_f* parameter is the frequency grid size, the number of points +from 0 to *f_max* in the frequency domain that will be +sampled. 3*2\ *N_f* per-atom random numbers are required in the random force generation and there could be as many atoms as in the whole simulation that can migrate into every individual -processor. A larger *N\_f* provides a more accurate sampling of the -spectrum while consumes more memory. With fixed *f\_max* and -:math:`\gamma`, *N\_f* should be big enough to converge the classical +processor. A larger *N_f* provides a more accurate sampling of the +spectrum while consumes more memory. With fixed *f_max* and +:math:`\gamma`, *N_f* should be big enough to converge the classical temperature :math:`T^{cl}` as a function of target quantum bath temperature. Memory usage per processor could be from 10 to 100 Mbytes. @@ -145,7 +145,7 @@ Mbytes. ---------- -**Restart, fix\_modify, output, run start/stop, minimizie info:** +**Restart, fix_modify, output, run start/stop, minimizie info:** No information about this fix is written to :doc:`binary restart files `. Because the state of the random number generator is not @@ -178,7 +178,7 @@ Default """"""" The keyword defaults are temp = 300, damp = 1, seed = 880302, -f\_max=200.0 and N\_f = 100. +f_max=200.0 and N_f = 100. ---------- diff --git a/doc/src/fix_reaxc_bonds.rst b/doc/src/fix_reaxc_bonds.rst index 01b1a8dadf..8f50473af8 100644 --- a/doc/src/fix_reaxc_bonds.rst +++ b/doc/src/fix_reaxc_bonds.rst @@ -43,11 +43,11 @@ The meaning of the column header abbreviations is as follows: * id = atom id * type = atom type * nb = number of bonds -* id\_1 = atom id of first bond -* id\_nb = atom id of Nth bond +* id_1 = atom id of first bond +* id_nb = atom id of Nth bond * mol = molecule id -* bo\_1 = bond order of first bond -* bo\_nb = bond order of Nth bond +* bo_1 = bond order of first bond +* bo_nb = bond order of Nth bond * abo = atom bond order (sum of all bonds) * nlp = number of lone pairs * q = atomic charge @@ -58,7 +58,7 @@ version, but will also take longer to write. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored @@ -98,7 +98,7 @@ package. See the :doc:`Build package ` doc page for more info. To write gzipped bond files, you must compile LAMMPS with the --DLAMMPS\_GZIP option. +-DLAMMPS_GZIP option. Related commands """""""""""""""" diff --git a/doc/src/fix_reaxc_species.rst b/doc/src/fix_reaxc_species.rst index 96ad89d7fe..63beb5520d 100644 --- a/doc/src/fix_reaxc_species.rst +++ b/doc/src/fix_reaxc_species.rst @@ -73,7 +73,7 @@ symbol printed for each LAMMPS atom type. The number of symbols must match the number of LAMMPS atom types and each symbol must consist of 1 or 2 alphanumeric characters. Normally, these symbols should be chosen to match the chemical identity of each LAMMPS atom type, as -specified using the :doc:`reax/c pair\_coeff ` command and +specified using the :doc:`reax/c pair_coeff ` command and the ReaxFF force field file. The optional keyword *position* writes center-of-mass positions of @@ -112,7 +112,7 @@ average bond-order for the species analysis output on timestep 100. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. @@ -167,9 +167,9 @@ package. See the :doc:`Build package ` doc page for more info. To write gzipped species files, you must compile LAMMPS with the --DLAMMPS\_GZIP option. +-DLAMMPS_GZIP option. -It should be possible to extend it to other reactive pair\_styles (such as +It should be possible to extend it to other reactive pair_styles (such as :doc:`rebo `, :doc:`airebo `, :doc:`comb `, and :doc:`bop `), but this has not yet been done. diff --git a/doc/src/fix_recenter.rst b/doc/src/fix_recenter.rst index 88cdc8d227..eec224c67d 100644 --- a/doc/src/fix_recenter.rst +++ b/doc/src/fix_recenter.rst @@ -93,7 +93,7 @@ velocities with zero aggregate linear and/or angular momentum. simulation scenario is to use the :doc:`fix spring ` command to tether the molecule in place. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. diff --git a/doc/src/fix_restrain.rst b/doc/src/fix_restrain.rst index 2a2edcb236..3965cee04d 100644 --- a/doc/src/fix_restrain.rst +++ b/doc/src/fix_restrain.rst @@ -182,7 +182,7 @@ current dihedral angle :math:`\phi` is equal to :math:`\phi_0`. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_rigid.rst b/doc/src/fix_rigid.rst index 2e70b63ed3..72ed56bab1 100644 --- a/doc/src/fix_rigid.rst +++ b/doc/src/fix_rigid.rst @@ -182,7 +182,7 @@ The *rigid* styles are typically the best choice for a system with a small number of large rigid bodies, each of which can extend across the domain of many processors. It operates by creating a single global list of rigid bodies, which all processors contribute to. -MPI\_Allreduce operations are performed each timestep to sum the +MPI_Allreduce operations are performed each timestep to sum the contributions from each processor to the force and torque on all the bodies. This operation will not scale well in parallel if large numbers of rigid bodies are simulated. @@ -756,7 +756,7 @@ instructions on how to use the accelerated styles effectively. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about the 4 NVE rigid styles is written to :doc:`binary restart files `. The exception is if the *infile* or *mol* keyword is used, in which case an auxiliary file is written out diff --git a/doc/src/fix_rigid_meso.rst b/doc/src/fix_rigid_meso.rst index eec2686be7..c9a709175f 100644 --- a/doc/src/fix_rigid_meso.rst +++ b/doc/src/fix_rigid_meso.rst @@ -286,7 +286,7 @@ cross periodic boundaries during the simulation. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information is written to :doc:`binary restart files `. If the *infile* keyword is used, an auxiliary file is written out diff --git a/doc/src/fix_rx.rst b/doc/src/fix_rx.rst index ba6dc393d9..c79fd2178b 100644 --- a/doc/src/fix_rx.rst +++ b/doc/src/fix_rx.rst @@ -18,7 +18,7 @@ Syntax * file = filename containing the reaction kinetic equations and Arrhenius parameters * localTemp = *none,lucy* = no local temperature averaging or local temperature defined through Lucy weighting function * matrix = *sparse, dense* format for the stoichiometric matrix -* solver = *lammps\_rk4,rkf45* = rk4 is an explicit 4th order Runge-Kutta method; rkf45 is an adaptive 4th-order Runge-Kutta-Fehlberg method +* solver = *lammps_rk4,rkf45* = rk4 is an explicit 4th order Runge-Kutta method; rkf45 is an adaptive 4th-order Runge-Kutta-Fehlberg method * minSteps = # of steps for rk4 solver or minimum # of steps for rkf45 (rk4 or rkf45) * maxSteps = maximum number of steps for the rkf45 solver (rkf45 only) * relTol = relative tolerance for the rkf45 solver (rkf45 only) @@ -63,10 +63,10 @@ constructed based on the *n* reaction rate equations. The ODE systems are solved over the full DPD timestep *dt* using either a 4th order Runge-Kutta *rk4* method with a fixed step-size *h*\ , specified -by the *lammps\_rk4* keyword, or a 4th order Runge-Kutta-Fehlberg (rkf45) method +by the *lammps_rk4* keyword, or a 4th order Runge-Kutta-Fehlberg (rkf45) method with an adaptive step-size for *h*\ . The number of ODE steps per DPD timestep for the rk4 method is optionally specified immediately after the rk4 -keyword. The ODE step-size is set as *dt/num\_steps*. Smaller +keyword. The ODE step-size is set as *dt/num_steps*. Smaller step-sizes tend to yield more accurate results but there is not control on the error. For error control, use the rkf45 ODE solver. @@ -74,13 +74,13 @@ The rkf45 method adjusts the step-size so that the local truncation error is hel within the specified absolute and relative tolerances. The initial step-size *h0* can be specified by the user or estimated internally. It is recommended that the user specify *h0* since this will generally reduced the number of ODE integration steps -required. *h0* is defined as *dt / min\_steps* if min\_steps >= 1. If min\_steps == 0, +required. *h0* is defined as *dt / min_steps* if min_steps >= 1. If min_steps == 0, *h0* is estimated such that an explicit Euler method would likely produce an acceptable solution. This is generally overly conservative for the 4th-order method and users are advised to specify *h0* as some fraction of the DPD timestep. For small DPD timesteps, only one step may be necessary depending upon the tolerances. -Note that more than min\_steps ODE steps may be taken depending upon the ODE stiffness -but no more than max\_steps will be taken. If max\_steps is reached, an error warning +Note that more than min_steps ODE steps may be taken depending upon the ODE stiffness +but no more than max_steps will be taken. If max_steps is reached, an error warning is printed and the simulation is stopped. After each ODE step, the solution error *e* is tested and weighted using the absTol @@ -189,13 +189,13 @@ Note that the species tags that are defined in the reaction equations are used by the :doc:`fix eos/table/rx ` command to define the thermodynamic properties of each species. Furthermore, the number of species molecules (i.e., concentration) can be specified -either with the :doc:`set ` command using the "d\_" prefix or by +either with the :doc:`set ` command using the "d_" prefix or by reading directly the concentrations from a data file. For the latter case, the :doc:`read_data ` command with the fix keyword should be specified, where the fix-ID will be the "fix rx`ID with a `_ suffix, e.g. fix foo all rx reaction.file ... -read\_data data.dpd fix foo\_SPECIES NULL Species +read_data data.dpd fix foo_SPECIES NULL Species ---------- diff --git a/doc/src/fix_saed_vtk.rst b/doc/src/fix_saed_vtk.rst index d0adefee00..818d14cc60 100644 --- a/doc/src/fix_saed_vtk.rst +++ b/doc/src/fix_saed_vtk.rst @@ -15,7 +15,7 @@ Syntax * Nevery = use input values every this many timesteps * Nrepeat = # of times to use input values for calculating averages * Nfreq = calculate averages every this many timesteps -* c\_ID = saed compute ID +* c_ID = saed compute ID .. parsed-literal:: @@ -56,7 +56,7 @@ outside the *Kmax* range assigned in the compute saed. The ghost data is assigned a value of -1 and can be removed setting a minimum isovolume of 0 within the visualization software. SAED images can be created by visualizing a spherical slice of the data that is centered at -R\_Ewald\*[h k l]/norm([h k l]), where R\_Ewald=1/lambda. +R_Ewald\*[h k l]/norm([h k l]), where R_Ewald=1/lambda. The group specified within this command is ignored. However, note that specified values may represent calculations performed by saed computes @@ -94,7 +94,7 @@ averaging is done; values are simply generated on timesteps The output for fix ave/time/saed is a file written with the 3rd generation vtk image data formatting. The filename assigned by the *file* keyword is -appended with \_N.vtk where N is an index (0,1,2...) to account for multiple +appended with _N.vtk where N is an index (0,1,2...) to account for multiple diffraction intensity outputs. By default the header contains the following information (with example data): @@ -157,7 +157,7 @@ running or windowed average. The *file* keyword allows a filename to be specified. Every *Nfreq* steps, the vector of saed intensity data is written to a new file using the 3rd generation vtk format. The base of each file is assigned by -the *file* keyword and this string is appended with \_N.vtk where N is +the *file* keyword and this string is appended with _N.vtk where N is an index (0,1,2...) to account for situations with multiple diffraction intensity outputs. @@ -165,7 +165,7 @@ The *overwrite* keyword will continuously overwrite the output file with the latest output, so that it only contains one timestep worth of output. This option can only be used with the *ave running* setting. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. @@ -176,7 +176,7 @@ the :doc:`run ` command. This fix is not invoked during :doc:`energy minim Restrictions """""""""""" -The attributes for fix\_saed\_vtk must match the values assigned in the +The attributes for fix_saed_vtk must match the values assigned in the associated :doc:`compute_saed ` command. Related commands diff --git a/doc/src/fix_setforce.rst b/doc/src/fix_setforce.rst index 1b53bfe200..59de49fbe0 100644 --- a/doc/src/fix_setforce.rst +++ b/doc/src/fix_setforce.rst @@ -55,7 +55,7 @@ alter the force component in that dimension. Any of the 3 quantities defining the force components can be specified as an equal-style or atom-style :doc:`variable `, namely *fx*\ , *fy*\ , *fz*\ . If the value is a variable, it should be specified as -v\_name, where name is the variable name. In this case, the variable +v_name, where name is the variable name. In this case, the variable will be evaluated each timestep, and its value used to determine the force component. @@ -111,7 +111,7 @@ instructions on how to use the accelerated styles effectively. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_shake.rst b/doc/src/fix_shake.rst index d687920e97..cd3fbd3865 100644 --- a/doc/src/fix_shake.rst +++ b/doc/src/fix_shake.rst @@ -121,7 +121,7 @@ constraint lists atom types. All bonds connected to an atom of the specified type will be constrained. The *m* constraint lists atom masses. All bonds connected to atoms of the specified masses will be constrained (within a fudge factor of MASSDELTA specified in -fix\_shake.cpp). The *a* constraint lists angle types. If both bonds +fix_shake.cpp). The *a* constraint lists angle types. If both bonds in the angle are constrained then the angle will also be constrained if its type is in the list. @@ -195,12 +195,12 @@ LAMMPS closely follows (:ref:`Andersen (1983) `). after fix rattle operates, then fix rattle will not take them into account and the overall time integration will typically not satisfy the RATTLE constraints. You can check whether the constraints work - correctly by setting the value of RATTLE\_DEBUG in src/fix\_rattle.cpp + correctly by setting the value of RATTLE_DEBUG in src/fix_rattle.cpp to 1 and recompiling LAMMPS. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** The :doc:`fix_modify ` *virial* option is supported by this fix to add the contribution due to keeping the constraints to the diff --git a/doc/src/fix_shardlow.rst b/doc/src/fix_shardlow.rst index a5ce32c89a..9949d3a51c 100644 --- a/doc/src/fix_shardlow.rst +++ b/doc/src/fix_shardlow.rst @@ -42,12 +42,12 @@ necessary). Note that numerous variants of DPD can be specified by choosing an appropriate combination of the integrator and :doc:`pair_style dpd/fdt ` command. DPD under isothermal conditions can -be specified by using fix *shardlow*\ , fix *nve* and pair\_style +be specified by using fix *shardlow*\ , fix *nve* and pair_style *dpd/fdt*\ . DPD under isoenergetic conditions can be specified by -using fix *shardlow*\ , fix *nve* and pair\_style *dpd/fdt/energy*\ . DPD +using fix *shardlow*\ , fix *nve* and pair_style *dpd/fdt/energy*\ . DPD under isobaric conditions can be specified by using fix shardlow, fix -*nph* and pair\_style *dpd/fdt*\ . DPD under isoenthalpic conditions can -be specified by using fix shardlow, fix *nph* and pair\_style +*nph* and pair_style *dpd/fdt*\ . DPD under isoenthalpic conditions can +be specified by using fix shardlow, fix *nph* and pair_style *dpd/fdt/energy*\ . Examples of each DPD variant are provided in the examples/USER/dpd directory. diff --git a/doc/src/fix_smd.rst b/doc/src/fix_smd.rst index ddd6a15505..b303114887 100644 --- a/doc/src/fix_smd.rst +++ b/doc/src/fix_smd.rst @@ -99,7 +99,7 @@ can then later be used to compute the potential of mean force (PMF) by averaging over multiple independent trajectories along the same pulling path. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** The fix stores the direction of the spring, current pulling target distance and the running PMF to :doc:`binary restart files `. diff --git a/doc/src/fix_smd_adjust_dt.rst b/doc/src/fix_smd_adjust_dt.rst index 3135df2dbf..d91ad1392d 100644 --- a/doc/src/fix_smd_adjust_dt.rst +++ b/doc/src/fix_smd_adjust_dt.rst @@ -11,8 +11,8 @@ Syntax fix ID group-ID smd/adjust_dt arg * ID, group-ID are documented in :doc:`fix ` command -* smd/adjust\_dt = style name of this fix command -* arg = *s\_fact* +* smd/adjust_dt = style name of this fix command +* arg = *s_fact* .. parsed-literal:: @@ -41,12 +41,12 @@ step. This fix inquires the minimum stable time increment across all particles contained in the group for which this fix is defined. An -additional safety factor *s\_fact* is applied to the time increment. +additional safety factor *s_fact* is applied to the time increment. See `this PDF guide `_ to use Smooth Mach Dynamics in LAMMPS. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** Currently, no part of USER-SMD supports restarting nor minimization. @@ -59,6 +59,6 @@ LAMMPS was built with that package. See the :doc:`Build package Related commands """""""""""""""" -:doc:`smd/tlsph\_dt ` +:doc:`smd/tlsph_dt ` **Default:** none diff --git a/doc/src/fix_smd_integrate_tlsph.rst b/doc/src/fix_smd_integrate_tlsph.rst index 7536e1f6e2..ef91414788 100644 --- a/doc/src/fix_smd_integrate_tlsph.rst +++ b/doc/src/fix_smd_integrate_tlsph.rst @@ -11,9 +11,9 @@ Syntax fix ID group-ID smd/integrate_tlsph keyword values * ID, group-ID are documented in :doc:`fix ` command -* smd/integrate\_tlsph = style name of this fix command +* smd/integrate_tlsph = style name of this fix command * zero or more keyword/value pairs may be appended -* keyword = *limit\_velocity* +* keyword = *limit_velocity* .. parsed-literal:: @@ -37,11 +37,11 @@ interact according with the Total-Lagrangian SPH pair style. See `this PDF guide `_ to using Smooth Mach Dynamics in LAMMPS. -The *limit\_velocity* keyword will control the velocity, scaling the -norm of the velocity vector to max\_vel in case it exceeds this +The *limit_velocity* keyword will control the velocity, scaling the +norm of the velocity vector to max_vel in case it exceeds this velocity limit. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** Currently, no part of USER-SMD supports restarting nor minimization. This fix has no outputs. @@ -55,6 +55,6 @@ LAMMPS was built with that package. See the :doc:`Build package Related commands """""""""""""""" -:doc:`smd/integrate\_ulsph ` +:doc:`smd/integrate_ulsph ` **Default:** none diff --git a/doc/src/fix_smd_integrate_ulsph.rst b/doc/src/fix_smd_integrate_ulsph.rst index 36197bd057..c355abf17b 100644 --- a/doc/src/fix_smd_integrate_ulsph.rst +++ b/doc/src/fix_smd_integrate_ulsph.rst @@ -11,16 +11,16 @@ Syntax fix ID group-ID smd/integrate_ulsph keyword * ID, group-ID are documented in :doc:`fix ` command -* smd/integrate\_ulsph = style name of this fix command +* smd/integrate_ulsph = style name of this fix command * zero or more keyword/value pairs may be appended -* keyword = adjust\_radius or limit\_velocity +* keyword = adjust_radius or limit_velocity -adjust\_radius values = adjust\_radius\_factor min\_nn max\_nn - adjust\_radius\_factor = factor which scale the smooth/kernel radius - min\_nn = minimum number of neighbors - max\_nn = maximum number of neighbors -limit\_velocity values = max\_velocity - max\_velocity = maximum allowed velocity. +adjust_radius values = adjust_radius_factor min_nn max_nn + adjust_radius_factor = factor which scale the smooth/kernel radius + min_nn = minimum number of neighbors + max_nn = maximum number of neighbors +limit_velocity values = max_velocity + max_velocity = maximum allowed velocity. Examples """""""" @@ -39,17 +39,17 @@ interact with the updated Lagrangian SPH pair style. See `this PDF guide `_ to using Smooth Mach Dynamics in LAMMPS. -The *adjust\_radius* keyword activates dynamic adjustment of the +The *adjust_radius* keyword activates dynamic adjustment of the per-particle SPH smoothing kernel radius such that the number of -neighbors per particles remains within the interval *min\_nn* to -*max\_nn*. The parameter *adjust\_radius\_factor* determines the amount -of adjustment per timestep. Typical values are *adjust\_radius\_factor* -=1.02, *min\_nn* =15, and *max\_nn* =20. +neighbors per particles remains within the interval *min_nn* to +*max_nn*. The parameter *adjust_radius_factor* determines the amount +of adjustment per timestep. Typical values are *adjust_radius_factor* +=1.02, *min_nn* =15, and *max_nn* =20. -The *limit\_velocity* keyword will control the velocity, scaling the norm of -the velocity vector to max\_vel in case it exceeds this velocity limit. +The *limit_velocity* keyword will control the velocity, scaling the norm of +the velocity vector to max_vel in case it exceeds this velocity limit. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** Currently, no part of USER-SMD supports restarting nor minimization. This fix has no outputs. diff --git a/doc/src/fix_smd_move_triangulated_surface.rst b/doc/src/fix_smd_move_triangulated_surface.rst index 7dc3758f30..3aa40a75c2 100644 --- a/doc/src/fix_smd_move_triangulated_surface.rst +++ b/doc/src/fix_smd_move_triangulated_surface.rst @@ -11,7 +11,7 @@ Syntax fix ID group-ID smd/move_tri_surf keyword * ID, group-ID are documented in :doc:`fix ` command -* smd/move\_tri\_surf keyword = style name of this fix command +* smd/move_tri_surf keyword = style name of this fix command * keyword = *\*LINEAR* or *\*WIGGLE* or *\*ROTATE* .. parsed-literal:: @@ -39,7 +39,7 @@ Description """"""""""" This fix applies only to rigid surfaces read from .STL files via fix -:doc:`smd/wall\_surface ` . It updates position +:doc:`smd/wall_surface ` . It updates position and velocity for the particles in the group each timestep without regard to forces on the particles. The rigid surfaces can thus be moved along simple trajectories during the simulation. @@ -50,7 +50,7 @@ to V = (Vx,Vy,Vz). The *\*WIGGLE* style moves particles in an oscillatory fashion. Particles are moved along (vx, vy, vz) with constant velocity until a -displacement of max\_travel is reached. Then, the velocity vector is +displacement of max_travel is reached. Then, the velocity vector is reversed. This process is repeated. The *\*ROTATE* style rotates particles around a rotation axis R = @@ -63,7 +63,7 @@ rotation axis to the particle. See `this PDF guide `_ to using Smooth Mach Dynamics in LAMMPS. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** Currently, no part of USER-SMD supports restarting nor minimization. This fix has no outputs. @@ -77,7 +77,7 @@ LAMMPS was built with that package. See the :doc:`Build package Related commands """""""""""""""" -:doc:`smd/triangle\_mesh\_vertices `, -:doc:`smd/wall\_surface ` +:doc:`smd/triangle_mesh_vertices `, +:doc:`smd/wall_surface ` **Default:** none diff --git a/doc/src/fix_smd_setvel.rst b/doc/src/fix_smd_setvel.rst index bdf97354f5..eb92f435e1 100644 --- a/doc/src/fix_smd_setvel.rst +++ b/doc/src/fix_smd_setvel.rst @@ -44,7 +44,7 @@ This fix is indented to be used together with a time integration fix. Any of the 3 quantities defining the velocity components can be specified as an equal-style or atom-style :doc:`variable `, namely *vx*\ , *vy*\ , *vz*\ . If the value is a variable, it should be specified as -v\_name, where name is the variable name. In this case, the variable +v_name, where name is the variable name. In this case, the variable will be evaluated each timestep, and its value used to determine the force component. @@ -63,7 +63,7 @@ specified geometric :doc:`region ` in order to have its velocity set by ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** Currently, no part of USER-SMD supports restarting nor minimization None of the :doc:`fix_modify ` options diff --git a/doc/src/fix_smd_wall_surface.rst b/doc/src/fix_smd_wall_surface.rst index fcb007363b..6bebcdf6c2 100644 --- a/doc/src/fix_smd_wall_surface.rst +++ b/doc/src/fix_smd_wall_surface.rst @@ -11,7 +11,7 @@ Syntax fix ID group-ID smd/wall_surface arg type mol-ID * ID, group-ID are documented in :doc:`fix ` command -* smd/wall\_surface = style name of this fix command +* smd/wall_surface = style name of this fix command * arg = *file* .. parsed-literal:: @@ -38,19 +38,19 @@ the new particle is that of the minimum circle which encompasses the triangle vertices. The triangulated surface can be used as a complex rigid wall via the -:doc:`smd/tri\_surface ` pair style. It +:doc:`smd/tri_surface ` pair style. It is possible to move the triangulated surface via the -:doc:`smd/move\_tri\_surf ` fix style. +:doc:`smd/move_tri_surf ` fix style. Immediately after a .STL file has been read, the simulation needs to be run for 0 timesteps in order to properly register the new particles -in the system. See the "funnel\_flow" example in the USER-SMD examples +in the system. See the "funnel_flow" example in the USER-SMD examples directory. See `this PDF guide `_ to use Smooth Mach Dynamics in LAMMPS. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** Currently, no part of USER-SMD supports restarting nor minimization. This fix has no outputs. @@ -71,8 +71,8 @@ multiple objects in one file. Related commands """""""""""""""" -:doc:`smd/triangle\_mesh\_vertices `, -:doc:`smd/move\_tri\_surf `, -:doc:`smd/tri\_surface ` +:doc:`smd/triangle_mesh_vertices `, +:doc:`smd/move_tri_surf `, +:doc:`smd/tri_surface ` **Default:** none diff --git a/doc/src/fix_spring.rst b/doc/src/fix_spring.rst index db8608ea99..b337a4e048 100644 --- a/doc/src/fix_spring.rst +++ b/doc/src/fix_spring.rst @@ -97,7 +97,7 @@ last example holds the ion a distance 5 away from the pore axis spring connecting two groups or a group and the tether point can cross a periodic boundary and its length be calculated correctly. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_spring_chunk.rst b/doc/src/fix_spring_chunk.rst index 01def4cabc..d839d9158c 100644 --- a/doc/src/fix_spring_chunk.rst +++ b/doc/src/fix_spring_chunk.rst @@ -48,7 +48,7 @@ chunk. Note that *K* thus represents the spring constant for the total force on each chunk of atoms, not for a spring applied to each atom. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_spring_rg.rst b/doc/src/fix_spring_rg.rst index 1d552c4d33..962e780f7f 100644 --- a/doc/src/fix_spring_rg.rst +++ b/doc/src/fix_spring_rg.rst @@ -57,7 +57,7 @@ for the aggregate force on the group of atoms, not a per-atom force. If :math:`R_{G0}` is specified as NULL, then the RG of the group is computed at the time the fix is specified, and that value is used as the target. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_spring_self.rst b/doc/src/fix_spring_self.rst index 8f8d2fb97e..38da0013b1 100644 --- a/doc/src/fix_spring_self.rst +++ b/doc/src/fix_spring_self.rst @@ -41,7 +41,7 @@ directions, but it can be limited to the xy-, xz-, yz-plane and the x-, y-, or z-direction, thus restraining the atoms to a line or a plane, respectively. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the original coordinates of tethered atoms to :doc:`binary restart files `, so that the spring effect will be the same in a restarted simulation. See the diff --git a/doc/src/fix_srd.rst b/doc/src/fix_srd.rst index 96ddcb6329..70f07cc0bf 100644 --- a/doc/src/fix_srd.rst +++ b/doc/src/fix_srd.rst @@ -334,13 +334,13 @@ interactions is specified, the :doc:`pair_coeff ` command should be used to turn off big/SRD interactions, e.g. by setting their epsilon or cutoff length to 0.0. -The "delete\_atoms overlap" command may be useful in setting up an SRD +The "delete_atoms overlap" command may be useful in setting up an SRD simulation to insure there are no initial overlaps between big and SRD particles. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. diff --git a/doc/src/fix_store_force.rst b/doc/src/fix_store_force.rst index e99d5db964..d9ccd162fd 100644 --- a/doc/src/fix_store_force.rst +++ b/doc/src/fix_store_force.rst @@ -49,7 +49,7 @@ potentially modify the force on each atom. Examples of such fixes are to include certain constraints (e.g. fix shake) in the stored force, then it could be specified after some fixes and before others. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. @@ -69,6 +69,6 @@ Restrictions Related commands """""""""""""""" -:doc:`fix store\_state ` +:doc:`fix store_state ` **Default:** none diff --git a/doc/src/fix_store_state.rst b/doc/src/fix_store_state.rst index 2e2049bbdd..b8fee6b5ea 100644 --- a/doc/src/fix_store_state.rst +++ b/doc/src/fix_store_state.rst @@ -102,7 +102,7 @@ The requested values are stored in a per-atom vector or array as discussed below. Zeroes are stored for atoms not in the specified group. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the per-atom values it stores to :doc:`binary restart files `, so that the values can be restored when a simulation is restarted. See the :doc:`read_restart ` diff --git a/doc/src/fix_temp_berendsen.rst b/doc/src/fix_temp_berendsen.rst index 33eee84bce..4913efdf53 100644 --- a/doc/src/fix_temp_berendsen.rst +++ b/doc/src/fix_temp_berendsen.rst @@ -50,7 +50,7 @@ of (roughly) 100 time units (tau or fmsec or psec - see the *Tstart* can be specified as an equal-style :doc:`variable `. In this case, the *Tstop* setting is ignored. If the value is a -variable, it should be specified as v\_name, where name is the variable +variable, it should be specified as v_name, where name is the variable name. In this case, the variable will be evaluated each timestep, and its value used to determine the target temperature. @@ -93,12 +93,12 @@ that the ID of the new compute is the fix-ID + underscore + "temp", and the group for the new compute is the same as the fix group. Note that this is NOT the compute used by thermodynamic output (see -the :doc:`thermo_style ` command) with ID = *thermo\_temp*. +the :doc:`thermo_style ` command) with ID = *thermo_temp*. This means you can change the attributes of this fix's temperature (e.g. its degrees-of-freedom) via the :doc:`compute_modify ` command or print this temperature during thermodynamic output via the :doc:`thermo_style custom ` command using the appropriate compute-ID. -It also means that changing attributes of *thermo\_temp* will have no +It also means that changing attributes of *thermo_temp* will have no effect on this fix. Like other fixes that perform thermostatting, this fix can be used @@ -117,7 +117,7 @@ thermal degrees of freedom, and the bias is added back in. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_temp_csvr.rst b/doc/src/fix_temp_csvr.rst index 7a528bcfa2..cd4e5dc88f 100644 --- a/doc/src/fix_temp_csvr.rst +++ b/doc/src/fix_temp_csvr.rst @@ -64,7 +64,7 @@ of (roughly) 100 time units (tau or fmsec or psec - see the *Tstart* can be specified as an equal-style :doc:`variable `. In this case, the *Tstop* setting is ignored. If the value is a -variable, it should be specified as v\_name, where name is the variable +variable, it should be specified as v_name, where name is the variable name. In this case, the variable will be evaluated each timestep, and its value used to determine the target temperature. @@ -101,12 +101,12 @@ that the ID of the new compute is the fix-ID + underscore + "temp", and the group for the new compute is the same as the fix group. Note that this is NOT the compute used by thermodynamic output (see -the :doc:`thermo_style ` command) with ID = *thermo\_temp*. +the :doc:`thermo_style ` command) with ID = *thermo_temp*. This means you can change the attributes of this fix's temperature (e.g. its degrees-of-freedom) via the :doc:`compute_modify ` command or print this temperature during thermodynamic output via the :doc:`thermo_style custom ` command using the appropriate compute-ID. -It also means that changing attributes of *thermo\_temp* will have no +It also means that changing attributes of *thermo_temp* will have no effect on this fix. Like other fixes that perform thermostatting, these fixes can be used @@ -125,7 +125,7 @@ thermal degrees of freedom, and the bias is added back in. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about these fixes are written to :doc:`binary restart files `. diff --git a/doc/src/fix_temp_rescale.rst b/doc/src/fix_temp_rescale.rst index d6a433ae42..d23006c52b 100644 --- a/doc/src/fix_temp_rescale.rst +++ b/doc/src/fix_temp_rescale.rst @@ -56,7 +56,7 @@ beginning and end of the run. *Tstart* can be specified as an equal-style :doc:`variable `. In this case, the *Tstop* setting is ignored. If the value is a -variable, it should be specified as v\_name, where name is the variable +variable, it should be specified as v_name, where name is the variable name. In this case, the variable will be evaluated each timestep, and its value used to determine the target temperature. @@ -100,12 +100,12 @@ ID of the new compute is the fix-ID + underscore + "temp", and the group for the new compute is the same as the fix group. Note that this is NOT the compute used by thermodynamic output (see -the :doc:`thermo_style ` command) with ID = *thermo\_temp*. +the :doc:`thermo_style ` command) with ID = *thermo_temp*. This means you can change the attributes of this fix's temperature (e.g. its degrees-of-freedom) via the :doc:`compute_modify ` command or print this temperature during thermodynamic output via the :doc:`thermo_style custom ` command using the appropriate compute-ID. -It also means that changing attributes of *thermo\_temp* will have no +It also means that changing attributes of *thermo_temp* will have no effect on this fix. Like other fixes that perform thermostatting, this fix can be used @@ -124,7 +124,7 @@ thermal degrees of freedom, and the bias is added back in. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_temp_rescale_eff.rst b/doc/src/fix_temp_rescale_eff.rst index 679913ab2d..5173e6addc 100644 --- a/doc/src/fix_temp_rescale_eff.rst +++ b/doc/src/fix_temp_rescale_eff.rst @@ -35,7 +35,7 @@ The operation of this fix is exactly like that described by the :doc:`fix temp/r is also applied to the radial electron velocity for electron particles. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_tfmc.rst b/doc/src/fix_tfmc.rst index 952850be59..fe290dfc0c 100644 --- a/doc/src/fix_tfmc.rst +++ b/doc/src/fix_tfmc.rst @@ -116,7 +116,7 @@ rotational component of the tfMC displacements after every iteration. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_thermal_conductivity.rst b/doc/src/fix_thermal_conductivity.rst index 133a091b8a..6b8b670694 100644 --- a/doc/src/fix_thermal_conductivity.rst +++ b/doc/src/fix_thermal_conductivity.rst @@ -108,7 +108,7 @@ fluid, in appropriate units. See the :ref:`Muller-Plathe paper accurately infer a thermal conductivity and should try increasing the Nevery parameter. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. diff --git a/doc/src/fix_ti_spring.rst b/doc/src/fix_ti_spring.rst index 0c764895c5..8bf5439e0d 100644 --- a/doc/src/fix_ti_spring.rst +++ b/doc/src/fix_ti_spring.rst @@ -13,8 +13,8 @@ Syntax * ID, group-ID are documented in :doc:`fix ` command * ti/spring = style name of this fix command * k = spring constant (force/distance units) -* t\_eq = number of steps for the equilibration procedure -* t\_s = number of steps for the switching procedure +* t_eq = number of steps for the equilibration procedure +* t_s = number of steps for the switching procedure * zero or more keyword/value pairs may be appended to args * keyword = *function* @@ -48,8 +48,8 @@ each atom is given by F = \left( 1-\lambda \right) F_{\text{solid}} + \lambda F_{\text{harm}} -where F\_solid is the force that acts on an atom due to an interatomic -potential (\ *e.g.* EAM potential), F\_harm is the force due to the +where F_solid is the force that acts on an atom due to an interatomic +potential (\ *e.g.* EAM potential), F_harm is the force due to the Einstein crystal harmonic spring, and lambda is the coupling parameter of the thermodynamic integration. An Einstein crystal is a solid where each atom is attached to its equilibrium position by a harmonic spring @@ -58,15 +58,15 @@ independently to each atom in the group defined by the fix to tether it to its initial position. The initial position of each atom is its position at the time the fix command was issued. -The fix acts as follows: during the first *t\_eq* steps after the fix +The fix acts as follows: during the first *t_eq* steps after the fix is defined the value of lambda is zero. This is the period to equilibrate the system in the lambda = 0 state. After this the value of lambda changes dynamically during the simulation from 0 to 1 according to the function defined using the keyword *function* (described below), this switching from lambda from 0 to 1 is done in -*t\_s* steps. Then comes the second equilibration period of *t\_eq* to +*t_s* steps. Then comes the second equilibration period of *t_eq* to equilibrate the system in the lambda = 1 state. After that, the -switching back to the lambda = 0 state is made using *t\_s* timesteps +switching back to the lambda = 0 state is made using *t_s* timesteps and following the same switching function. After this period the value of lambda is kept equal to zero and the fix has no other effect on the dynamics of the system. @@ -88,7 +88,7 @@ time: \lambda(\tau) = \tau -where tau is the scaled time variable *t/t\_s*. The option *2* performs +where tau is the scaled time variable *t/t_s*. The option *2* performs the lambda switching at a rate defined by the following switching function @@ -116,7 +116,7 @@ increase in computational resources cost. option will *NOT* solve this problem). The Langevin thermostat (:doc:`fix langevin `) correctly thermostats the system and we advise its usage with ti/spring command. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the original coordinates of tethered atoms to :doc:`binary restart files `, so that the spring effect will be the same in a restarted simulation. See the :doc:`read restart ` command for info on how to re-specify a fix diff --git a/doc/src/fix_tmd.rst b/doc/src/fix_tmd.rst index 4e9b410490..bbc99d3ba2 100644 --- a/doc/src/fix_tmd.rst +++ b/doc/src/fix_tmd.rst @@ -12,7 +12,7 @@ Syntax * ID, group-ID are documented in :doc:`fix ` command * tmd = style name of this fix command -* rho\_final = desired value of rho at the end of the run (distance units) +* rho_final = desired value of rho at the end of the run (distance units) * file1 = filename to read target structure from * N = dump TMD statistics every this many timesteps, 0 = no dump * file2 = filename to write TMD statistics to (only needed if N > 0) @@ -32,12 +32,12 @@ Perform targeted molecular dynamics (TMD) on a group of atoms. A holonomic constraint is used to force the atoms to move towards (or away from) the target configuration. The parameter "rho" is monotonically decreased (or increased) from its initial value to -rho\_final at the end of the run. +rho_final at the end of the run. Rho has distance units and is a measure of the root-mean-squared distance (RMSD) between the current configuration of the atoms in the group and the target coordinates listed in file1. Thus a value of -rho\_final = 0.0 means move the atoms all the way to the final +rho_final = 0.0 means move the atoms all the way to the final structure during the course of the run. The target file1 can be ASCII text or a gzipped text file (detected by @@ -78,10 +78,10 @@ The atoms in the fix tmd group should be integrated (via a fix nve, nvt, npt) along with other atoms in the system. Restarts can be used with a fix tmd command. For example, imagine a -10000 timestep run with a rho\_initial = 11 and a rho\_final = 1. If a +10000 timestep run with a rho_initial = 11 and a rho_final = 1. If a restart file was written after 2000 time steps, then the configuration in the file would have a rho value of 9. A new 8000 time step run -could be performed with the same rho\_final = 1 to complete the +could be performed with the same rho_final = 1 to complete the conformational change at the same transition rate. Note that for restarted runs, the name of the TMD statistics file should be changed to prevent it being overwritten. @@ -89,7 +89,7 @@ to prevent it being overwritten. For more information about TMD, see :ref:`(Schlitter1) ` and :ref:`(Schlitter2) `. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored @@ -114,7 +114,7 @@ are not multiple competing holonomic constraints applied to the same atoms. To read gzipped target files, you must compile LAMMPS with the --DLAMMPS\_GZIP option. See the :doc:`Build settings ` +-DLAMMPS_GZIP option. See the :doc:`Build settings ` doc page for details. **Related commands:** none diff --git a/doc/src/fix_ttm.rst b/doc/src/fix_ttm.rst index e70243231e..ae759c1b13 100644 --- a/doc/src/fix_ttm.rst +++ b/doc/src/fix_ttm.rst @@ -15,7 +15,7 @@ Syntax fix ID group-ID ttm/mod seed init_file Nx Ny Nz T_infile N T_outfile * ID, group-ID are documented in :doc:`fix ` command -* style = *ttm* or *ttm\_mod* +* style = *ttm* or *ttm_mod* * seed = random number seed to use for white noise (positive integer) * remaining arguments for fix ttm: @@ -93,11 +93,11 @@ reservoir, whereas the heat reservoir for fix TTM is finite and represents the local electrons. Third, the TTM fix allows users to specify not just one friction coefficient, but rather two independent friction coefficients: one for the electron-ion interactions -(*gamma\_p*), and one for electron stopping (*gamma\_s*). +(*gamma_p*), and one for electron stopping (*gamma_s*). -When the friction coefficient due to electron stopping, *gamma\_s*, is +When the friction coefficient due to electron stopping, *gamma_s*, is non-zero, electron stopping effects are included for atoms moving -faster than the electron stopping critical velocity, *v\_0*. For +faster than the electron stopping critical velocity, *v_0*. For further details about this algorithm, see :ref:`(Duffy) ` and :ref:`(Rutherford) `. @@ -111,11 +111,11 @@ transfer between the subsystems: \bigtriangledown (\kappa_e \bigtriangledown T_e) - g_p (T_e - T_a) + g_s T_a' -where C\_e is the specific heat, rho\_e is the density, kappa\_e is the +where C_e is the specific heat, rho_e is the density, kappa_e is the thermal conductivity, T is temperature, the "e" and "a" subscripts -represent electronic and atomic subsystems respectively, g\_p is the -coupling constant for the electron-ion interaction, and g\_s is the -electron stopping coupling parameter. C\_e, rho\_e, and kappa\_e are +represent electronic and atomic subsystems respectively, g_p is the +coupling constant for the electron-ion interaction, and g_s is the +electron stopping coupling parameter. C_e, rho_e, and kappa_e are specified as parameters to the fix. The other quantities are derived. The form of the heat diffusion equation used here is almost the same as that in equation 6 of :ref:`(Duffy) `, with the exception that the @@ -135,12 +135,12 @@ approach of :ref:`(Rutherford) ` where the atomic subsystem was embedded within a larger continuum representation of the electronic subsystem. -The initial electronic temperature input file, *T\_infile*, is a text +The initial electronic temperature input file, *T_infile*, is a text file LAMMPS reads in with no header and with four numeric columns (ix,iy,iz,Temp) and with a number of rows equal to the number of user-specified grid points (Nx by Ny by Nz). The ix,iy,iz are node indices from 0 to nxnodes-1, etc. For example, the initial electronic -temperatures on a 1 by 2 by 3 grid could be specified in a *T\_infile* +temperatures on a 1 by 2 by 3 grid could be specified in a *T_infile* as follows: .. parsed-literal:: @@ -157,7 +157,7 @@ where the electronic temperatures along the y=0 plane have been set to to 2.0. The order of lines in this file is no important. If all the nodal values are not specified, LAMMPS will generate an error. -The temperature output file, *T\_oufile*, is created and written by +The temperature output file, *T_oufile*, is created and written by this fix. Temperatures for both the electronic and atomic subsystems at every node and every N timesteps are output. If N is specified as zero, no output is generated, and no output filename is needed. The @@ -196,22 +196,22 @@ heat sources (e.g. laser heating in ablation simulations): \bigtriangledown (\kappa_e \bigtriangledown T_e) - g_p (T_e - T_a) + g_s T_a' + \theta (x-x_{surface})I_0 \exp(-x/l_{skin}) -where theta is the Heaviside step function, I\_0 is the (absorbed) -laser pulse intensity for ablation simulations, l\_skin is the depth +where theta is the Heaviside step function, I_0 is the (absorbed) +laser pulse intensity for ablation simulations, l_skin is the depth of skin-layer, and all other designations have the same meaning as in the former equation. The duration of the pulse is set by the parameter -*tau* in the *init\_file*. +*tau* in the *init_file*. -Fix ttm/mod also allows users to specify the dependencies of C\_e and -kappa\_e on the electronic temperature. The specific heat is expressed +Fix ttm/mod also allows users to specify the dependencies of C_e and +kappa_e on the electronic temperature. The specific heat is expressed as .. math:: C_e = C_0 + (a_0 + a_1 X + a_2 X^2 + a_3 X^3 + a_4 X^4) \exp (-(AX)^2) -where *X* = T\_e/1000, and the thermal conductivity is defined as -kappa\_e = D\_e\*rho\_e\*C\_e, where D\_e is the thermal diffusion +where *X* = T_e/1000, and the thermal conductivity is defined as +kappa_e = D_e\*rho_e\*C_e, where D_e is the thermal diffusion coefficient. Electronic pressure effects are included in the TTM model to account @@ -223,23 +223,23 @@ acting on an ion is: {\vec F}_i = - \partial U / \partial {\vec r}_i + {\vec F}_{langevin} - \nabla P_e/n_{ion} -where F\_langevin is a force from Langevin thermostat simulating -electron-phonon coupling, and nabla P\_e/n\_ion is the electron blast +where F_langevin is a force from Langevin thermostat simulating +electron-phonon coupling, and nabla P_e/n_ion is the electron blast force. -The electronic pressure is taken to be P\_e = B\*rho\_e\*C\_e\*T\_e +The electronic pressure is taken to be P_e = B\*rho_e\*C_e\*T_e The current fix ttm/mod implementation allows TTM simulations with a vacuum. The vacuum region is defined as the grid cells with zero electronic temperature. The numerical scheme does not allow energy exchange with such cells. Since the material can expand to previously unoccupied region in some simulations, the vacuum border can be -allowed to move. It is controlled by the *surface\_movement* parameter -in the *init\_file*. If it is set to 1, then "vacuum" cells can be -changed to "electron-filled" cells with the temperature *T\_e_min* if +allowed to move. It is controlled by the *surface_movement* parameter +in the *init_file*. If it is set to 1, then "vacuum" cells can be +changed to "electron-filled" cells with the temperature *T_e_min* if atoms move into them (currently only implemented for the case of 1-dimensional motion of flat surface normal to the X axis). The -initial borders of vacuum can be set in the *init\_file* via *lsurface* +initial borders of vacuum can be set in the *init_file* via *lsurface* and *rsurface* parameters. In this case, electronic pressure gradient is calculated as @@ -250,7 +250,7 @@ is calculated as where lambda is the electron mean free path (see :ref:`(Norman) `, :ref:`(Pisarev) `) -The fix ttm/mod parameter file *init\_file* has the following syntax/ +The fix ttm/mod parameter file *init_file* has the following syntax/ Every line with the odd number is considered as a comment and ignored. The lines with the even numbers are treated as follows: @@ -281,7 +281,7 @@ ignored. The lines with the even numbers are treated as follows: ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** These fixes write the state of the electronic subsystem and the energy exchange between the subsystems to :doc:`binary restart files `. See the :doc:`read_restart ` command diff --git a/doc/src/fix_tune_kspace.rst b/doc/src/fix_tune_kspace.rst index 1f201799cb..66a3fef024 100644 --- a/doc/src/fix_tune_kspace.rst +++ b/doc/src/fix_tune_kspace.rst @@ -83,7 +83,7 @@ Restrictions This fix is part of the KSPACE package. It is only enabled if LAMMPS was built with that package. See the :doc:`Build package ` doc page for more info. -Do not set "neigh\_modify once yes" or else this fix will never be +Do not set "neigh_modify once yes" or else this fix will never be called. Reneighboring is required. This fix is not compatible with a hybrid pair style, long-range dispersion, diff --git a/doc/src/fix_vector.rst b/doc/src/fix_vector.rst index 4a6d415a22..8cf6d900f4 100644 --- a/doc/src/fix_vector.rst +++ b/doc/src/fix_vector.rst @@ -14,7 +14,7 @@ Syntax * vector = style name of this fix command * Nevery = use input values every this many timesteps * one or more input values can be listed -* value = c\_ID, c\_ID[N], f\_ID, f\_ID[N], v\_name +* value = c_ID, c_ID[N], f_ID, f_ID[N], v_name .. parsed-literal:: @@ -86,7 +86,7 @@ sufficient size. ---------- -If a value begins with "c\_", a compute ID must follow which has been +If a value begins with "c_", a compute ID must follow which has been previously defined in the input script. If no bracketed term is appended, the global scalar calculated by the compute is used. If a bracketed term is appended, the Ith element of the global vector @@ -100,7 +100,7 @@ or :doc:`fix temp/rescale `. See the doc pages for these commands which give the IDs of these computes. Users can also write code for their own compute styles and :doc:`add them to LAMMPS `. -If a value begins with "f\_", a fix ID must follow which has been +If a value begins with "f_", a fix ID must follow which has been previously defined in the input script. If no bracketed term is appended, the global scalar calculated by the fix is used. If a bracketed term is appended, the Ith element of the global vector @@ -110,7 +110,7 @@ Note that some fixes only produce their values on certain timesteps, which must be compatible with *Nevery*\ , else an error will result. Users can also write code for their own fix styles and :doc:`add them to LAMMPS `. -If a value begins with "v\_", a variable name must follow which has +If a value begins with "v_", a variable name must follow which has been previously defined in the input script. An equal-style or vector-style variable can be referenced; the latter requires a bracketed term to specify the Ith element of the vector calculated by @@ -123,7 +123,7 @@ quantities to be stored by fix vector. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. diff --git a/doc/src/fix_viscosity.rst b/doc/src/fix_viscosity.rst index b3c1b92bd3..e31cbf2e45 100644 --- a/doc/src/fix_viscosity.rst +++ b/doc/src/fix_viscosity.rst @@ -113,7 +113,7 @@ system using a :doc:`PPPM solver ` since PPPM does not currently support non-orthogonal boxes. Using fix viscosity keeps the box orthogonal; thus it does not suffer from this limitation. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. diff --git a/doc/src/fix_viscous.rst b/doc/src/fix_viscous.rst index 5a6d966822..88d619e56c 100644 --- a/doc/src/fix_viscous.rst +++ b/doc/src/fix_viscous.rst @@ -84,7 +84,7 @@ more easily be used as a thermostat. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are diff --git a/doc/src/fix_wall.rst b/doc/src/fix_wall.rst index acd97d83c6..a56bca3c45 100644 --- a/doc/src/fix_wall.rst +++ b/doc/src/fix_wall.rst @@ -165,7 +165,7 @@ EDGE is used, then the corresponding boundary of the current simulation box is used. If a numeric constant is specified then the wall is placed at that position in the appropriate dimension (x, y, or z). In both the EDGE and constant cases, the wall will never move. -If the wall position is a variable, it should be specified as v\_name, +If the wall position is a variable, it should be specified as v_name, where name is an :doc:`equal-style variable ` name. In this case the variable is evaluated each timestep and the result becomes the current position of the reflecting wall. Equal-style variables @@ -222,7 +222,7 @@ inverse distance units, and :math:`r_0` distance units. For any wall, the :math:`\epsilon` and/or :math:`\sigma` and/or :math:`\alpha` parameter can be specified as an :doc:`equal-style variable `, in which case it should be -specified as v\_name, where name is the variable name. As with a +specified as v_name, where name is the variable name. As with a variable wall position, the variable is evaluated each timestep and the result becomes the current epsilon or sigma of the wall. Equal-style variables can specify formulas with various mathematical @@ -323,7 +323,7 @@ perturbation on the particles: ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_wall_body_polygon.rst b/doc/src/fix_wall_body_polygon.rst index 0371710604..a93d71369f 100644 --- a/doc/src/fix_wall_body_polygon.rst +++ b/doc/src/fix_wall_body_polygon.rst @@ -12,9 +12,9 @@ Syntax * ID, group-ID are documented in :doc:`fix ` command * wall/body/polygon = style name of this fix command -* k\_n = normal repulsion strength (force/distance or pressure units) -* c\_n = normal damping coefficient (force/distance or pressure units) -* c\_t = tangential damping coefficient (force/distance or pressure units) +* k_n = normal repulsion strength (force/distance or pressure units) +* c_n = normal damping coefficient (force/distance or pressure units) +* c_t = tangential damping coefficient (force/distance or pressure units) * wallstyle = *xplane* or *yplane* or *zplane* or *zcylinder* * args = list of arguments for a particular style @@ -54,7 +54,7 @@ particles themselves, which is similar to a Hookean potential. See the :doc:`Howto body ` doc page for more details on using body particles. -The parameters *k\_n*, *c\_n*, *c\_t* have the same meaning and units as +The parameters *k_n*, *c_n*, *c_t* have the same meaning and units as those specified with the :doc:`pair_style body/rounded/polygon ` command. The *wallstyle* can be planar or cylindrical. The 2 planar options @@ -87,7 +87,7 @@ the *amplitude*\ , *omega* is 2 PI / *period*\ , and *delta* is the time elapsed since the fix was specified. The velocity of the wall is set to the derivative of this expression. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored by this fix for diff --git a/doc/src/fix_wall_body_polyhedron.rst b/doc/src/fix_wall_body_polyhedron.rst index a36d8a5fca..4b01234f0f 100644 --- a/doc/src/fix_wall_body_polyhedron.rst +++ b/doc/src/fix_wall_body_polyhedron.rst @@ -12,9 +12,9 @@ Syntax * ID, group-ID are documented in :doc:`fix ` command * wall/body/polyhedron = style name of this fix command -* k\_n = normal repulsion strength (force/distance units or pressure units - see discussion below) -* c\_n = normal damping coefficient (force/distance units or pressure units - see discussion below) -* c\_t = tangential damping coefficient (force/distance units or pressure units - see discussion below) +* k_n = normal repulsion strength (force/distance units or pressure units - see discussion below) +* c_n = normal damping coefficient (force/distance units or pressure units - see discussion below) +* c_t = tangential damping coefficient (force/distance units or pressure units - see discussion below) * wallstyle = *xplane* or *yplane* or *zplane* or *zcylinder* * args = list of arguments for a particular style @@ -54,7 +54,7 @@ particles themselves, which is similar to a Hookean potential. See the :doc:`Howto body ` doc page for more details on using body particles. -The parameters *k\_n*, *c\_n*, *c\_t* have the same meaning and units as +The parameters *k_n*, *c_n*, *c_t* have the same meaning and units as those specified with the :doc:`pair_style body/rounded/polyhedron ` command. The *wallstyle* can be planar or cylindrical. The 3 planar options @@ -86,7 +86,7 @@ the *amplitude*\ , *omega* is 2 PI / *period*\ , and *delta* is the time elapsed since the fix was specified. The velocity of the wall is set to the derivative of this expression. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored by this fix for diff --git a/doc/src/fix_wall_gran.rst b/doc/src/fix_wall_gran.rst index 98cc251fcc..daf3152c34 100644 --- a/doc/src/fix_wall_gran.rst +++ b/doc/src/fix_wall_gran.rst @@ -18,7 +18,7 @@ Syntax possible choices: hooke, hooke/history, hertz/history, granular -* fstyle\_params = parameters associated with force interaction style +* fstyle_params = parameters associated with force interaction style .. parsed-literal:: @@ -82,25 +82,25 @@ The nature of the wall/particle interactions are determined by the :doc:`pair_style granular ` commands. Currently the options are *hooke*\ , *hooke/history*\ , or *hertz/history* for the former, and *granular* with all the possible options of the associated -*pair\_coeff* command for the latter. The equation for the force +*pair_coeff* command for the latter. The equation for the force between the wall and particles touching it is the same as the corresponding equation on the :doc:`pair_style gran/\* ` and :doc:`pair_style granular ` doc pages, in the limit of one of the two particles going to infinite radius and mass (flat wall). -Specifically, delta = radius - r = overlap of particle with wall, m\_eff +Specifically, delta = radius - r = overlap of particle with wall, m_eff = mass of particle, and the effective radius of contact = RiRj/Ri+Rj is set to the radius of the particle. -The parameters *Kn*\ , *Kt*\ , *gamma\_n*, *gamma\_t*, *xmu* and *dampflag* +The parameters *Kn*\ , *Kt*\ , *gamma_n*, *gamma_t*, *xmu* and *dampflag* have the same meaning and units as those specified with the :doc:`pair_style gran/\* ` commands. This means a NULL can be -used for either *Kt* or *gamma\_t* as described on that page. If a +used for either *Kt* or *gamma_t* as described on that page. If a NULL is used for *Kt*\ , then a default value is used where *Kt* = 2/7 -*Kn*\ . If a NULL is used for *gamma\_t*, then a default value is used -where *gamma\_t* = 1/2 *gamma\_n*. +*Kn*\ . If a NULL is used for *gamma_t*, then a default value is used +where *gamma_t* = 1/2 *gamma_n*. All the model choices for cohesion, tangential friction, rolling -friction and twisting friction supported by the :doc:`pair_style granular ` through its *pair\_coeff* command are also +friction and twisting friction supported by the :doc:`pair_style granular ` through its *pair_coeff* command are also supported for walls. These are discussed in greater detail on the doc page for :doc:`pair_style granular `. @@ -122,10 +122,10 @@ material. appropriately in the current code to reproduce the results of a previous Hertzian monodisperse calculation. For example, for the common case of a monodisperse system with particles of diameter 1, Kn, - Kt, gamma\_n, and gamma\_s should be set sqrt(2.0) larger than they were + Kt, gamma_n, and gamma_s should be set sqrt(2.0) larger than they were previously. -The effective mass *m\_eff* in the formulas listed on the :doc:`pair_style granular ` doc page is the mass of the particle for +The effective mass *m_eff* in the formulas listed on the :doc:`pair_style granular ` doc page is the mass of the particle for particle/wall interactions (mass of wall is infinite). If the particle is part of a rigid body, its mass is replaced by the mass of the rigid body in those formulas. This is determined by searching for @@ -171,7 +171,7 @@ the clockwise direction for *vshear* > 0 or counter-clockwise for *vshear* < 0. In this case, *vshear* is the tangential velocity of the wall at whatever *radius* has been defined. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** This fix writes the shear friction state of atoms interacting with the wall to :doc:`binary restart files `, so that a simulation can diff --git a/doc/src/fix_wall_gran_region.rst b/doc/src/fix_wall_gran_region.rst index 8144769270..620baa0942 100644 --- a/doc/src/fix_wall_gran_region.rst +++ b/doc/src/fix_wall_gran_region.rst @@ -18,7 +18,7 @@ Syntax possible choices: hooke, hooke/history, hertz/history, granular -* fstyle\_params = parameters associated with force interaction style +* fstyle_params = parameters associated with force interaction style .. parsed-literal:: @@ -153,7 +153,7 @@ The nature of the wall/particle interactions are determined by the :doc:`pair_style granular ` commands. Currently the options are *hooke*\ , *hooke/history*\ , or *hertz/history* for the former, and *granular* with all the possible options of the associated -*pair\_coeff* command for the latter. The equation for the force +*pair_coeff* command for the latter. The equation for the force between the wall and particles touching it is the same as the corresponding equation on the :doc:`pair_style gran/\* ` and :doc:`pair_style granular ` doc pages, but the effective @@ -161,24 +161,24 @@ radius is calculated using the radius of the particle and the radius of curvature of the wall at the contact point. Specifically, delta = radius - r = overlap of particle with wall, -m\_eff = mass of particle, and RiRj/Ri+Rj is the effective radius, with +m_eff = mass of particle, and RiRj/Ri+Rj is the effective radius, with Rj replaced by the radius of curvature of the wall at the contact point. The radius of curvature can be negative for a concave wall section, e.g. the interior of cylinder. For a flat wall, delta = -radius - r = overlap of particle with wall, m\_eff = mass of particle, +radius - r = overlap of particle with wall, m_eff = mass of particle, and the effective radius of contact is just the radius of the particle. -The parameters *Kn*\ , *Kt*\ , *gamma\_n*, *gamma\_t*, *xmu* and *dampflag* +The parameters *Kn*\ , *Kt*\ , *gamma_n*, *gamma_t*, *xmu* and *dampflag* have the same meaning and units as those specified with the :doc:`pair_style gran/\* ` commands. This means a NULL can be -used for either *Kt* or *gamma\_t* as described on that page. If a +used for either *Kt* or *gamma_t* as described on that page. If a NULL is used for *Kt*\ , then a default value is used where *Kt* = 2/7 -*Kn*\ . If a NULL is used for *gamma\_t*, then a default value is used -where *gamma\_t* = 1/2 *gamma\_n*. +*Kn*\ . If a NULL is used for *gamma_t*, then a default value is used +where *gamma_t* = 1/2 *gamma_n*. All the model choices for cohesion, tangential friction, rolling -friction and twisting friction supported by the :doc:`pair_style granular ` through its *pair\_coeff* command are also +friction and twisting friction supported by the :doc:`pair_style granular ` through its *pair_coeff* command are also supported for walls. These are discussed in greater detail on the doc page for :doc:`pair_style granular `. @@ -187,7 +187,7 @@ values for the 6 wall/particle coefficients than for particle/particle interactions. E.g. if you wish to model the wall as a different material. -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** Similar to :doc:`fix wall/gran ` command, this fix writes the shear friction state of atoms interacting with the wall to :doc:`binary restart files `, so that a simulation can continue diff --git a/doc/src/fix_wall_piston.rst b/doc/src/fix_wall_piston.rst index fe12bbc13c..626634ec83 100644 --- a/doc/src/fix_wall_piston.rst +++ b/doc/src/fix_wall_piston.rst @@ -90,7 +90,7 @@ define the lattice spacings. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. No global or per-atom quantities are stored diff --git a/doc/src/fix_wall_reflect.rst b/doc/src/fix_wall_reflect.rst index 76591bebf0..3960105ab9 100644 --- a/doc/src/fix_wall_reflect.rst +++ b/doc/src/fix_wall_reflect.rst @@ -74,7 +74,7 @@ EDGE is used, then the corresponding boundary of the current simulation box is used. If a numeric constant is specified then the wall is placed at that position in the appropriate dimension (x, y, or z). In both the EDGE and constant cases, the wall will never move. -If the wall position is a variable, it should be specified as v\_name, +If the wall position is a variable, it should be specified as v_name, where name is an :doc:`equal-style variable ` name. In this case the variable is evaluated each timestep and the result becomes the current position of the reflecting wall. Equal-style variables @@ -161,7 +161,7 @@ instructions on how to use the accelerated styles effectively. ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are diff --git a/doc/src/fix_wall_region.rst b/doc/src/fix_wall_region.rst index 9581966b61..b3f4733c56 100644 --- a/doc/src/fix_wall_region.rst +++ b/doc/src/fix_wall_region.rst @@ -186,10 +186,10 @@ surface no longer interact. The cutoff is always the last argument. The energy of the wall potential is shifted so that the wall-particle interaction energy is 0.0 at the cutoff distance. -For a full description of these wall styles, see fix\_style +For a full description of these wall styles, see fix_style :doc:`wall ` -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. diff --git a/doc/src/fix_wall_srd.rst b/doc/src/fix_wall_srd.rst index fbcdca3035..5df7345a4d 100644 --- a/doc/src/fix_wall_srd.rst +++ b/doc/src/fix_wall_srd.rst @@ -84,7 +84,7 @@ EDGE is used, then the corresponding boundary of the current simulation box is used. If a numeric constant is specified then the wall is placed at that position in the appropriate dimension (x, y, or z). In both the EDGE and constant cases, the wall will never move. -If the wall position is a variable, it should be specified as v\_name, +If the wall position is a variable, it should be specified as v_name, where name is an :doc:`equal-style variable ` name. In this case the variable is evaluated each timestep and the result becomes the current position of the reflecting wall. Equal-style variables @@ -177,7 +177,7 @@ perturbation on the particles: ---------- -**Restart, fix\_modify, output, run start/stop, minimize info:** +**Restart, fix_modify, output, run start/stop, minimize info:** No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options are relevant to this fix. diff --git a/doc/src/improper_coeff.rst b/doc/src/improper_coeff.rst index 6b0ab9ab52..3d2878c517 100644 --- a/doc/src/improper_coeff.rst +++ b/doc/src/improper_coeff.rst @@ -40,7 +40,7 @@ to N. A leading asterisk means all types from 1 to n (inclusive). A trailing asterisk means all types from n to N (inclusive). A middle asterisk means all types from m to n (inclusive). -Note that using an improper\_coeff command can override a previous +Note that using an improper_coeff command can override a previous setting for the same improper type. For example, these commands set the coeffs for all improper types, then overwrite the coeffs for just improper type 2: @@ -51,7 +51,7 @@ improper type 2: improper_coeff 2 50.0 0.0 A line in a data file that specifies improper coefficients uses the -exact same format as the arguments of the improper\_coeff command in an +exact same format as the arguments of the improper_coeff command in an input script, except that wild-card asterisks should not be used since coefficients for all N types must be listed in the file. For example, under the "Improper Coeffs" section of a data file, the line that @@ -74,7 +74,7 @@ in more compact form on the :ref:`Commands improper ` doc page. On either of those pages, click on the style to display the formula it computes and its coefficients as specified by the associated -improper\_coeff command. +improper_coeff command. ---------- diff --git a/doc/src/improper_distance.rst b/doc/src/improper_distance.rst index 933afe9160..d5f07f9971 100644 --- a/doc/src/improper_distance.rst +++ b/doc/src/improper_distance.rst @@ -42,8 +42,8 @@ linear dihedral. Normally, the bonds I-J, I-K, I-L would exist for an improper to be defined between the 4 atoms. The following coefficients must be defined for each improper type via -the improper\_coeff command as in the example above, or in the data -file or restart files read by the read\_data or read\_restart commands: +the improper_coeff command as in the example above, or in the data +file or restart files read by the read_data or read_restart commands: * :math:`K_2` (energy/distance\^2) * :math:`K_4` (energy/distance\^4) diff --git a/doc/src/improper_distharm.rst b/doc/src/improper_distharm.rst index b5b20e47d2..113941bee4 100644 --- a/doc/src/improper_distharm.rst +++ b/doc/src/improper_distharm.rst @@ -32,12 +32,12 @@ by the other three atoms. If the 4 atoms in an improper quadruplet (listed in the data file read by the :doc:`read_data ` command) are ordered I,J,K,L then the L-atom is assumed to be the central atom. Note that this is different from the convention used -in the improper\_style distance. The distance :math:`d` is oriented and can take +in the improper_style distance. The distance :math:`d` is oriented and can take on negative values. This may lead to unwanted behavior if :math:`d_0` is not equal to zero. The following coefficients must be defined for each improper type via -the improper\_coeff command as in the example above, or in the data -file or restart files read by the read\_data or read\_restart commands: +the improper_coeff command as in the example above, or in the data +file or restart files read by the read_data or read_restart commands: * :math:`K` (energy/distance\^2) * :math:`d_0` (distance) diff --git a/doc/src/improper_fourier.rst b/doc/src/improper_fourier.rst index a3500f11e6..7842e866f6 100644 --- a/doc/src/improper_fourier.rst +++ b/doc/src/improper_fourier.rst @@ -76,7 +76,7 @@ Restrictions """""""""""" This angle style can only be used if LAMMPS was built with the -USER\_MISC package. See the :doc:`Build package ` doc +USER_MISC package. See the :doc:`Build package ` doc page for more info. Related commands diff --git a/doc/src/improper_hybrid.rst b/doc/src/improper_hybrid.rst index 12464fee6a..9d5c4c696d 100644 --- a/doc/src/improper_hybrid.rst +++ b/doc/src/improper_hybrid.rst @@ -32,9 +32,9 @@ boundary (of improper type 2) could be computed with a *cvff* potential. The assignment of improper type to style is made via the :doc:`improper_coeff ` command or in the data file. -In the improper\_coeff command, the first coefficient sets the improper +In the improper_coeff command, the first coefficient sets the improper style and the remaining coefficients are those appropriate to that -style. In the example above, the 2 improper\_coeff commands would set +style. In the example above, the 2 improper_coeff commands would set impropers of improper type 1 to be computed with a *harmonic* potential with coefficients 120.0, 30 for :math:`K`, :math:`\chi_0`. Improper type 2 would be computed with a *cvff* potential with coefficients @@ -49,7 +49,7 @@ appropriate to that style. The AngleAngle coeffs for that improper type will then be ignored. An improper style of *none* can be specified as the 2nd argument to -the improper\_coeff command, if you desire to turn off certain improper +the improper_coeff command, if you desire to turn off certain improper types. ---------- @@ -64,7 +64,7 @@ for more info. Unlike other improper styles, the hybrid improper style does not store improper coefficient info for individual sub-styles in a :doc:`binary restart files `. Thus when restarting a simulation from a -restart file, you need to re-specify improper\_coeff commands. +restart file, you need to re-specify improper_coeff commands. Related commands """""""""""""""" diff --git a/doc/src/improper_ring.rst b/doc/src/improper_ring.rst index ff62812341..df4a73760e 100644 --- a/doc/src/improper_ring.rst +++ b/doc/src/improper_ring.rst @@ -39,8 +39,8 @@ equilibrium value. If the 4 atoms in an improper quadruplet (listed in the data file read by the :doc:`read_data ` command) are ordered i,j,k,l then -theta\_\ *ijl* is the angle between atoms i,j and l, theta\_\ *ijk* is the -angle between atoms i,j and k, theta\_\ *kjl* is the angle between atoms +theta_\ *ijl* is the angle between atoms i,j and l, theta_\ *ijk* is the +angle between atoms i,j and k, theta_\ *kjl* is the angle between atoms j,k, and l. The "ring" improper style implements the improper potential introduced diff --git a/doc/src/improper_sqdistharm.rst b/doc/src/improper_sqdistharm.rst index 9f4fde5b91..2f8723a68c 100644 --- a/doc/src/improper_sqdistharm.rst +++ b/doc/src/improper_sqdistharm.rst @@ -32,11 +32,11 @@ by the other three atoms. If the 4 atoms in an improper quadruplet (listed in the data file read by the :doc:`read_data ` command) are ordered I,J,K,L then the L-atom is assumed to be the central atom. Note that this is different from the convention used -in the improper\_style distance. +in the improper_style distance. The following coefficients must be defined for each improper type via -the improper\_coeff command as in the example above, or in the data -file or restart files read by the read\_data or read\_restart commands: +the improper_coeff command as in the example above, or in the data +file or restart files read by the read_data or read_restart commands: * :math:`K` (energy/distance\^4) * :math:`{d_0}^2` (distance\^2) diff --git a/doc/src/improper_style.rst b/doc/src/improper_style.rst index c4ccdb5a74..0667b8f5b9 100644 --- a/doc/src/improper_style.rst +++ b/doc/src/improper_style.rst @@ -41,11 +41,11 @@ a data or restart file or via the :doc:`improper_coeff ` command. All improper potentials store their coefficient data in binary restart -files which means improper\_style and +files which means improper_style and :doc:`improper_coeff ` commands do not need to be re-specified in an input script that restarts a simulation. See the :doc:`read_restart ` command for details on how to do -this. The one exception is that improper\_style *hybrid* only stores +this. The one exception is that improper_style *hybrid* only stores the list of sub-styles in the restart file; improper coefficients need to be re-specified. @@ -64,7 +64,7 @@ specified by the associated :doc:`improper_coeff ` command. Click on the style to display the formula it computes, any additional -arguments specified in the improper\_style command, and coefficients +arguments specified in the improper_style command, and coefficients specified by the associated :doc:`improper_coeff ` command. @@ -95,7 +95,7 @@ more of (g,i,k,o,t) to indicate which accelerated styles exist. Restrictions """""""""""" -Improper styles can only be set for atom\_style choices that allow +Improper styles can only be set for atom_style choices that allow impropers to be defined. Most improper styles are part of the MOLECULE package. They are only diff --git a/doc/src/improper_zero.rst b/doc/src/improper_zero.rst index 6d28566c66..354c0d486e 100644 --- a/doc/src/improper_zero.rst +++ b/doc/src/improper_zero.rst @@ -33,7 +33,7 @@ command. If no improper style is defined, this command cannot be used. The optional *nocoeff* flag allows to read data files with a ImproperCoeff -section for any improper style. Similarly, any improper\_coeff commands +section for any improper style. Similarly, any improper_coeff commands will only be checked for the improper type number and the rest ignored. Note that the :doc:`improper_coeff ` command must be diff --git a/doc/src/kim_commands.rst b/doc/src/kim_commands.rst index 5a4b5c56ae..c710ddfe5d 100644 --- a/doc/src/kim_commands.rst +++ b/doc/src/kim_commands.rst @@ -23,12 +23,12 @@ Syntax kim_param get param_name index_range variables formatarg kim_param set param_name index_range values -.. _formatarg\_options: +.. _formatarg_options: * model = name of the KIM interatomic model (the KIM ID for models archived in OpenKIM) -* user\_units = the LAMMPS :doc:`units ` style assumed in the LAMMPS input script -* unitarg = *unit\_conversion\_mode* (optional) -* typeargs = atom type to species mapping (one entry per atom type) or *fixed\_types* for models with a preset fixed mapping +* user_units = the LAMMPS :doc:`units ` style assumed in the LAMMPS input script +* unitarg = *unit_conversion_mode* (optional) +* typeargs = atom type to species mapping (one entry per atom type) or *fixed_types* for models with a preset fixed mapping * variable(s) = single name or list of names of (string style) LAMMPS variable(s) where a query result or parameter get result is stored. Variables that do not exist will be created by the command. * formatarg = *list, split, or explicit* (optional): @@ -43,10 +43,10 @@ Syntax *explicit* = returns the values separately in one more more variable names provided as arguments that precede *formatarg*\ . [default for *kim_param*] -* query\_function = name of the OpenKIM web API query function to be used +* query_function = name of the OpenKIM web API query function to be used * queryargs = a series of *keyword=value* pairs that represent the web query; supported keywords depend on the query function -* param\_name = name of a KIM portable model parameter -* index\_range = KIM portable model parameter index range (an integer for a single element, or pair of integers separated by a colon for a range of elements) +* param_name = name of a KIM portable model parameter +* index_range = KIM portable model parameter index range (an integer for a single element, or pair of integers separated by a colon for a range of elements) * values = new value(s) to replace the current value(s) of a KIM portable model parameter Examples @@ -68,14 +68,14 @@ Examples Description """"""""""" -The set of *kim\_commands* provide a high-level wrapper around the +The set of *kim_commands* provide a high-level wrapper around the `Open Knowledgebase of Interatomic Models (OpenKIM) `_ repository of interatomic models (IMs) (potentials and force fields), so that they can be used by LAMMPS scripts. These commands do not implement any computations directly, but rather generate LAMMPS input commands based on the information retrieved from the OpenKIM repository to initialize and activate OpenKIM IMs and query their predictions for use in the LAMMPS script. -All LAMMPS input commands generated and executed by *kim\_commands* are +All LAMMPS input commands generated and executed by *kim_commands* are echoed to the LAMMPS log file. Benefits of Using OpenKIM IMs @@ -99,18 +99,18 @@ Reproducibility Convenience ^^^^^^^^^^^ -* IMs in OpenKIM are distributed in binary form along with LAMMPS and can be used in a LAMMPS input script simply by providing their KIM ID in the *kim\_init* command documented on this page. -* The *kim\_query* web query tool provides the ability to use the predictions of IMs for supported material properties (computed via `KIM Tests `_) as part of a LAMMPS input script setup and analysis. +* IMs in OpenKIM are distributed in binary form along with LAMMPS and can be used in a LAMMPS input script simply by providing their KIM ID in the *kim_init* command documented on this page. +* The *kim_query* web query tool provides the ability to use the predictions of IMs for supported material properties (computed via `KIM Tests `_) as part of a LAMMPS input script setup and analysis. * Support is provided for unit conversion between the :doc:`unit style ` used in the LAMMPS input script and the units required by the OpenKIM IM. This makes it possible to use a single input script with IMs using different units without change and minimizes the likelihood of errors due to incompatible units. -.. _IM\_types: +.. _IM_types: Types of IMs in OpenKIM ----------------------- There are two types of IMs archived in OpenKIM: -.. _PM\_type: +.. _PM_type: 1. The first type is called a *KIM Portable Model* (PM). A KIM PM is an independent computer implementation of an IM written in one of the languages supported by KIM (C, C++, Fortran) that conforms to the KIM Application Programming Interface (`KIM API `_) Portable Model Interface (PMI) standard. A KIM PM will work seamlessly with any simulation code that supports the KIM API/PMI standard (including LAMMPS; see `complete list of supported codes `_). 2. The second type is called a *KIM Simulator Model* (SM). A KIM SM is an IM that is implemented natively within a simulation code (\ *simulator*\ ) that supports the KIM API Simulator Model Interface (SMI); in this case LAMMPS. A separate SM package is archived in OpenKIM for each parameterization of the IM, which includes all of the necessary parameter files, LAMMPS commands, and metadata (supported species, units, etc.) needed to run the IM in LAMMPS. @@ -127,7 +127,7 @@ and supported species, separated by two underscores from the KIM ID itself, which begins with an IM code (\ *MO* for a KIM Portable Model, and *SM* for a KIM Simulator Model) followed by a unique 12-digit code and a 3-digit version identifier. -By convention SM prefixes begin with *Sim\_* to readily identify them. +By convention SM prefixes begin with *Sim_* to readily identify them. .. parsed-literal:: @@ -169,57 +169,57 @@ Using OpenKIM IMs with LAMMPS ----------------------------- Two commands are employed when using OpenKIM IMs, one to select the -IM and perform necessary initialization (*kim\_init*), and the second +IM and perform necessary initialization (*kim_init*), and the second to set up the IM for use by executing any necessary LAMMPS commands -(*kim\_interactions*). Both are required. +(*kim_interactions*). Both are required. See the *examples/kim* directory for example input scripts that use KIM PMs and KIM SMs. -OpenKIM IM Initialization (*kim\_init*) +OpenKIM IM Initialization (*kim_init*) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The *kim\_init* mode command must be issued **before** +The *kim_init* mode command must be issued **before** the simulation box is created (normally at the top of the file). This command sets the OpenKIM IM that will be used and may issue additional commands changing LAMMPS default settings that are required for using the selected IM (such as :doc:`units ` or :doc:`atom_style `). If needed, those settings can be overridden, -however, typically a script containing a *kim\_init* command -would not include *units* and *atom\_style* commands. +however, typically a script containing a *kim_init* command +would not include *units* and *atom_style* commands. -The required arguments of *kim\_init* are the *model* name of the +The required arguments of *kim_init* are the *model* name of the IM to be used in the simulation (for an IM archived in OpenKIM this is its `extended KIM ID `_, and -the *user\_units*, which are the LAMMPS :doc:`units style ` used +the *user_units*, which are the LAMMPS :doc:`units style ` used in the input script. (Any dimensioned numerical values in the input script and values read in from files are expected to be in the -*user\_units* system.) +*user_units* system.) The selected IM can be either a :ref:`KIM PM or a KIM SM `. -For a KIM SM, the *kim\_init* command verifies that the SM is designed +For a KIM SM, the *kim_init* command verifies that the SM is designed to work with LAMMPS (and not another simulation code). In addition, the LAMMPS version used for defining the SM and the LAMMPS version being currently run are printed to help diagnose any incompatible changes to input script or command syntax between the two LAMMPS versions. -Based on the selected model *kim\_init* may modify the +Based on the selected model *kim_init* may modify the :doc:`atom_style `. Some SMs have requirements for this setting. If this is the case, then -*atom\_style* will be set to the required style. Otherwise, the value is left -unchanged (which in the absence of an *atom\_style* command in the input script -is the :doc:`default atom\_style value `). +*atom_style* will be set to the required style. Otherwise, the value is left +unchanged (which in the absence of an *atom_style* command in the input script +is the :doc:`default atom_style value `). -Regarding units, the *kim\_init* command behaves in different ways depending +Regarding units, the *kim_init* command behaves in different ways depending on whether or not *unit conversion mode* is activated as indicated by the optional *unitarg* argument. -If unit conversion mode is **not** active, then *user\_units* must +If unit conversion mode is **not** active, then *user_units* must either match the required units of the IM or the IM must be able to adjust its units to match. (The latter is only possible with some KIM PMs; SMs can never adjust their units.) If a match is possible, the LAMMPS :doc:`units ` command is called to set the units to -*user\_units*. If the match fails, the simulation is terminated with +*user_units*. If the match fails, the simulation is terminated with an error. Here is an example of a LAMMPS script to compute the cohesive energy @@ -240,13 +240,13 @@ potential for Al: variable Ec equal (pe/count(all))/${_u_energy} print "Cohesive Energy = ${EcJ} eV" -The above script will end with an error in the *kim\_init* line if the +The above script will end with an error in the *kim_init* line if the IM is changed to another potential for Al that does not work with *metal* -units. To address this *kim\_init* offers the *unit\_conversion\_mode* +units. To address this *kim_init* offers the *unit_conversion_mode* as shown below. -If unit conversion mode *is* active, then *kim\_init* calls the LAMMPS +If unit conversion mode *is* active, then *kim_init* calls the LAMMPS :doc:`units ` command to set the units to the IM's required or -preferred units. Conversion factors between the IM's units and the *user\_units* +preferred units. Conversion factors between the IM's units and the *user_units* are defined for all :doc:`physical quantities ` (mass, distance, etc.). (Note that converting to or from the "lj" unit style is not supported.) These factors are stored as :doc:`internal style variables ` with @@ -293,12 +293,12 @@ Joules regardless of the units of the IM. variable Ec_in_J equal (pe/count(all))/${_u_energy} print "Cohesive Energy = ${Ec_in_J} J" -Note the multiplication by ${\_u_distance} and ${\_u_mass} to convert -from SI units (specified in the *kim\_init* command) to whatever units the -IM uses (metal in this case), and the division by ${\_u_energy} +Note the multiplication by ${_u_distance} and ${_u_mass} to convert +from SI units (specified in the *kim_init* command) to whatever units the +IM uses (metal in this case), and the division by ${_u_energy} to convert from the IM's energy units to SI units (Joule). This script will work correctly for any IM for Al (KIM PM or SM) selected by the -*kim\_init* command. +*kim_init* command. Care must be taken to apply unit conversion to dimensional variables read in from a file. For example, if a configuration of atoms is read in from a @@ -324,17 +324,17 @@ be done to convert the box and all atomic positions to the correct units: all appropriate places in the input script. It is up to the user to do this correctly. -OpenKIM IM Execution (*kim\_interactions*) +OpenKIM IM Execution (*kim_interactions*) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The second and final step in using an OpenKIM IM is to execute the -*kim\_interactions* command. This command must be preceded by a *kim\_init* +*kim_interactions* command. This command must be preceded by a *kim_init* command and a command that defines the number of atom types *N* (such as :doc:`create_box `). -The *kim\_interactions* command has one argument *typeargs*\ . This argument +The *kim_interactions* command has one argument *typeargs*\ . This argument contains either a list of *N* chemical species, which defines a mapping between atom types in LAMMPS to the available species in the OpenKIM IM, or the -keyword *fixed\_types* for models that have a preset fixed mapping (i.e. +keyword *fixed_types* for models that have a preset fixed mapping (i.e. the mapping between LAMMPS atom types and chemical species is defined by the model and cannot be changed). In the latter case, the user must consult the model documentation to see how many atom types there are and how they @@ -342,7 +342,7 @@ map to the chemical species. For example, consider an OpenKIM IM that supports Si and C species. If the LAMMPS simulation has four atom types, where the first three are Si, -and the fourth is C, the following *kim\_interactions* command would be used: +and the fourth is C, the following *kim_interactions* command would be used: .. code-block:: LAMMPS @@ -354,11 +354,11 @@ Alternatively, for a model with a fixed mapping the command would be: kim_interactions fixed_types -The *kim\_interactions* command performs all the necessary steps to set up -the OpenKIM IM selected in the *kim\_init* command. The specific actions depend +The *kim_interactions* command performs all the necessary steps to set up +the OpenKIM IM selected in the *kim_init* command. The specific actions depend on whether the IM is a KIM PM or a KIM SM. For a KIM PM, a :doc:`pair_style kim ` command is executed followed by -the appropriate *pair\_coeff* command. For example, for the +the appropriate *pair_coeff* command. For example, for the Ercolessi and Adams (1994) KIM PM for Al set by the following commands: .. code-block:: LAMMPS @@ -369,7 +369,7 @@ Ercolessi and Adams (1994) KIM PM for Al set by the following commands: ... kim_interactions Al -the *kim\_interactions* command executes the following LAMMPS input commands: +the *kim_interactions* command executes the following LAMMPS input commands: .. code-block:: LAMMPS @@ -391,7 +391,7 @@ set by the following commands: ... kim_interactions C H N O -the *kim\_interactions* command executes the following LAMMPS input commands: +the *kim_interactions* command executes the following LAMMPS input commands: .. code-block:: LAMMPS @@ -399,7 +399,7 @@ the *kim\_interactions* command executes the following LAMMPS input commands: pair_coeff * * ffield.reax.rdx C H N O fix reaxqeq all qeq/reax 1 0.0 10.0 1.0e-6 param.qeq -Note that the files *lmp\_control*, *ffield.reax.rdx* and *param.qeq* +Note that the files *lmp_control*, *ffield.reax.rdx* and *param.qeq* are specific to the Strachan et al. (2003) ReaxFF parameterization and are archived as part of the SM package in OpenKIM. Note also that parameters like cutoff radii and charge tolerances, @@ -408,24 +408,24 @@ SM definition ensuring reproducibility. .. note:: - When using *kim\_init* and *kim\_interactions* to select + When using *kim_init* and *kim_interactions* to select and set up an OpenKIM IM, other LAMMPS commands - for the same functions (such as pair\_style, pair\_coeff, bond\_style, - bond\_coeff, fixes related to charge equilibration, etc.) should normally + for the same functions (such as pair_style, pair_coeff, bond_style, + bond_coeff, fixes related to charge equilibration, etc.) should normally not appear in the input script. -Using OpenKIM Web Queries in LAMMPS (*kim\_query*) +Using OpenKIM Web Queries in LAMMPS (*kim_query*) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The *kim\_query* command performs a web query to retrieve the predictions -of an IM set by *kim\_init* for material properties archived in +The *kim_query* command performs a web query to retrieve the predictions +of an IM set by *kim_init* for material properties archived in `OpenKIM `_. .. note:: - The *kim\_query* command must be preceded by a *kim\_init* command. + The *kim_query* command must be preceded by a *kim_init* command. -The syntax for the *kim\_query* command is as follows: +The syntax for the *kim_query* command is as follows: .. code-block:: LAMMPS @@ -438,21 +438,21 @@ For the "list" setting of *formatarg* (or if *formatarg* is not specified), the result is returned as a space-separated list of values in *variable*\ . The *formatarg* keyword "split" separates the result values into -individual variables of the form *prefix\_I*, where *prefix* is set to the -*kim\_query* *variable* argument and *I* ranges from 1 to the number of +individual variables of the form *prefix_I*, where *prefix* is set to the +*kim_query* *variable* argument and *I* ranges from 1 to the number of returned values. The number and order of the returned values is determined by the type of query performed. (Note that the "explicit" setting of -*formatarg* is not supported by *kim\_query*.) +*formatarg* is not supported by *kim_query*.) .. note:: - *kim\_query* only supports queries that return a single result or + *kim_query* only supports queries that return a single result or an array of values. More complex queries that return a JSON structure - are not currently supported. An attempt to use *kim\_query* in such + are not currently supported. An attempt to use *kim_query* in such cases will generate an error. -The second required argument *query\_function* is the name of the -query function to be called (e.g. *get\_lattice\_constant\_cubic*). +The second required argument *query_function* is the name of the +query function to be called (e.g. *get_lattice_constant_cubic*). All following :doc:`arguments ` are parameters handed over to the web query in the format *keyword=value*\ , where *value* is always an array of one or more comma-separated items in brackets. @@ -465,12 +465,12 @@ is available on the OpenKIM webpage at All query functions require the *model* keyword, which identifies the IM whose predictions are being queried. This keyword is automatically - generated by *kim\_query* based on the IM set in *kim\_init* and must not - be specified as an argument to *kim\_query*. + generated by *kim_query* based on the IM set in *kim_init* and must not + be specified as an argument to *kim_query*. .. note:: - Each *query\_function* is associated with a default method (implemented + Each *query_function* is associated with a default method (implemented as a `KIM Test `_) used to compute this property. In cases where there are multiple methods in OpenKIM for computing a property, a *method* keyword can @@ -478,10 +478,10 @@ is available on the OpenKIM webpage at `query documentation `_ to see which methods are available for a given *query function*\ . -*kim\_query* Usage Examples and Further Clarifications +*kim_query* Usage Examples and Further Clarifications ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The data obtained by *kim\_query* commands can be used as part of the setup +The data obtained by *kim_query* commands can be used as part of the setup or analysis phases of LAMMPS simulations. Some examples are given below. **Define an equilibrium fcc crystal** @@ -494,18 +494,18 @@ or analysis phases of LAMMPS simulations. Some examples are given below. lattice fcc ${a0} ... -The *kim\_query* command retrieves from `OpenKIM `_ +The *kim_query* command retrieves from `OpenKIM `_ the equilibrium lattice constant predicted by the Ercolessi and Adams (1994) potential for the fcc structure and places it in variable *a0*\ . This variable is then used on the next line to set up the -crystal. By using *kim\_query*, the user is saved the trouble and possible +crystal. By using *kim_query*, the user is saved the trouble and possible error of tracking this value down, or of having to perform an energy minimization to find the equilibrium lattice constant. -Note that in *unit\_conversion\_mode* the results obtained from a -*kim\_query* would need to be converted to the appropriate units system. +Note that in *unit_conversion_mode* the results obtained from a +*kim_query* would need to be converted to the appropriate units system. For example, in the above script, the lattice command would need to be -changed to: "lattice fcc ${a0}\*${\_u_distance}". +changed to: "lattice fcc ${a0}\*${_u_distance}". **Define an equilibrium hcp crystal** @@ -521,10 +521,10 @@ changed to: "lattice fcc ${a0}\*${\_u_distance}". basis 0.333333 0.666666 0.25 basis 0.666666 0.333333 0.75 ... -In this case the *kim\_query* returns two arguments (since the hexagonal +In this case the *kim_query* returns two arguments (since the hexagonal close packed (hcp) structure has two independent lattice constants). The *formatarg* keyword "split" places the two values into -the variables *latconst\_1* and *latconst\_2*. (These variables are +the variables *latconst_1* and *latconst_2*. (These variables are created if they do not already exist.) For convenience the variables *a0* and *c0* are created in order to make the remainder of the input script more readable. @@ -553,7 +553,7 @@ potential. of the temperature in the above example) it is also possible to pass a tolerance indicating how close to the value is considered a match. If no tolerance is passed a default value is used. If multiple results - are returned (indicating that the tolerance is too large), *kim\_query* + are returned (indicating that the tolerance is too large), *kim_query* will return an error. See the `query documentation `_ to see which numerical arguments and tolerances are available for a @@ -578,7 +578,7 @@ ideal fcc cohesive energy of the atoms in the system obtained from .. note:: - *kim\_query* commands return results archived in + *kim_query* commands return results archived in `OpenKIM `_. These results are obtained using programs for computing material properties (KIM Tests and KIM Test Drivers) that were contributed to OpenKIM. @@ -586,7 +586,7 @@ ideal fcc cohesive energy of the atoms in the system obtained from from these programs are queried is tracked. No other information about the nature of the query or its source is recorded. -Accessing KIM Model Parameters from LAMMPS (*kim\_param*) +Accessing KIM Model Parameters from LAMMPS (*kim_param*) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ All IMs are functional forms containing a set of @@ -609,10 +609,10 @@ of an IM, whereas KIM SMs are wrappers to an IM implemented within LAMMPS. Two different mechanisms are provided for accessing IM parameters in these two cases: -* For a KIM PM, the *kim\_param* command can be used to *get* and *set* the values of the PM's parameters as explained below. +* For a KIM PM, the *kim_param* command can be used to *get* and *set* the values of the PM's parameters as explained below. * For a KIM SM, the user should consult the documentation page for the specific IM and follow instructions there for how to modify its parameters (if possible). -The *kim\_param get* and *kim\_param set* commands provide an interface +The *kim_param get* and *kim_param set* commands provide an interface to access and change the parameters of a KIM PM that "publishes" its parameters and makes them publicly available (see the `KIM API documentation `_ @@ -620,19 +620,19 @@ for details). .. note:: - The *kim\_param get/set* commands must be preceded by *kim\_init*. - The *kim\_param set* command must additionally be preceded by a - *kim\_interactions* command (or alternatively by a *pair\_style kim* - and *pair\_coeff* commands). The *kim\_param set* command may be used wherever a *pair\_coeff* command may occur. + The *kim_param get/set* commands must be preceded by *kim_init*. + The *kim_param set* command must additionally be preceded by a + *kim_interactions* command (or alternatively by a *pair_style kim* + and *pair_coeff* commands). The *kim_param set* command may be used wherever a *pair_coeff* command may occur. -The syntax for the *kim\_param* command is as follows: +The syntax for the *kim_param* command is as follows: .. code-block:: LAMMPS kim_param get param_name index_range variable formatarg kim_param set param_name index_range values -Here, *param\_name* is the name of a KIM PM parameter (which is published +Here, *param_name* is the name of a KIM PM parameter (which is published by the PM and available for access). The specific string used to identify a parameter is defined by the PM. For example, for the `Stillinger--Weber (SW) potential in OpenKIM `_, @@ -641,7 +641,7 @@ the parameter names are *A, B, p, q, sigma, gamma, cutoff, lambda, costheta0*\ . .. note:: The list of all the parameters that a PM exposes for access/mutation are - automatically written to the lammps log file when *kim\_init* is called. + automatically written to the lammps log file when *kim_init* is called. Each published parameter of a KIM PM takes the form of an array of numerical values. The array can contain one element for a single-valued @@ -654,32 +654,32 @@ values used for each pairwise combination of the model's six supported species (this model does not have parameters specific to individual ternary combinations of its supported species). -The *index\_range* argument may either be an integer referring to +The *index_range* argument may either be an integer referring to a specific element within the array associated with the parameter -specified by *param\_name*, or a pair of integers separated by a colon +specified by *param_name*, or a pair of integers separated by a colon that refer to a slice of this array. In both cases, one-based indexing is used to refer to the entries of the array. -The result of a *get* operation for a specific *index\_range* is stored in +The result of a *get* operation for a specific *index_range* is stored in one or more :doc:`LAMMPS string style variables ` as determined by the optional *formatarg* argument :ref:`documented above. ` If not specified, the default for *formatarg* is "explicit" for the -*kim\_param* command. +*kim_param* command. For the case where the result is an array with multiple values -(i.e. *index\_range* contains a range), the optional "split" or "explicit" +(i.e. *index_range* contains a range), the optional "split" or "explicit" *formatarg* keywords can be used to separate the results into multiple variables; see the examples below. -Multiple parameters can be retrieved with a single call to *kim\_param get* +Multiple parameters can be retrieved with a single call to *kim_param get* by repeating the argument list following *get*\ . For a *set* operation, the *values* argument contains the new value(s) -for the element(s) of the parameter specified by *index\_range*. For the case +for the element(s) of the parameter specified by *index_range*. For the case where multiple values are being set, *values* contains a set of values separated by spaces. Multiple parameters can be set with a single call to -*kim\_param set* by repeating the argument list following *set*\ . +*kim_param set* by repeating the argument list following *set*\ . -*kim\_param* Usage Examples and Further Clarifications +*kim_param* Usage Examples and Further Clarifications ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Examples of getting and setting KIM PM parameters with further @@ -722,9 +722,9 @@ determined by the *formatarg* argument. In this case, *formatarg* is not specified and therefore the default "explicit" mode is used. (The behavior would be the same if the word -*explicit* were added after *LAM\_TeSe*.) Elements 7, 8 and 9 of parameter +*explicit* were added after *LAM_TeSe*.) Elements 7, 8 and 9 of parameter lambda retrieved by the *get* operation are placed in the LAMMPS variables -*LAM\_TeTe*, *LAM\_TeZn* and *LAM\_TeSe*, respectively. +*LAM_TeTe*, *LAM_TeZn* and *LAM_TeSe*, respectively. .. note:: @@ -754,7 +754,7 @@ The result of the *get* operation is stored in the LAMMPS variable *LAMS* as a string containing the three retrieved values separated by spaces, e.g "1.0 2.0 3.0". This can be used in LAMMPS with an *index* variable to access the values one at a time within a loop -as shown in the example. At each iteration of the loop *LAM\_VALUE* +as shown in the example. At each iteration of the loop *LAM_VALUE* contains the current value of lambda. .. code-block:: LAMMPS @@ -765,7 +765,7 @@ contains the current value of lambda. In this case, the "split" mode of *formatarg* is used. The three values retrieved by the *get* operation are stored in -the three LAMMPS variables *LAM\_15*, *LAM\_16* and *LAM\_17*. +the three LAMMPS variables *LAM_15*, *LAM_16* and *LAM_17*. The provided name "LAM" is used as prefix and the location in the lambda array is appended to create the variable names. @@ -792,8 +792,8 @@ operation will return the new value that was set. For example: ... print "original gamma = ${ORIG_GAMMA}, new gamma = ${NEW_GAMMA}" -Here, *ORIG\_GAMMA* will contain the original gamma value for the SW -potential, while *NEW\_GAMMA* will contain the value 2.6. +Here, *ORIG_GAMMA* will contain the original gamma value for the SW +potential, while *NEW_GAMMA* will contain the value 2.6. **Setting multiple scalar parameters with a single call** @@ -842,7 +842,7 @@ and enables open source efforts like OpenKIM to function. Restrictions """""""""""" -The set of *kim\_commands* is part of the KIM package. It is only enabled if +The set of *kim_commands* is part of the KIM package. It is only enabled if LAMMPS is built with that package. A requirement for the KIM package, is the KIM API library that must be downloaded from the `OpenKIM website `_ and installed before @@ -850,7 +850,7 @@ LAMMPS is compiled. When installing LAMMPS from binary, the kim-api package is a dependency that is automatically downloaded and installed. See the KIM section of the :doc:`Packages details ` for details. -Furthermore, when using *kim\_commands* to run KIM SMs, any packages required +Furthermore, when using *kim_commands* to run KIM SMs, any packages required by the native potential being used or other commands or fixes that it invokes must be installed. diff --git a/doc/src/kspace_modify.rst b/doc/src/kspace_modify.rst index ac0b0e8aad..afbe1b0043 100644 --- a/doc/src/kspace_modify.rst +++ b/doc/src/kspace_modify.rst @@ -324,18 +324,18 @@ The *tolerance* option affects how the *accuracy* specified with the The following values may be used: * energy = absolute accuracy in total Coulombic energy -* energy\_rel = relative accuracy in total Coulombic energy +* energy_rel = relative accuracy in total Coulombic energy * potential = absolute accuracy in total Coulombic potential -* potential\_rel = relative accuracy in total Coulombic potential +* potential_rel = relative accuracy in total Coulombic potential * field = absolute accuracy in electric field -* field\_rel = relative accuracy in electric field +* field_rel = relative accuracy in electric field -The values with suffix \_rel indicate the tolerance is a relative +The values with suffix _rel indicate the tolerance is a relative tolerance; the other values impose an absolute tolerance on the given quantity. Absolute tolerance in this case means, that for a given -quantity q and a given absolute tolerance of t\_a the result should -be between q-t\_a and q+t\_a. For a relative tolerance t\_r the relative -error should not be greater than t\_r, i.e. abs(1 - (result/q)) < t\_r. +quantity q and a given absolute tolerance of t_a the result should +be between q-t_a and q+t_a. For a relative tolerance t_r the relative +error should not be greater than t_r, i.e. abs(1 - (result/q)) < t_r. As a consequence of this, the tolerance type should be checked, when performing computations with a high absolute field / energy. E.g. if the total energy in the system is 1000000.0 an absolute tolerance @@ -343,10 +343,10 @@ of 1e-3 would mean that the result has to be between 999999.999 and 1000000.001, which would be equivalent to a relative tolerance of 1e-9. -The energy and energy\_rel values, set a tolerance based on the total -Coulombic energy of the system. The potential and potential\_rel set a +The energy and energy_rel values, set a tolerance based on the total +Coulombic energy of the system. The potential and potential_rel set a tolerance based on the per-atom Coulombic energy. The field and -field\_rel tolerance types set a tolerance based on the electric field +field_rel tolerance types set a tolerance based on the electric field values computed by ScaFaCoS. Since per-atom forces are derived from the per-atom electric field, this effectively sets a tolerance on the forces, similar to other LAMMPS KSpace styles, as explained on the @@ -355,7 +355,7 @@ forces, similar to other LAMMPS KSpace styles, as explained on the Note that not all ScaFaCoS solvers support all tolerance types. These are the allowed values for each method: -* fmm = energy and energy\_rel +* fmm = energy and energy_rel * p2nfft = field (1d-,2d-,3d-periodic systems) or potential (0d-periodic) * p3m = field * ewald = field @@ -365,7 +365,7 @@ If the tolerance type is not changed, the default values for the tolerance type are the first values in the above list, e.g. energy is the default tolerance type for the fmm solver. -The *fmm\_tuning* option is only relevant when using the FMM method. +The *fmm_tuning* option is only relevant when using the FMM method. It activates (value=1) or deactivates (value=0) an internal tuning mechanism for the FMM solver. The tuning operation runs sequentially and can be very time-consuming. Usually it is not needed for systems @@ -452,7 +452,7 @@ ik (PPPM), mix/disp = pair, force/disp/real = -1.0, force/disp/kspace = -1.0, split = 0, tol = 1.0e-6, and disp/auto = no. For pppm/intel, order = order/disp = 7. For scafacos settings, the scafacos tolerance option depends on the method chosen, as documented above. The -scafacos fmm\_tuning default = 0. +scafacos fmm_tuning default = 0. ---------- diff --git a/doc/src/kspace_style.rst b/doc/src/kspace_style.rst index 786b048b04..157e376fb4 100644 --- a/doc/src/kspace_style.rst +++ b/doc/src/kspace_style.rst @@ -216,13 +216,13 @@ parameters and how to choose them is described in .. note:: All of the PPPM styles can be used with single-precision FFTs by - using the compiler switch -DFFT\_SINGLE for the FFT\_INC setting in your + using the compiler switch -DFFT_SINGLE for the FFT_INC setting in your low-level Makefile. This setting also changes some of the PPPM operations (e.g. mapping charge to mesh and interpolating electric fields to particles) to be performed in single precision. This option can speed-up long-range calculations, particularly in parallel or on - GPUs. The use of the -DFFT\_SINGLE flag is discussed on the :doc:`Build settings ` doc page. MSM does not currently support - the -DFFT\_SINGLE compiler switch. + GPUs. The use of the -DFFT_SINGLE flag is discussed on the :doc:`Build settings ` doc page. MSM does not currently support + the -DFFT_SINGLE compiler switch. ---------- @@ -274,7 +274,7 @@ See details on :ref:`this page `. Unlike other KSpace solvers in LAMMPS, ScaFaCoS computes all Coulombic interactions, both short- and long-range. Thus you should - NOT use a Coulombic pair style when using kspace\_style scafacos. This + NOT use a Coulombic pair style when using kspace_style scafacos. This also means the total Coulombic energy (short- and long-range) will be tallied for :doc:`thermodynamic output ` command as part of the *elong* keyword; the *ecoul* keyword will be zero. @@ -377,7 +377,7 @@ produce the same results, except for round-off and precision issues. More specifically, the *pppm/gpu* style performs charge assignment and force interpolation calculations on the GPU. These processes are performed either in single or double precision, depending on whether -the -DFFT\_SINGLE setting was specified in your low-level Makefile, as +the -DFFT_SINGLE setting was specified in your low-level Makefile, as discussed above. The FFTs themselves are still calculated on the CPU. If *pppm/gpu* is used with a GPU-enabled pair style, part of the PPPM calculation can be performed concurrently on the GPU while other diff --git a/doc/src/min_modify.rst b/doc/src/min_modify.rst index c5452e21f4..a01aab173d 100644 --- a/doc/src/min_modify.rst +++ b/doc/src/min_modify.rst @@ -108,25 +108,25 @@ all atoms in the system: For the min styles *spin*\ , *spin/cg* and *spin/lbfgs*\ , the force norm is replaced by the spin-torque norm. -Keywords *alpha\_damp* and *discrete\_factor* only make sense when +Keywords *alpha_damp* and *discrete_factor* only make sense when a :doc:`min_spin ` command is declared. -Keyword *alpha\_damp* defines an analog of a magnetic Gilbert +Keyword *alpha_damp* defines an analog of a magnetic Gilbert damping. It defines a relaxation rate toward an equilibrium for a given magnetic system. -Keyword *discrete\_factor* defines a discretization factor for the +Keyword *discrete_factor* defines a discretization factor for the adaptive timestep used in the *spin* minimization. See :doc:`min_spin ` for more information about those quantities. The choice of a line search algorithm for the *spin/cg* and *spin/lbfgs* styles can be specified via the *line* keyword. The -*spin\_cubic* and *spin\_none* keywords only make sense when one of those two -minimization styles is declared. The *spin\_cubic* performs the line +*spin_cubic* and *spin_none* keywords only make sense when one of those two +minimization styles is declared. The *spin_cubic* performs the line search based on a cubic interpolation of the energy along the search -direction. The *spin\_none* keyword deactivates the line search -procedure. The *spin\_none* is a default value for *line* keyword for +direction. The *spin_none* keyword deactivates the line search +procedure. The *spin_none* is a default value for *line* keyword for both *spin/lbfgs* and *spin/cg*\ . Convergence of *spin/lbfgs* can be -more robust if *spin\_cubic* line search is used. +more robust if *spin_cubic* line search is used. The Newton *integrator* used for *fire* minimization can be selected to be either the symplectic Euler (\ *eulerimplicit*\ ) or velocity @@ -163,7 +163,7 @@ to the *fire/old* style by using the following set of parameters: Restrictions """""""""""" -For magnetic GNEB calculations, only *spin\_none* value for *line* +For magnetic GNEB calculations, only *spin_none* value for *line* keyword can be used when minimization styles *spin/cg* and *spin/lbfgs* are employed. See :doc:`neb/spin ` for more explanation. @@ -178,8 +178,8 @@ Default The option defaults are dmax = 0.1, line = quadratic and norm = two. For the *spin*\ , *spin/cg* and *spin/lbfgs* styles, the option -defaults are alpha\_damp = 1.0, discrete\_factor = 10.0, line = -spin\_none, and norm = euclidean. +defaults are alpha_damp = 1.0, discrete_factor = 10.0, line = +spin_none, and norm = euclidean. For the *fire* style, the option defaults are integrator = eulerimplicit, tmax = 10.0, tmin = 0.02, delaystep = 20, dtgrow = 1.1, diff --git a/doc/src/min_spin.rst b/doc/src/min_spin.rst index 2474493fe8..46fd08b838 100644 --- a/doc/src/min_spin.rst +++ b/doc/src/min_spin.rst @@ -41,7 +41,7 @@ timestep, according to: with :math:`\lambda` a damping coefficient (similar to a Gilbert damping). :math:`\lambda` can be defined by setting the -*alpha\_damp* keyword with the :doc:`min_modify ` command. +*alpha_damp* keyword with the :doc:`min_modify ` command. The minimization procedure solves this equation using an adaptive timestep. The value of this timestep is defined @@ -56,15 +56,15 @@ with :math:`\left|\vec{\omega}_{\rm max}\right|` the norm of the largest precess frequency in the system (across all processes, and across all replicas if a spin/neb calculation is performed). -:math:`\kappa` defines a discretization factor *discrete\_factor* for -the definition of this timestep. *discrete\_factor* can be defined with +:math:`\kappa` defines a discretization factor *discrete_factor* for +the definition of this timestep. *discrete_factor* can be defined with the :doc:`min_modify ` command. Style *spin/cg* defines an orthogonal spin optimization (OSO) combined to a conjugate gradient (CG) algorithm. The :doc:`min_modify ` command can be used to couple the *spin/cg* to a line search procedure, and to modify the -discretization factor *discrete\_factor*. +discretization factor *discrete_factor*. By default, style *spin/cg* does not employ the line search procedure and uses the adaptive time-step technique in the same way as style *spin*\ . @@ -74,12 +74,12 @@ algorithm. By default, style *spin/lbfgs* does not employ line search procedure. If the line search procedure is not used then the discrete factor defines the maximum root mean squared rotation angle of spins by equation *pi/(5\*Kappa)*. The default value for Kappa is 10. The -*spin\_cubic* line search option can improve the convergence of the +*spin_cubic* line search option can improve the convergence of the *spin/lbfgs* algorithm. The :doc:`min_modify ` command can be used to activate the line search procedure, and to modify the -discretization factor *discrete\_factor*. +discretization factor *discrete_factor*. For more information about styles *spin/cg* and *spin/lbfgs*\ , see their implementation reported in :ref:`(Ivanov) `. @@ -110,8 +110,8 @@ Related commands Default """"""" -The option defaults are *alpha\_damp* = 1.0, *discrete\_factor* = -10.0, *line* = spin\_none and *norm* = euclidean. +The option defaults are *alpha_damp* = 1.0, *discrete_factor* = +10.0, *line* = spin_none and *norm* = euclidean. ---------- diff --git a/doc/src/molecule.rst b/doc/src/molecule.rst index f6839c57df..32e6d846ae 100644 --- a/doc/src/molecule.rst +++ b/doc/src/molecule.rst @@ -242,7 +242,7 @@ on each atom in the molecule is 0.0. * diam = diameter of atom This section is only allowed for :doc:`atom styles ` that -support finite-size spherical particles, e.g. atom\_style sphere. If +support finite-size spherical particles, e.g. atom_style sphere. If not listed, the default diameter of each atom in the molecule is 1.0. ---------- diff --git a/doc/src/neb.rst b/doc/src/neb.rst index bd08ae3d1d..acb157e2ec 100644 --- a/doc/src/neb.rst +++ b/doc/src/neb.rst @@ -374,24 +374,24 @@ restart the calculation from an intermediate point with altered parameters. There are 2 Python scripts provided in the tools/python directory, -neb\_combine.py and neb\_final.py, which are useful in analyzing output +neb_combine.py and neb_final.py, which are useful in analyzing output from a NEB calculation. Assume a NEB simulation with M replicas, and the NEB atoms labeled with a specific atom type. -The neb\_combine.py script extracts atom coords for the NEB atoms from +The neb_combine.py script extracts atom coords for the NEB atoms from all M dump files and creates a single dump file where each snapshot contains the NEB atoms from all the replicas and one copy of non-NEB atoms from the first replica (presumed to be identical in other replicas). This can be visualized/animated to see how the NEB atoms relax as the NEB calculation proceeds. -The neb\_final.py script extracts the final snapshot from each of the M +The neb_final.py script extracts the final snapshot from each of the M dump files to create a single dump file with M snapshots. This can be visualized to watch the system make its transition over the energy barrier. To illustrate, here are images from the final snapshot produced by the -neb\_combine.py script run on the dump files produced by the two +neb_combine.py script run on the dump files produced by the two example input scripts in examples/neb. Click on them to see a larger image. diff --git a/doc/src/neb_spin.rst b/doc/src/neb_spin.rst index cbeca25327..10b08f674b 100644 --- a/doc/src/neb_spin.rst +++ b/doc/src/neb_spin.rst @@ -369,7 +369,7 @@ calculation fails to converge properly to the MEP, and you wish to restart the calculation from an intermediate point with altered parameters. -A c file script in provided in the tool/spin/interpolate\_gneb +A c file script in provided in the tool/spin/interpolate_gneb directory, that interpolates the MEP given the information provided by the *verbose* output option (as detailed in Appendix D of :ref:`(BessarabA) `). @@ -383,7 +383,7 @@ This command can only be used if LAMMPS was built with the SPIN package. See the :doc:`Build package ` doc page for more info. -For magnetic GNEB calculations, only the *spin\_none* value for the +For magnetic GNEB calculations, only the *spin_none* value for the *line* keyword can be used when minimization styles *spin/cg* and *spin/lbfgs* are employed. diff --git a/doc/src/neigh_modify.rst b/doc/src/neigh_modify.rst index fea38e5e50..74b4572b95 100644 --- a/doc/src/neigh_modify.rst +++ b/doc/src/neigh_modify.rst @@ -159,7 +159,7 @@ turning off bond interactions. long-range solver treats the interaction. This is done correctly for pairwise interactions that are excluded (or weighted) via the :doc:`special_bonds ` command. But it is not done for - interactions that are excluded via these neigh\_modify exclude options. + interactions that are excluded via these neigh_modify exclude options. The *page* and *one* options affect how memory is allocated for the neighbor lists. For most simulations the default settings for these diff --git a/doc/src/package.rst b/doc/src/package.rst index 059dfba957..609216206d 100644 --- a/doc/src/package.rst +++ b/doc/src/package.rst @@ -264,11 +264,11 @@ GPUs from different vendors or for CPU based accelerator support). In LAMMPS only one platform can be active at a time and by default the first platform with an accelerator is selected. This is equivalent to using a platform ID of -1. The platform ID is a number corresponding -to the output of the ocl\_get\_devices tool. The platform ID is passed +to the output of the ocl_get_devices tool. The platform ID is passed to the GPU library, by prefixing the *device* keyword with that number separated by a colon. For CUDA, the *device* keyword is ignored. Currently, the device tuning support is limited to NVIDIA Kepler, NVIDIA -Fermi, AMD Cypress, Intel x86\_64 CPU, Intel Xeon Phi, or a generic device. +Fermi, AMD Cypress, Intel x86_64 CPU, Intel Xeon Phi, or a generic device. More devices may be added later. The default device type can be specified when building LAMMPS with the GPU library, via setting a variable in the lib/gpu/Makefile that is used. @@ -278,19 +278,19 @@ In addition, a device type *custom* is available, which is followed by from the package command. It can be combined with the (colon separated) platform id. The individual settings are: -* MEM\_THREADS -* THREADS\_PER\_ATOM -* THREADS\_PER\_CHARGE -* BLOCK\_PAIR -* MAX\_SHARED\_TYPES -* BLOCK\_NBOR\_BUILD -* BLOCK\_BIO\_PAIR -* BLOCK\_ELLIPSE -* WARP\_SIZE -* PPPM\_BLOCK\_1D -* BLOCK\_CELL\_2D -* BLOCK\_CELL\_ID -* MAX\_BIO\_SHARED\_TYPES +* MEM_THREADS +* THREADS_PER_ATOM +* THREADS_PER_CHARGE +* BLOCK_PAIR +* MAX_SHARED_TYPES +* BLOCK_NBOR_BUILD +* BLOCK_BIO_PAIR +* BLOCK_ELLIPSE +* WARP_SIZE +* PPPM_BLOCK_1D +* BLOCK_CELL_2D +* BLOCK_CELL_ID +* MAX_BIO_SHARED_TYPES The *blocksize* keyword allows you to tweak the number of threads used per thread block. This number should be a multiple of 32 (for GPUs) @@ -333,10 +333,10 @@ The *Nthread* value for the *omp* keyword sets the number of OpenMP threads allocated for each MPI task. Setting *Nthread* = 0 (the default) instructs LAMMPS to use whatever value is the default for the given OpenMP environment. This is usually determined via the -*OMP\_NUM\_THREADS* environment variable or the compiler runtime, which +*OMP_NUM_THREADS* environment variable or the compiler runtime, which is usually a value of 1. -For more details, including examples of how to set the OMP\_NUM\_THREADS +For more details, including examples of how to set the OMP_NUM_THREADS environment variable, see the discussion of the *Nthreads* setting on this doc page for the "package omp" command. Nthreads is a required argument for the USER-OMP package. Its meaning is exactly the same @@ -368,7 +368,7 @@ force calculation. The *lrt* keyword can be used to enable "Long Range Thread (LRT)" mode. It can take a value of *yes* to enable and *no* to disable. LRT mode generates an extra thread (in addition to any OpenMP threads -specified with the OMP\_NUM\_THREADS environment variable or the *omp* +specified with the OMP_NUM_THREADS environment variable or the *omp* keyword). The extra thread is dedicated for performing part of the :doc:`PPPM solver ` computations and communications. This can improve parallel performance on processors supporting @@ -381,7 +381,7 @@ ignored and no extra threads are generated. Enabling LRT will replace the :doc:`run_style ` with the *verlet/lrt/intel* style that is identical to the default *verlet* style aside from supporting the LRT feature. This feature requires setting the pre-processor flag --DLMP\_INTEL\_USELRT in the makefile when compiling LAMMPS. +-DLMP_INTEL_USELRT in the makefile when compiling LAMMPS. The *balance* keyword sets the fraction of :doc:`pair style ` work offloaded to the co-processor for split values between 0.0 and 1.0 inclusive. While this fraction of work is @@ -421,7 +421,7 @@ with 16 threads, for a total of 128. Note that the default settings for *tpc* and *tptask* are fine for most problems, regardless of how many MPI tasks you assign to a Phi. -The *no\_affinity* keyword will turn off automatic setting of core +The *no_affinity* keyword will turn off automatic setting of core affinity for MPI tasks and OpenMP threads on the host when using offload to a co-processor. Affinity settings are used when possible to prevent MPI tasks and OpenMP threads from being on separate NUMA @@ -538,7 +538,7 @@ keywords are set to *device*\ , the value for these *comm* keywords will be automatically changed to *host*\ . This setting has no effect if not running on GPUs or if using only one MPI rank. CUDA-aware MPI is available for OpenMPI 1.8 (or later versions), Mvapich2 1.9 (or later) when the -"MV2\_USE\_CUDA" environment variable is set to "1", CrayMPI, and IBM +"MV2_USE_CUDA" environment variable is set to "1", CrayMPI, and IBM Spectrum MPI when the "-gpu" flag is used. ---------- @@ -557,10 +557,10 @@ tasks \* threads/task should not exceed the physical number of cores Setting *Nthread* = 0 instructs LAMMPS to use whatever value is the default for the given OpenMP environment. This is usually determined -via the *OMP\_NUM\_THREADS* environment variable or the compiler +via the *OMP_NUM_THREADS* environment variable or the compiler runtime. Note that in most cases the default for OpenMP capable compilers is to use one thread for each available CPU core when -*OMP\_NUM\_THREADS* is not explicitly set, which can lead to poor +*OMP_NUM_THREADS* is not explicitly set, which can lead to poor performance. Here are examples of how to set the environment variable when @@ -576,7 +576,7 @@ or you can set it permanently in your shell's start-up script. All three of these examples use a total of 4 CPU cores. Note that different MPI implementations have different ways of passing -the OMP\_NUM\_THREADS environment variable to all MPI processes. The +the OMP_NUM_THREADS environment variable to all MPI processes. The 2nd example line above is for MPICH; the 3rd example line with -x is for OpenMPI. Check your MPI documentation for additional details. diff --git a/doc/src/pair_adp.rst b/doc/src/pair_adp.rst index fb8394a31b..2e2be63430 100644 --- a/doc/src/pair_adp.rst +++ b/doc/src/pair_adp.rst @@ -46,7 +46,7 @@ and quadruple distortions of the local atomic environment which extend the original EAM framework by introducing angular forces. Note that unlike for other potentials, cutoffs for ADP potentials are -not set in the pair\_style or pair\_coeff command; they are specified in +not set in the pair_style or pair_coeff command; they are specified in the ADP potential files themselves. Likewise, the ADP potential files list atomic masses; thus you do not need to use the :doc:`mass ` command to specify them. @@ -61,10 +61,10 @@ command to specify them. ---------- -Only a single pair\_coeff command is used with the *adp* style which +Only a single pair_coeff command is used with the *adp* style which specifies an extended DYNAMO *setfl* file, which contains information for :math:`M` elements. These are mapped to LAMMPS atom types by specifying :math:`N` -additional arguments after the filename in the pair\_coeff command, +additional arguments after the filename in the pair_coeff command, where :math:`N` is the number of LAMMPS atom types: * filename @@ -78,7 +78,7 @@ potentials directory of the LAMMPS distribution, is an extended *setfl* file which has tabulated ADP values for w elements and their alloy interactions: Cu and Al. If your LAMMPS simulation has 4 atoms types and you want the 1st 3 to be Al, and the 4th to be Cu, you would use -the following pair\_coeff command: +the following pair_coeff command: .. code-block:: LAMMPS @@ -164,7 +164,7 @@ This pair style does not support the :doc:`pair_modify ` shift, table, and tail options. This pair style does not write its information to :doc:`binary restart files `, since it is stored in tabulated potential files. -Thus, you need to re-specify the pair\_style and pair\_coeff commands in +Thus, you need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_agni.rst b/doc/src/pair_agni.rst index c0453d9130..2023e655f4 100644 --- a/doc/src/pair_agni.rst +++ b/doc/src/pair_agni.rst @@ -48,11 +48,11 @@ of the method is to map the atomic environment numerically into a fingerprint, and use machine learning methods to create a mapping to the vectorial atomic forces. -Only a single pair\_coeff command is used with the *agni* style which +Only a single pair_coeff command is used with the *agni* style which specifies an AGNI potential file containing the parameters of the force field for the needed elements. These are mapped to LAMMPS atom types by specifying :math:`N` additional arguments after the filename in the -pair\_coeff command, where :math:`N` is the number of LAMMPS atom types: +pair_coeff command, where :math:`N` is the number of LAMMPS atom types: * filename * :math:`N` element names = mapping of AGNI elements to atom types @@ -91,7 +91,7 @@ This pair style does not support the :doc:`pair_modify ` shift, table, and tail options. This pair style does not write its information to :doc:`binary restart files `, since it is stored in potential files. Thus, you -need to re-specify the pair\_style and pair\_coeff commands in an input +need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_airebo.rst b/doc/src/pair_airebo.rst index dd113b8f4b..d7fc9a9c07 100644 --- a/doc/src/pair_airebo.rst +++ b/doc/src/pair_airebo.rst @@ -36,9 +36,9 @@ Syntax * style = *airebo* or *airebo/morse* or *rebo* * cutoff = LJ or Morse cutoff (:math:`\sigma` scale factor) (AIREBO and AIREBO-M only) -* LJ\_flag = 0/1 to turn off/on the LJ or Morse term (AIREBO and AIREBO-M only, optional) -* TORSION\_flag = 0/1 to turn off/on the torsion term (AIREBO and AIREBO-M only, optional) -* cutoff\_min = Start of the transition region of cutoff (:math:`\sigma` scale factor) (AIREBO and AIREBO-M only, optional) +* LJ_flag = 0/1 to turn off/on the LJ or Morse term (AIREBO and AIREBO-M only, optional) +* TORSION_flag = 0/1 to turn off/on the torsion term (AIREBO and AIREBO-M only, optional) +* cutoff_min = Start of the transition region of cutoff (:math:`\sigma` scale factor) (AIREBO and AIREBO-M only, optional) Examples """""""" @@ -87,7 +87,7 @@ The AIREBO potential consists of three terms: \sum_{k \neq i,j} \sum_{l \neq i,j,k} E^{\text{TORSION}}_{kijl} \right] \\ By default, all three terms are included. For the *airebo* style, if -the first two optional flag arguments to the pair\_style command are +the first two optional flag arguments to the pair_style command are included, the LJ and torsional terms can be turned off. Note that both or neither of the flags must be included. If both of the LJ an torsional terms are turned off, it becomes the 2nd-generation REBO @@ -125,9 +125,9 @@ factor of 3.0 (the argument in pair_style), the resulting :math:`E^{\text{LJ}}` would be 10.2 Angstroms. By default, the longer-ranged interaction is smoothly switched off -between 2.16 and 3.0 :math:`\sigma`. By specifying *cutoff\_min* in addition +between 2.16 and 3.0 :math:`\sigma`. By specifying *cutoff_min* in addition to *cutoff*\ , the switching can be configured to take place between -*cutoff\_min* and *cutoff*\ . *cutoff\_min* can only be specified if all +*cutoff_min* and *cutoff*\ . *cutoff_min* can only be specified if all optional arguments are given. The :math:`E^{\text{TORSION}}` term is an explicit 4-body potential that describes diff --git a/doc/src/pair_atm.rst b/doc/src/pair_atm.rst index edb6444c24..902e07a80d 100644 --- a/doc/src/pair_atm.rst +++ b/doc/src/pair_atm.rst @@ -11,7 +11,7 @@ Syntax pair_style atm cutoff cutoff_triple * cutoff = cutoff for each pair in 3-body interaction (distance units) -* cutoff\_triple = additional cutoff applied to product of 3 pairwise distances (distance units) +* cutoff_triple = additional cutoff applied to product of 3 pairwise distances (distance units) Examples """""""" diff --git a/doc/src/pair_awpmd.rst b/doc/src/pair_awpmd.rst index 5ff884e790..701c45849e 100644 --- a/doc/src/pair_awpmd.rst +++ b/doc/src/pair_awpmd.rst @@ -12,7 +12,7 @@ Syntax * Rc = global cutoff, -1 means cutoff of half the shortest box length * zero or more keyword/value pairs may be appended -* keyword = *hartree* or *dproduct* or *uhf* or *free* or *pbc* or *fix* or *harm* or *ermscale* or *flex\_press* +* keyword = *hartree* or *dproduct* or *uhf* or *free* or *pbc* or *fix* or *harm* or *ermscale* or *flex_press* .. parsed-literal:: @@ -49,7 +49,7 @@ basic formulas here. Could be links to other documents. Rc is the cutoff. -The pair\_style command allows for several optional keywords +The pair_style command allows for several optional keywords to be specified. The *hartree*\ , *dproduct*\ , and *uhf* keywords specify the form of the @@ -77,7 +77,7 @@ The *ermscale* keyword specifies a unitless scaling factor between the electron masses and the width variable mass. More details needed. -If the *flex\_press* keyword is used, then a contribution from the +If the *flex_press* keyword is used, then a contribution from the electrons is added to the total virial and pressure of the system. This potential is designed to be used with :doc:`atom_style wavepacket ` definitions, in order to handle the @@ -93,7 +93,7 @@ commands, or by mixing as described below: For *awpmd/cut*\ , the cutoff coefficient is optional. If it is not used (as in some of the examples above), the default global value -specified in the pair\_style command is used. +specified in the pair_style command is used. ---------- @@ -102,7 +102,7 @@ specified in the pair\_style command is used. The :doc:`pair_modify ` mix, shift, table, and tail options are not relevant for this pair style. -This pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the @@ -123,5 +123,5 @@ Related commands Default """"""" -These are the defaults for the pair\_style keywords: *hartree* for the +These are the defaults for the pair_style keywords: *hartree* for the initial wave function, *free* for the wave packet width. diff --git a/doc/src/pair_beck.rst b/doc/src/pair_beck.rst index b71661ea78..f234366eae 100644 --- a/doc/src/pair_beck.rst +++ b/doc/src/pair_beck.rst @@ -90,7 +90,7 @@ for this pair style. This pair style does not support the :doc:`pair_modify ` tail option for adding long-range tail corrections. -This pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_body_rounded_polygon.rst b/doc/src/pair_body_rounded_polygon.rst index 152dd9a996..baba67bf7f 100644 --- a/doc/src/pair_body_rounded_polygon.rst +++ b/doc/src/pair_body_rounded_polygon.rst @@ -54,7 +54,7 @@ between two particles are defined with respect to the separation of their respective rounded surfaces, not by the separation of the vertices and edges themselves. -This means that the specified cutoff in the pair\_style command is the +This means that the specified cutoff in the pair_style command is the cutoff distance, :math:`r_c`, for the surface separation, :math:`\delta_n` (see figure below). This is the distance at which two particles no longer interact. If :math:`r_c` is specified as 0.0, then it is a contact-only @@ -121,8 +121,8 @@ above for force versus surface separation, for :math:`\delta_n < 0` and This pair style does not support the :doc:`pair_modify ` mix, shift, table, and tail options. -This pair style does not write its information to :doc:`binary restart files `. Thus, you need to re-specify the pair\_style and -pair\_coeff commands in an input script that reads a restart file. +This pair style does not write its information to :doc:`binary restart files `. Thus, you need to re-specify the pair_style and +pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the :doc:`run_style respa ` command. It does not support the diff --git a/doc/src/pair_body_rounded_polyhedron.rst b/doc/src/pair_body_rounded_polyhedron.rst index ac4d578c30..72e94db8c9 100644 --- a/doc/src/pair_body_rounded_polyhedron.rst +++ b/doc/src/pair_body_rounded_polyhedron.rst @@ -54,7 +54,7 @@ and energies between two particles are defined with respect to the separation of their respective rounded surfaces, not by the separation of the vertices, edges, and faces themselves. -This means that the specified cutoff in the pair\_style command is the +This means that the specified cutoff in the pair_style command is the cutoff distance, :math:`r_c`, for the surface separation, :math:`\delta_n` (see figure below). This is the distance at which two particles no longer interact. If :math:`r_c` is specified as 0.0, then it is a contact-only @@ -116,7 +116,7 @@ This pair style does not support the :doc:`pair_modify ` mix, shift, table, and tail options. This pair style does not write its information to :doc:`binary restart files `. -Thus, you need to re-specify the pair\_style and pair\_coeff +Thus, you need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_bop.rst b/doc/src/pair_bop.rst index 31a5a369d7..ce7b69f41f 100644 --- a/doc/src/pair_bop.rst +++ b/doc/src/pair_bop.rst @@ -36,15 +36,15 @@ quantum mechanical theory incorporating both :math:`\sigma` and :math:`\pi` bond By analytically deriving the BOP from quantum mechanical theory its transferability to different phases can approach that of quantum mechanical methods. This potential is similar to the original BOP -developed by Pettifor (:ref:`Pettifor\_1 `, -:ref:`Pettifor\_2 `, :ref:`Pettifor\_3 `) and later updated +developed by Pettifor (:ref:`Pettifor_1 `, +:ref:`Pettifor_2 `, :ref:`Pettifor_3 `) and later updated by Murdick, Zhou, and Ward (:ref:`Murdick `, :ref:`Ward `). Currently, BOP potential files for these systems are provided with LAMMPS: AlCu, CCu, CdTe, CdTeSe, CdZnTe, CuH, GaAs. A system with only a subset of these elements, including a single element (e.g. C or Cu or Al or Ga or Zn or CdZn), can also be modeled by using the appropriate alloy file and assigning all atom types to the -single element or subset of elements via the pair\_coeff command, as +single element or subset of elements via the pair_coeff command, as discussed below. The BOP potential consists of three terms: @@ -58,7 +58,7 @@ representing the repulsion between a pair of ion cores, :math:`\beta_{\sigma,ij}(r_{ij})` and :math:`\beta_{\sigma,ij}(r_{ij})` are respectively sigma and :math:`\pi` bond integrals, :math:`\Theta_{\sigma,ij}` and :math:`\Theta_{\pi,ij}` are :math:`\sigma` and :math:`\pi` -bond-orders, and U\_prom is the promotion energy for sp-valent systems. +bond-orders, and U_prom is the promotion energy for sp-valent systems. The detailed formulas for this potential are given in Ward (:ref:`Ward `); here we provide only a brief description. @@ -84,7 +84,7 @@ efficient potential formulation suitable for MD simulations, the derived BOP only takes (and retains) the first two levels of the recursive representations for both the :math:`\sigma` and the :math:`\pi` bond-orders. Bond-order terms can be understood in terms of molecular orbital hopping paths -based upon the Cyrot-Lackmann theorem (:ref:`Pettifor\_1 `). +based upon the Cyrot-Lackmann theorem (:ref:`Pettifor_1 `). The :math:`\sigma` bond-order with a half-full valence shell is used to interpolate the bond-order expression that incorporated explicit valance band filling. This :math:`\pi` bond-order expression also contains also contains @@ -96,7 +96,7 @@ length 4. This enables the incorporation of dihedral angles effects. .. note:: Note that unlike for other potentials, cutoffs for BOP - potentials are not set in the pair\_style or pair\_coeff command; they + potentials are not set in the pair_style or pair_coeff command; they are specified in the BOP potential files themselves. Likewise, the BOP potential files list atomic masses; thus you do not need to use the :doc:`mass ` command to specify them. Note that for BOP @@ -106,7 +106,7 @@ length 4. This enables the incorporation of dihedral angles effects. :doc:`pair_coeff ` command to read the BOP potential file. -One option can be specified as a keyword with the pair\_style command. +One option can be specified as a keyword with the pair_style command. The *save* keyword gives you the option to calculate in advance and store a set of distances, angles, and derivatives of angles. The @@ -118,10 +118,10 @@ system configuration. ---------- -Only a single pair\_coeff command is used with the *bop* style which +Only a single pair_coeff command is used with the *bop* style which specifies a BOP potential file, with parameters for all needed elements. These are mapped to LAMMPS atom types by specifying -N additional arguments after the filename in the pair\_coeff command, +N additional arguments after the filename in the pair_coeff command, where N is the number of LAMMPS atom types: * filename @@ -130,7 +130,7 @@ where N is the number of LAMMPS atom types: As an example, imagine the CdTe.bop file has BOP values for Cd and Te. If your LAMMPS simulation has 4 atoms types and you want the 1st 3 to be Cd, and the 4th to be Te, you would use the following -pair\_coeff command: +pair_coeff command: .. parsed-literal:: @@ -143,8 +143,8 @@ element in the BOP file. The final Te argument maps LAMMPS atom type BOP files in the *potentials* directory of the LAMMPS distribution have a ".bop" suffix. The potentials are in tabulated form containing -pre-tabulated pair functions for phi\_ij(r\_ij), beta\_(sigma,ij)(r\_ij), -and beta\_pi,ij)(r\_ij). +pre-tabulated pair functions for phi_ij(r_ij), beta_(sigma,ij)(r_ij), +and beta_pi,ij)(r_ij). The parameters/coefficients format for the different kinds of BOP files are given below with variables matching the formulation of Ward @@ -170,89 +170,89 @@ the tabulated functions are given. * Line 1: nr, nBOt (nr is the number of divisions the radius is broken into for function tables and MUST be a factor of 5; nBOt is the number - of divisions for the tabulated values of THETA\_(S,ij) -* Line 2: delta\_1-delta\_7 (if all are not used in the particular + of divisions for the tabulated values of THETA_(S,ij) +* Line 2: delta_1-delta_7 (if all are not used in the particular * formulation, set unused values to 0.0) -Following this N lines for e\_1-e\_N containing p\_pi. +Following this N lines for e_1-e_N containing p_pi. -* Line 3: p\_pi (for e\_1) -* Line 4: p\_pi (for e\_2 and continues to e\_N) +* Line 3: p_pi (for e_1) +* Line 4: p_pi (for e_2 and continues to e_N) The next section contains several pair constants for the number of -interaction types e\_i-e\_j, with i=1->N, j=i->N +interaction types e_i-e_j, with i=1->N, j=i->N -* Line 1: r\_cut (for e\_1-e\_1 interactions) -* Line 2: c\_sigma, a\_sigma, c\_pi, a\_pi -* Line 3: delta\_sigma, delta\_pi -* Line 4: f\_sigma, k\_sigma, delta\_3 (This delta\_3 is similar to that of +* Line 1: r_cut (for e_1-e_1 interactions) +* Line 2: c_sigma, a_sigma, c_pi, a_pi +* Line 3: delta_sigma, delta_pi +* Line 4: f_sigma, k_sigma, delta_3 (This delta_3 is similar to that of the previous section but is interaction type dependent) The next section contains a line for each three body interaction type -e\_j-e\_i-e\_k with i=0->N, j=0->N, k=j->N +e_j-e_i-e_k with i=0->N, j=0->N, k=j->N -* Line 1: g\_(sigma0), g\_(sigma1), g\_(sigma2) (These are coefficients for - g\_(sigma,jik)(THETA\_ijk) for e\_1-e\_1-e\_1 interaction. :ref:`Ward ` +* Line 1: g_(sigma0), g_(sigma1), g_(sigma2) (These are coefficients for + g_(sigma,jik)(THETA_ijk) for e_1-e_1-e_1 interaction. :ref:`Ward ` contains the full expressions for the constants as functions of - b\_(sigma,ijk), p\_(sigma,ijk), u\_(sigma,ijk)) -* Line 2: g\_(sigma0), g\_(sigma1), g\_(sigma2) (for e\_1-e\_1-e\_2) + b_(sigma,ijk), p_(sigma,ijk), u_(sigma,ijk)) +* Line 2: g_(sigma0), g_(sigma1), g_(sigma2) (for e_1-e_1-e_2) The next section contains a block for each interaction type for the -phi\_ij(r\_ij). Each block has nr entries with 5 entries per line. +phi_ij(r_ij). Each block has nr entries with 5 entries per line. -* Line 1: phi(r1), phi(r2), phi(r3), phi(r4), phi(r5) (for the e\_1-e\_1 +* Line 1: phi(r1), phi(r2), phi(r3), phi(r4), phi(r5) (for the e_1-e_1 interaction type) * Line 2: phi(r6), phi(r7), phi(r8), phi(r9), phi(r10) (this continues until nr) * ... -* Line nr/5\_1: phi(r1), phi(r2), phi(r3), phi(r4), phi(r5), (for the - e\_1-e\_1 interaction type) +* Line nr/5_1: phi(r1), phi(r2), phi(r3), phi(r4), phi(r5), (for the + e_1-e_1 interaction type) The next section contains a block for each interaction type for the -beta\_(sigma,ij)(r\_ij). Each block has nr entries with 5 entries per +beta_(sigma,ij)(r_ij). Each block has nr entries with 5 entries per line. -* Line 1: beta\_sigma(r1), beta\_sigma(r2), beta\_sigma(r3), beta\_sigma(r4), - beta\_sigma(r5) (for the e\_1-e\_1 interaction type) -* Line 2: beta\_sigma(r6), beta\_sigma(r7), beta\_sigma(r8), beta\_sigma(r9), - beta\_sigma(r10) (this continues until nr) +* Line 1: beta_sigma(r1), beta_sigma(r2), beta_sigma(r3), beta_sigma(r4), + beta_sigma(r5) (for the e_1-e_1 interaction type) +* Line 2: beta_sigma(r6), beta_sigma(r7), beta_sigma(r8), beta_sigma(r9), + beta_sigma(r10) (this continues until nr) * ... -* Line nr/5+1: beta\_sigma(r1), beta\_sigma(r2), beta\_sigma(r3), - beta\_sigma(r4), beta\_sigma(r5) (for the e\_1-e\_2 interaction type) +* Line nr/5+1: beta_sigma(r1), beta_sigma(r2), beta_sigma(r3), + beta_sigma(r4), beta_sigma(r5) (for the e_1-e_2 interaction type) The next section contains a block for each interaction type for -beta\_(pi,ij)(r\_ij). Each block has nr entries with 5 entries per line. +beta_(pi,ij)(r_ij). Each block has nr entries with 5 entries per line. -* Line 1: beta\_pi(r1), beta\_pi(r2), beta\_pi(r3), beta\_pi(r4), beta\_pi(r5) - (for the e\_1-e\_1 interaction type) -* Line 2: beta\_pi(r6), beta\_pi(r7), beta\_pi(r8), beta\_pi(r9), - beta\_pi(r10) (this continues until nr) +* Line 1: beta_pi(r1), beta_pi(r2), beta_pi(r3), beta_pi(r4), beta_pi(r5) + (for the e_1-e_1 interaction type) +* Line 2: beta_pi(r6), beta_pi(r7), beta_pi(r8), beta_pi(r9), + beta_pi(r10) (this continues until nr) * ... -* Line nr/5+1: beta\_pi(r1), beta\_pi(r2), beta\_pi(r3), beta\_pi(r4), - beta\_pi(r5) (for the e\_1-e\_2 interaction type) +* Line nr/5+1: beta_pi(r1), beta_pi(r2), beta_pi(r3), beta_pi(r4), + beta_pi(r5) (for the e_1-e_2 interaction type) The next section contains a block for each interaction type for the -THETA\_(S,ij)((THETA\_(sigma,ij))\^(1/2), f\_(sigma,ij)). Each block has +THETA_(S,ij)((THETA_(sigma,ij))\^(1/2), f_(sigma,ij)). Each block has nBOt entries with 5 entries per line. -* Line 1: THETA\_(S,ij)(r1), THETA\_(S,ij)(r2), THETA\_(S,ij)(r3), - THETA\_(S,ij)(r4), THETA\_(S,ij)(r5) (for the e\_1-e\_2 interaction type) -* Line 2: THETA\_(S,ij)(r6), THETA\_(S,ij)(r7), THETA\_(S,ij)(r8), - THETA\_(S,ij)(r9), THETA\_(S,ij)(r10) (this continues until nBOt) +* Line 1: THETA_(S,ij)(r1), THETA_(S,ij)(r2), THETA_(S,ij)(r3), + THETA_(S,ij)(r4), THETA_(S,ij)(r5) (for the e_1-e_2 interaction type) +* Line 2: THETA_(S,ij)(r6), THETA_(S,ij)(r7), THETA_(S,ij)(r8), + THETA_(S,ij)(r9), THETA_(S,ij)(r10) (this continues until nBOt) * ... -* Line nBOt/5+1: THETA\_(S,ij)(r1), THETA\_(S,ij)(r2), THETA\_(S,ij)(r3), - THETA\_(S,ij)(r4), THETA\_(S,ij)(r5) (for the e\_1-e\_2 interaction type) +* Line nBOt/5+1: THETA_(S,ij)(r1), THETA_(S,ij)(r2), THETA_(S,ij)(r3), + THETA_(S,ij)(r4), THETA_(S,ij)(r5) (for the e_1-e_2 interaction type) -The next section contains a block of N lines for e\_1-e\_N +The next section contains a block of N lines for e_1-e_N -* Line 1: delta\^mu (for e\_1) -* Line 2: delta\^mu (for e\_2 and repeats to e\_N) +* Line 1: delta\^mu (for e_1) +* Line 2: delta\^mu (for e_2 and repeats to e_N) -The last section contains more constants for e\_i-e\_j interactions with +The last section contains more constants for e_i-e_j interactions with i=0->N, j=i->N -* Line 1: (A\_ij)\^(mu\*nu) (for e1-e1) -* Line 2: (A\_ij)\^(mu\*nu) (for e1-e2 and repeats as above) +* Line 1: (A_ij)\^(mu\*nu) (for e1-e1) +* Line 2: (A_ij)\^(mu\*nu) (for e1-e2 and repeats as above) ---------- @@ -274,34 +274,34 @@ the tabulated functions are given. * Line 1: nr, ntheta, nBOt (nr is the number of divisions the radius is broken into for function tables and MUST be a factor of 5; ntheta is the power of the power of the spline used to fit the angular function; nBOt is the number - of divisions for the tabulated values of THETA\_(S,ij) -* Line 2: delta\_1-delta\_7 (if all are not used in the particular + of divisions for the tabulated values of THETA_(S,ij) +* Line 2: delta_1-delta_7 (if all are not used in the particular * formulation, set unused values to 0.0) -Following this N lines for e\_1-e\_N containing p\_pi. +Following this N lines for e_1-e_N containing p_pi. -* Line 3: p\_pi (for e\_1) -* Line 4: p\_pi (for e\_2 and continues to e\_N) +* Line 3: p_pi (for e_1) +* Line 4: p_pi (for e_2 and continues to e_N) The next section contains several pair constants for the number of -interaction types e\_i-e\_j, with i=1->N, j=i->N +interaction types e_i-e_j, with i=1->N, j=i->N -* Line 1: r\_cut (for e\_1-e\_1 interactions) -* Line 2: c\_sigma, a\_sigma, c\_pi, a\_pi -* Line 3: delta\_sigma, delta\_pi -* Line 4: f\_sigma, k\_sigma, delta\_3 (This delta\_3 is similar to that of +* Line 1: r_cut (for e_1-e_1 interactions) +* Line 2: c_sigma, a_sigma, c_pi, a_pi +* Line 3: delta_sigma, delta_pi +* Line 4: f_sigma, k_sigma, delta_3 (This delta_3 is similar to that of the previous section but is interaction type dependent) The next section contains a line for each three body interaction type -e\_j-e\_i-e\_k with i=0->N, j=0->N, k=j->N +e_j-e_i-e_k with i=0->N, j=0->N, k=j->N * Line 1: g0, g1, g2... (These are coefficients for the angular spline - of the g\_(sigma,jik)(THETA\_ijk) for e\_1-e\_1-e\_1 interaction. The + of the g_(sigma,jik)(THETA_ijk) for e_1-e_1-e_1 interaction. The function can contain up to 10 term thus 10 constants. The first line can contain up to five constants. If the spline has more than five terms the second line will contain the remaining constants The following lines will then contain the constants for the remaining g0, - g1, g2... (for e\_1-e\_1-e\_2) and the other three body + g1, g2... (for e_1-e_1-e_2) and the other three body interactions The rest of the table has the same structure as the previous section @@ -327,34 +327,34 @@ the tabulated functions are given. * Line 1: nr, ntheta, nBOt (nr is the number of divisions the radius is broken into for function tables and MUST be a factor of 5; ntheta is the number of divisions for the tabulated values of the g angular function; nBOt is the number - of divisions for the tabulated values of THETA\_(S,ij) -* Line 2: delta\_1-delta\_7 (if all are not used in the particular + of divisions for the tabulated values of THETA_(S,ij) +* Line 2: delta_1-delta_7 (if all are not used in the particular * formulation, set unused values to 0.0) -Following this N lines for e\_1-e\_N containing p\_pi. +Following this N lines for e_1-e_N containing p_pi. -* Line 3: p\_pi (for e\_1) -* Line 4: p\_pi (for e\_2 and continues to e\_N) +* Line 3: p_pi (for e_1) +* Line 4: p_pi (for e_2 and continues to e_N) The next section contains several pair constants for the number of -interaction types e\_i-e\_j, with i=1->N, j=i->N +interaction types e_i-e_j, with i=1->N, j=i->N -* Line 1: r\_cut (for e\_1-e\_1 interactions) -* Line 2: c\_sigma, a\_sigma, c\_pi, a\_pi -* Line 3: delta\_sigma, delta\_pi -* Line 4: f\_sigma, k\_sigma, delta\_3 (This delta\_3 is similar to that of +* Line 1: r_cut (for e_1-e_1 interactions) +* Line 2: c_sigma, a_sigma, c_pi, a_pi +* Line 3: delta_sigma, delta_pi +* Line 4: f_sigma, k_sigma, delta_3 (This delta_3 is similar to that of the previous section but is interaction type dependent) The next section contains a line for each three body interaction type -e\_j-e\_i-e\_k with i=0->N, j=0->N, k=j->N +e_j-e_i-e_k with i=0->N, j=0->N, k=j->N -* Line 1: g(theta1), g(theta2), g(theta3), g(theta4), g(theta5) (for the e\_1-e\_1-e\_1 +* Line 1: g(theta1), g(theta2), g(theta3), g(theta4), g(theta5) (for the e_1-e_1-e_1 interaction type) * Line 2: g(theta6), g(theta7), g(theta8), g(theta9), g(theta10) (this continues until ntheta) * ... * Line ntheta/5+1: g(theta1), g(theta2), g(theta3), g(theta4), g(theta5), (for the - e\_1-e\_1-e\_2 interaction type) + e_1-e_1-e_2 interaction type) The rest of the table has the same structure as the previous section (see above). @@ -366,7 +366,7 @@ This pair style does not support the :doc:`pair_modify ` mix, shift, table, and tail options. This pair style does not write its information to :doc:`binary restart files `, since it is stored in potential files. Thus, you -need to re-specify the pair\_style and pair\_coeff commands in an input +need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the @@ -398,23 +398,23 @@ Related commands Default """"""" -non-tabulated potential file, a\_0 is non-zero. +non-tabulated potential file, a_0 is non-zero. ---------- -.. _Pettifor\_1: +.. _Pettifor_1: -**(Pettifor\_1)** D.G. Pettifor and I.I. Oleinik, Phys. Rev. B, 59, 8487 +**(Pettifor_1)** D.G. Pettifor and I.I. Oleinik, Phys. Rev. B, 59, 8487 (1999). -.. _Pettifor\_2: +.. _Pettifor_2: -**(Pettifor\_2)** D.G. Pettifor and I.I. Oleinik, Phys. Rev. Lett., 84, +**(Pettifor_2)** D.G. Pettifor and I.I. Oleinik, Phys. Rev. Lett., 84, 4124 (2000). -.. _Pettifor\_3: +.. _Pettifor_3: -**(Pettifor\_3)** D.G. Pettifor and I.I. Oleinik, Phys. Rev. B, 65, 172103 +**(Pettifor_3)** D.G. Pettifor and I.I. Oleinik, Phys. Rev. B, 65, 172103 (2002). .. _Murdick: diff --git a/doc/src/pair_born.rst b/doc/src/pair_born.rst index c517e4c301..2fa5785132 100644 --- a/doc/src/pair_born.rst +++ b/doc/src/pair_born.rst @@ -147,12 +147,12 @@ commands, or by mixing as described below: The second coefficient, rho, must be greater than zero. The last coefficient is optional. If not specified, the global A,C,D -cutoff specified in the pair\_style command is used. +cutoff specified in the pair_style command is used. For *born/coul/long*\ , *born/coul/wolf* and *born/coul/dsf* no Coulombic cutoff can be specified for an individual I,J type pair. All type pairs use the same global Coulombic cutoff specified in the -pair\_style command. +pair_style command. ---------- @@ -189,11 +189,11 @@ The *born/coul/long* pair style supports the :doc:`pair_modify ` table option to tabulate the short-range portion of the long-range Coulombic interaction. -These styles support the pair\_modify tail option for adding long-range +These styles support the pair_modify tail option for adding long-range tail corrections to energy and pressure. Thess styles writes thei information to binary :doc:`restart ` -files, so pair\_style and pair\_coeff commands do not need to be +files, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. These styles can only be used via the *pair* keyword of the :doc:`run_style respa ` command. They do not support the *inner*\ , diff --git a/doc/src/pair_brownian.rst b/doc/src/pair_brownian.rst index db4e1345ec..12566a2993 100644 --- a/doc/src/pair_brownian.rst +++ b/doc/src/pair_brownian.rst @@ -25,7 +25,7 @@ Syntax * flagfld = 0/1 to include/exclude Fast Lubrication Dynamics effects * cutinner = inner cutoff distance (distance units) * cutoff = outer cutoff for interactions (distance units) -* t\_target = target temp of the system (temperature units) +* t_target = target temp of the system (temperature units) * seed = seed for the random number generator (positive integer) * flagHI (optional) = 0/1 to include/exclude 1/r hydrodynamic interactions * flagVF (optional) = 0/1 to include/exclude volume fraction corrections in the long-range isotropic terms @@ -53,7 +53,7 @@ when dissipative lubrication forces are acting. Thus the parameters specified consistent with the settings in the lubrication pair styles. For details, refer to either of the lubrication pair styles. -The *t\_target* setting is used to specify the target temperature of +The *t_target* setting is used to specify the target temperature of the system. The random number *seed* is used to generate random numbers for the thermostatting procedure. @@ -72,7 +72,7 @@ commands, or by mixing as described below: * cutoff (distance units) The two coefficients are optional. If neither is specified, the two -cutoffs specified in the pair\_style command are used. Otherwise both +cutoffs specified in the pair_style command are used. Otherwise both must be specified. ---------- @@ -101,7 +101,7 @@ instructions on how to use the accelerated styles effectively. For atom type pairs I,J and I != J, the two cutoff distances for this pair style can be mixed. The default mix value is *geometric*\ . See -the "pair\_modify" command for details. +the "pair_modify" command for details. This pair style does not support the :doc:`pair_modify ` shift option for the energy of the pair interaction. @@ -113,7 +113,7 @@ This pair style does not support the :doc:`pair_modify ` tail option for adding long-range tail corrections to energy and pressure. -This pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the @@ -128,10 +128,10 @@ Restrictions These styles are part of the COLLOID package. They are only enabled if LAMMPS was built with that package. See the :doc:`Build package ` doc page for more info. -Only spherical monodisperse particles are allowed for pair\_style +Only spherical monodisperse particles are allowed for pair_style brownian. -Only spherical particles are allowed for pair\_style brownian/poly. +Only spherical particles are allowed for pair_style brownian/poly. Related commands """""""""""""""" diff --git a/doc/src/pair_buck.rst b/doc/src/pair_buck.rst index 512b751dd0..c0eb0ee282 100644 --- a/doc/src/pair_buck.rst +++ b/doc/src/pair_buck.rst @@ -164,7 +164,7 @@ the A,C and Coulombic cutoffs for this type pair. You cannot specify For *buck/coul/long* only the LJ cutoff can be specified since a Coulombic cutoff cannot be specified for an individual I,J type pair. All type pairs use the same global Coulombic cutoff specified in the -pair\_style command. +pair_style command. ---------- @@ -200,11 +200,11 @@ The *buck/coul/long* pair style supports the :doc:`pair_modify ` table option to tabulate the short-range portion of the long-range Coulombic interaction. -These styles support the pair\_modify tail option for adding long-range +These styles support the pair_modify tail option for adding long-range tail corrections to energy and pressure for the A,C terms in the pair interaction. -These styles write their information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +These styles write their information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. These styles can only be used via the *pair* keyword of the :doc:`run_style respa ` command. They do not support the *inner*\ , diff --git a/doc/src/pair_buck6d_coul_gauss.rst b/doc/src/pair_buck6d_coul_gauss.rst index f7f190a322..f8c5a29a32 100644 --- a/doc/src/pair_buck6d_coul_gauss.rst +++ b/doc/src/pair_buck6d_coul_gauss.rst @@ -127,7 +127,7 @@ These styles do not support the :doc:`pair_modify ` shift option for the energy. Instead the smoothing function should be applied by setting the global smoothing parameter to a value < 1.0. -These styles write their information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +These styles write their information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. Restrictions diff --git a/doc/src/pair_buck_long.rst b/doc/src/pair_buck_long.rst index 7e4e0f8200..6f1e2d83ef 100644 --- a/doc/src/pair_buck_long.rst +++ b/doc/src/pair_buck_long.rst @@ -13,14 +13,14 @@ Syntax pair_style buck/long/coul/long flag_buck flag_coul cutoff (cutoff2) -* flag\_buck = *long* or *cut* +* flag_buck = *long* or *cut* .. parsed-literal:: *long* = use Kspace long-range summation for the dispersion term 1/r\^6 *cut* = use a cutoff -* flag\_coul = *long* or *off* +* flag_coul = *long* or *off* .. parsed-literal:: @@ -52,34 +52,34 @@ instead of Lennard-Jones 12/6) and Coulombic potential, given by E = & A e^{-r / \rho} - \frac{C}{r^6} \qquad r < r_c \\ E = & \frac{C q_i q_j}{\epsilon r} \qquad r < r_c -:math:`r_c` is the cutoff. If one cutoff is specified in the pair\_style +:math:`r_c` is the cutoff. If one cutoff is specified in the pair_style command, it is used for both the Buckingham and Coulombic terms. If two cutoffs are specified, they are used as cutoffs for the Buckingham and Coulombic terms respectively. The purpose of this pair style is to capture long-range interactions resulting from both attractive 1/r\^6 Buckingham and Coulombic 1/r -interactions. This is done by use of the *flag\_buck* and *flag\_coul* +interactions. This is done by use of the *flag_buck* and *flag_coul* settings. The :ref:`Ismail ` paper has more details on when it is appropriate to include long-range 1/r\^6 interactions, using this potential. -If *flag\_buck* is set to *long*\ , no cutoff is used on the Buckingham +If *flag_buck* is set to *long*\ , no cutoff is used on the Buckingham 1/r\^6 dispersion term. The long-range portion can be calculated by using the :doc:`kspace_style ewald/disp or pppm/disp ` commands. The specified Buckingham cutoff then determines which portion of the Buckingham interactions are computed directly by the pair potential versus which part is computed in reciprocal space via -the Kspace style. If *flag\_buck* is set to *cut*\ , the Buckingham +the Kspace style. If *flag_buck* is set to *cut*\ , the Buckingham interactions are simply cutoff, as with :doc:`pair_style buck `. -If *flag\_coul* is set to *long*\ , no cutoff is used on the Coulombic +If *flag_coul* is set to *long*\ , no cutoff is used on the Coulombic interactions. The long-range portion can calculated by using any of several :doc:`kspace_style ` command options such as -*pppm* or *ewald*\ . Note that if *flag\_buck* is also set to long, then +*pppm* or *ewald*\ . Note that if *flag_buck* is also set to long, then the *ewald/disp* or *pppm/disp* Kspace style needs to be used to perform the long-range calculations for both the Buckingham and -Coulombic interactions. If *flag\_coul* is set to *off*\ , Coulombic +Coulombic interactions. If *flag_coul* is set to *off*\ , Coulombic interactions are not computed. The following coefficients must be defined for each pair of atoms @@ -97,14 +97,14 @@ commands: The second coefficient, rho, must be greater than zero. The latter 2 coefficients are optional. If not specified, the global -Buckingham and Coulombic cutoffs specified in the pair\_style command +Buckingham and Coulombic cutoffs specified in the pair_style command are used. If only one cutoff is specified, it is used as the cutoff for both Buckingham and Coulombic interactions for this type pair. If both coefficients are specified, they are used as the Buckingham and Coulombic cutoffs for this type pair. Note that if you are using -*flag\_buck* set to *long*\ , you cannot specify a Buckingham cutoff for +*flag_buck* set to *long*\ , you cannot specify a Buckingham cutoff for an atom type pair, since only one global Buckingham cutoff is allowed. -Similarly, if you are using *flag\_coul* set to *long*\ , you cannot +Similarly, if you are using *flag_coul* set to *long*\ , you cannot specify a Coulombic cutoff for an atom type pair, since only one global Coulombic cutoff is allowed. @@ -137,7 +137,7 @@ I,J pairs must be specified explicitly. This pair style supports the :doc:`pair_modify ` shift option for the energy of the exp() and 1/r\^6 portion of the pair -interaction, assuming *flag\_buck* is *cut*\ . +interaction, assuming *flag_buck* is *cut*\ . This pair style does not support the :doc:`pair_modify ` shift option for the energy of the Buckingham portion of the pair @@ -147,7 +147,7 @@ This pair style supports the :doc:`pair_modify ` table and table/disp options since they can tabulate the short-range portion of the long-range Coulombic and dispersion interactions. -This pair style write its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style write its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. This pair style supports the use of the *inner*\ , *middle*\ , and *outer* diff --git a/doc/src/pair_charmm.rst b/doc/src/pair_charmm.rst index c9746a58d0..031e6e6717 100644 --- a/doc/src/pair_charmm.rst +++ b/doc/src/pair_charmm.rst @@ -180,7 +180,7 @@ used in the *charmmfsw* and *charmmfsh* styles. When using the *lj/charmm/coul/charmm styles*\ , both the LJ and Coulombic terms require an inner and outer cutoff. They can be the same for both formulas or different depending on whether 2 or 4 -arguments are used in the pair\_style command. For the +arguments are used in the pair_style command. For the *lj/charmmfsw/coul/charmmfsh* style, the LJ term requires both an inner and outer cutoff, while the Coulombic term requires only one cutoff. If the Coulombic cutoff is not specified (2 instead of 3 @@ -206,7 +206,7 @@ factor is applied to the Coulombic term, so it can be used in conjunction with the :doc:`kspace_style ` command and its *ewald* or *pppm* or *msm* option. Only one Coulombic cutoff is specified for these styles; if only 2 arguments are used in the -pair\_style command, then the outer LJ cutoff is used as the single +pair_style command, then the outer LJ cutoff is used as the single Coulombic cutoff. The Coulombic cutoff specified for these styles means that pairwise interactions within this distance are computed directly; interactions outside that distance are computed in @@ -231,7 +231,7 @@ are used in the LJ formula between 2 atoms of these types which are also first and fourth atoms in any dihedral. No cutoffs are specified because the CHARMM force field does not allow varying cutoffs for individual atom pairs; all pairs use the global cutoff(s) specified in -the pair\_style command. +the pair_style command. ---------- @@ -257,10 +257,10 @@ instructions on how to use the accelerated styles effectively. **Mixing, shift, table, tail correction, restart, rRESPA info**\ : -For atom type pairs I,J and I != J, the epsilon, sigma, epsilon\_14, -and sigma\_14 coefficients for all of the lj/charmm pair styles can be +For atom type pairs I,J and I != J, the epsilon, sigma, epsilon_14, +and sigma_14 coefficients for all of the lj/charmm pair styles can be mixed. The default mix value is *arithmetic* to coincide with the -usual settings for the CHARMM force field. See the "pair\_modify" +usual settings for the CHARMM force field. See the "pair_modify" command for details. None of the *lj/charmm* or *lj/charmmfsw* pair styles support the @@ -278,8 +278,8 @@ corrections to energy and pressure, since the Lennard-Jones portion of the pair interaction is smoothed to 0.0 at the cutoff. All of the *lj/charmm* and *lj/charmmfsw* pair styles write their -information to :doc:`binary restart files `, so pair\_style and -pair\_coeff commands do not need to be specified in an input script +information to :doc:`binary restart files `, so pair_style and +pair_coeff commands do not need to be specified in an input script that reads a restart file. The *lj/charmm/coul/long* and *lj/charmmfsw/coul/long* pair styles @@ -287,7 +287,7 @@ support the use of the *inner*\ , *middle*\ , and *outer* keywords of the :doc:`run_style respa ` command, meaning the pairwise forces can be partitioned by distance at different levels of the rRESPA hierarchy. The other styles only support the *pair* keyword of -run\_style respa. See the :doc:`run_style ` command for +run_style respa. See the :doc:`run_style ` command for details. ---------- diff --git a/doc/src/pair_class2.rst b/doc/src/pair_class2.rst index d279370791..d1c673ab97 100644 --- a/doc/src/pair_class2.rst +++ b/doc/src/pair_class2.rst @@ -114,11 +114,11 @@ Coulombic terms. For *lj/class2/coul/long* only the class 2 cutoff can be specified since a Coulombic cutoff cannot be specified for an individual I,J type pair. All type pairs use the same global Coulombic cutoff -specified in the pair\_style command. +specified in the pair_style command. ---------- -If the pair\_coeff command is not used to define coefficients for a +If the pair_coeff command is not used to define coefficients for a particular I != J type pair, the mixing rule for :math:`\epsilon` and :math:`\sigma` for all class2 potentials is to use the *sixthpower* formulas documented by the :doc:`pair_modify ` command. @@ -160,8 +160,8 @@ instructions on how to use the accelerated styles effectively. For atom type pairs I,J and I != J, the epsilon and sigma coefficients and cutoff distance for all of the lj/class2 pair styles can be mixed. Epsilon and sigma are always mixed with the value *sixthpower*\ . The -cutoff distance is mixed by whatever option is set by the pair\_modify -command (default = geometric). See the "pair\_modify" command for +cutoff distance is mixed by whatever option is set by the pair_modify +command (default = geometric). See the "pair_modify" command for details. All of the lj/class2 pair styles support the @@ -177,13 +177,13 @@ All of the lj/class2 pair styles support the tail correction to the energy and pressure of the Lennard-Jones portion of the pair interaction. -All of the lj/class2 pair styles write their information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do +All of the lj/class2 pair styles write their information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. Only the *lj/class2* and *lj/class2/coul/long* pair styles support the use of the *inner*\ , *middle*\ , and *outer* keywords of the :doc:`run_style respa ` command, meaning the pairwise forces can be partitioned by distance at different levels of the rRESPA hierarchy. -The other styles only support the *pair* keyword of run\_style respa. +The other styles only support the *pair* keyword of run_style respa. See the :doc:`run_style ` command for details. Restrictions diff --git a/doc/src/pair_coeff.rst b/doc/src/pair_coeff.rst index 8ebb15b173..26910c1746 100644 --- a/doc/src/pair_coeff.rst +++ b/doc/src/pair_coeff.rst @@ -49,7 +49,7 @@ types from 1 to N. A leading asterisk means all types from 1 to n (inclusive). Note that only type pairs with I <= J are considered; if asterisks imply type pairs where J < I, they are ignored. -Note that a pair\_coeff command can override a previous setting for the +Note that a pair_coeff command can override a previous setting for the same I,J pair. For example, these commands set the coeffs for all I,J pairs, then overwrite the coeffs for just the I,J = 2,3 pair: @@ -59,7 +59,7 @@ pairs, then overwrite the coeffs for just the I,J = 2,3 pair: pair_coeff 2 3 2.0 1.0 1.12 A line in a data file that specifies pair coefficients uses the exact -same format as the arguments of the pair\_coeff command in an input +same format as the arguments of the pair_coeff command in an input script, with the exception of the I,J type arguments. In each line of the "Pair Coeffs" section of a data file, only a single type I is specified, which sets the coefficients for type I interacting with @@ -74,28 +74,28 @@ as 2 1.0 1.0 2.5 For many potentials, if coefficients for type pairs with I != J are -not set explicitly by a pair\_coeff command, the values are inferred +not set explicitly by a pair_coeff command, the values are inferred from the I,I and J,J settings by mixing rules; see the :doc:`pair_modify ` command for a discussion. Details on this option as it pertains to individual potentials are described on the doc page for the potential. Many pair styles, typically for many-body potentials, use tabulated -potential files as input, when specifying the pair\_coeff command. +potential files as input, when specifying the pair_coeff command. Potential files provided with LAMMPS are in the potentials directory of the distribution. For some potentials, such as EAM, other archives of suitable files can be found on the Web. They can be used with LAMMPS so long as they are in the format LAMMPS expects, as discussed on the individual doc pages. -When a pair\_coeff command using a potential file is specified, LAMMPS +When a pair_coeff command using a potential file is specified, LAMMPS looks for the potential file in 2 places. First it looks in the location specified. E.g. if the file is specified as "niu3.eam", it is looked for in the current working directory. If it is specified as "../potentials/niu3.eam", then it is looked for in the potentials directory, assuming it is a sister directory of the current working directory. If the file is not found, it is then looked for in the -directory specified by the LAMMPS\_POTENTIALS environment variable. +directory specified by the LAMMPS_POTENTIALS environment variable. Thus if this is set to the potentials directory in the LAMMPS distribution, then you can use those files from anywhere on your system, without copying them into your working directory. Environment variables are @@ -127,7 +127,7 @@ The alphabetic list of pair styles defined in LAMMPS is given on the compact form on the :doc:`Commands pair ` doc page. Click on the style to display the formula it computes and its -coefficients as specified by the associated pair\_coeff command. +coefficients as specified by the associated pair_coeff command. ---------- diff --git a/doc/src/pair_colloid.rst b/doc/src/pair_colloid.rst index 453a42a974..d9f086059d 100644 --- a/doc/src/pair_colloid.rst +++ b/doc/src/pair_colloid.rst @@ -137,12 +137,12 @@ particle of size :math:`\sigma`. If either d1 = 0 or d2 = 0 and the other is larger, then the pair interacts via the colloid-solvent formula. Note that the diameter of a particular particle type may appear in -multiple pair\_coeff commands, as it interacts with other particle +multiple pair_coeff commands, as it interacts with other particle types. You should insure the particle diameter is specified consistently each time it appears. The last coefficient is optional. If not specified, the global cutoff -specified in the pair\_style command is used. However, you typically +specified in the pair_style command is used. However, you typically want different cutoffs for interactions between different particle sizes. E.g. if colloidal particles of diameter 10 are used with solvent particles of diameter 1, then a solvent-solvent cutoff of 2.5 @@ -153,7 +153,7 @@ colloid-solvent cutoff in this case. .. note:: - When using pair\_style colloid for a mixture with 2 (or more) + When using pair_style colloid for a mixture with 2 (or more) widely different particles sizes (e.g. sigma=10 colloids in a background sigma=1 LJ fluid), you will likely want to use these commands for efficiency: :doc:`neighbor multi ` and @@ -187,7 +187,7 @@ For atom type pairs I,J and I != J, the A, sigma, d1, and d2 coefficients and cutoff distance for this pair style can be mixed. A is an energy value mixed like a LJ epsilon. D1 and d2 are distance values and are mixed like sigma. The default mix value is -*geometric*\ . See the "pair\_modify" command for details. +*geometric*\ . See the "pair_modify" command for details. This pair style supports the :doc:`pair_modify ` shift option for the energy of the pair interaction. @@ -199,7 +199,7 @@ This pair style does not support the :doc:`pair_modify ` tail option for adding long-range tail corrections to energy and pressure. -This pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the @@ -216,14 +216,14 @@ LAMMPS was built with that package. See the :doc:`Build package Normally, this pair style should be used with finite-size particles which have a diameter, e.g. see the :doc:`atom_style sphere ` command. However, this is not a requirement, -since the only definition of particle size is via the pair\_coeff +since the only definition of particle size is via the pair_coeff parameters for each type. In other words, the physical radius of the particle is ignored. Thus you should insure that the d1,d2 parameters you specify are consistent with the physical size of the particles of that type. Per-particle polydispersity is not yet supported by this pair style; -only per-type polydispersity is enabled via the pair\_coeff parameters. +only per-type polydispersity is enabled via the pair_coeff parameters. Related commands """""""""""""""" diff --git a/doc/src/pair_comb.rst b/doc/src/pair_comb.rst index faddf42e70..a03bc3fffe 100644 --- a/doc/src/pair_comb.rst +++ b/doc/src/pair_comb.rst @@ -67,16 +67,16 @@ that determine how often charge equilibration is performed, its convergence criterion, and which atoms are included in the calculation. -Only a single pair\_coeff command is used with the *comb* and *comb3* +Only a single pair_coeff command is used with the *comb* and *comb3* styles which specifies the COMB potential file with parameters for all needed elements. These are mapped to LAMMPS atom types by specifying -N additional arguments after the potential file in the pair\_coeff +N additional arguments after the potential file in the pair_coeff command, where N is the number of LAMMPS atom types. For example, if your LAMMPS simulation of a Si/SiO2/ HfO2 interface has 4 atom types, and you want the 1st and last to be Si, the 2nd to be Hf, and the 3rd to be O, and you would -use the following pair\_coeff command: +use the following pair_coeff command: .. code-block:: LAMMPS @@ -129,12 +129,12 @@ For style *comb3*\ , in addition to ffield.comb3, a special parameter file, *lib.comb3*\ , that is exclusively used for C/O/H systems, will be automatically loaded if carbon atom is detected in LAMMPS input structure. This file must be in your working directory or in the -directory pointed to by the environment variable LAMMPS\_POTENTIALS, as +directory pointed to by the environment variable LAMMPS_POTENTIALS, as described on the :doc:`pair_coeff ` command doc page. Keyword *polar* indicates whether the force field includes the atomic polarization. Since the equilibration of the polarization -has not yet been implemented, it can only set polar\_off at present. +has not yet been implemented, it can only set polar_off at present. .. note:: @@ -173,7 +173,7 @@ These pair styles does not support the :doc:`pair_modify ` shift, table, and tail options. These pair styles do not write its information to :doc:`binary restart files `, since it is stored in potential files. Thus, you -need to re-specify the pair\_style, pair\_coeff, and :doc:`fix qeq/comb ` commands in an input script that reads a +need to re-specify the pair_style, pair_coeff, and :doc:`fix qeq/comb ` commands in an input script that reads a restart file. These pair styles can only be used via the *pair* keyword of the diff --git a/doc/src/pair_cosine_squared.rst b/doc/src/pair_cosine_squared.rst index 4669985db9..4f19ddd1e4 100644 --- a/doc/src/pair_cosine_squared.rst +++ b/doc/src/pair_cosine_squared.rst @@ -54,7 +54,7 @@ between two point particles, where (:math:`\sigma, -\epsilon`) is the location of the (rightmost) minimum of the potential, as explained in the syntax section above. -This potential was first used in (Cooke)\_#CKD for a coarse-grained lipid +This potential was first used in (Cooke)_#CKD for a coarse-grained lipid membrane model. It is generally very useful as a non-specific interaction potential because it is fully adjustable in depth and width while joining the minimum at (sigma, -epsilon) and zero at (cutoff, 0) @@ -63,7 +63,7 @@ energy calculations etc. This evidently requires *cutoff* to be larger than *sigma*\ . If the *wca* option is used then a Weeks-Chandler-Andersen potential -(Weeks)\_#WCA is added to the above specified cosine-squared potential, +(Weeks)_#WCA is added to the above specified cosine-squared potential, specifically the following: .. math:: @@ -94,7 +94,7 @@ Mixing is not supported for this style. The *shift*\ , *table* and *tail* options are not relevant for this style. -This pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. These pair styles can only be used via the *pair* keyword of the diff --git a/doc/src/pair_coul.rst b/doc/src/pair_coul.rst index 55a6b9b057..8f77a622d6 100644 --- a/doc/src/pair_coul.rst +++ b/doc/src/pair_coul.rst @@ -269,7 +269,7 @@ a massless site located a short distance away from the oxygen atom along the bisector of the HOH angle. The atomic types of the oxygen and hydrogen atoms, the bond and angle types for OH and HOH interactions, and the distance to the massless charge site are specified as -pair\_style arguments. Style *tip4p/cut* uses a global cutoff for +pair_style arguments. Style *tip4p/cut* uses a global cutoff for Coulomb interactions; style *tip4p/long* is for use with a long-range Coulombic solver (Ewald or PPPM). @@ -311,11 +311,11 @@ commands, or by mixing as described below: For *coul/cut* and *coul/debye*\ , the cutoff coefficient is optional. If it is not used (as in some of the examples above), the default -global value specified in the pair\_style command is used. +global value specified in the pair_style command is used. For *coul/long* and *coul/msm* no cutoff can be specified for an -individual I,J type pair via the pair\_coeff command. All type pairs -use the same global Coulomb cutoff specified in the pair\_style +individual I,J type pair via the pair_coeff command. All type pairs +use the same global Coulomb cutoff specified in the pair_style command. ---------- @@ -344,7 +344,7 @@ instructions on how to use the accelerated styles effectively. For atom type pairs I,J and I != J, the cutoff distance for the *coul/cut* style can be mixed. The default mix value is *geometric*\ . -See the "pair\_modify" command for details. +See the "pair_modify" command for details. The :doc:`pair_modify ` shift option is not relevant for these pair styles. @@ -357,7 +357,7 @@ These pair styles do not support the :doc:`pair_modify ` tail option for adding long-range tail corrections to energy and pressure. -These pair styles write their information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +These pair styles write their information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. These pair styles can only be used via the *pair* keyword of the diff --git a/doc/src/pair_coul_diel.rst b/doc/src/pair_coul_diel.rst index 8011137199..02ad620327 100644 --- a/doc/src/pair_coul_diel.rst +++ b/doc/src/pair_coul_diel.rst @@ -28,7 +28,7 @@ Description Style *coul/diel* computes a Coulomb correction for implicit solvent ion interactions in which the dielectric permittivity is distance dependent. -The dielectric permittivity epsilon\_D(r) connects to limiting regimes: +The dielectric permittivity epsilon_D(r) connects to limiting regimes: One limit is defined by a small dielectric permittivity (close to vacuum) at or close to contact separation between the ions. At larger separations the dielectric permittivity reaches a bulk value used in the regular Coulomb @@ -43,9 +43,9 @@ in the Coulomb correction term for small ion separations as follows where :math:`r_{me}` is the inflection point of :math:`\epsilon_D(r)` and :math:`\sigma_e` is a slope defining length scale. C is the same Coulomb conversion factor as in the -pair\_styles coul/cut, coul/long, and coul/debye. In this way the Coulomb +pair_styles coul/cut, coul/long, and coul/debye. In this way the Coulomb interaction between ions is corrected at small distances r. The lower -limit of epsilon\_D(r->0)=5.2 due to dielectric saturation :ref:`(Stiles) ` +limit of epsilon_D(r->0)=5.2 due to dielectric saturation :ref:`(Stiles) ` while the Coulomb interaction reaches its bulk limit by setting :math:`\epsilon_D(r \to \infty) = \epsilon`, the bulk value of the solvent which is 78 for water at 298K. @@ -67,7 +67,7 @@ commands: * :math:`r_{me}` (distance units) * :math:`\sigma_e` (distance units) -The global cutoff (:math:`r_c`) specified in the pair\_style command is used. +The global cutoff (:math:`r_c`) specified in the pair_style command is used. ---------- diff --git a/doc/src/pair_coul_shield.rst b/doc/src/pair_coul_shield.rst index 14de8c773f..c9acbf40ef 100644 --- a/doc/src/pair_coul_shield.rst +++ b/doc/src/pair_coul_shield.rst @@ -11,7 +11,7 @@ Syntax pair_style coul/shield cutoff tap_flag * cutoff = global cutoff (distance units) -* tap\_flag = 0/1 to turn off/on the taper function +* tap_flag = 0/1 to turn off/on the taper function Examples """""""" @@ -58,7 +58,7 @@ each pair of atom types via the :doc:`pair_coeff ` command as in the example above, or in the data file or restart files read by the :doc:`read_data ` or :doc:`read_restart ` commands: -The global cutoff (:math:`r_c`) specified in the pair\_style command is used. +The global cutoff (:math:`r_c`) specified in the pair_style command is used. ---------- @@ -90,7 +90,7 @@ Related commands :doc:`pair_coeff ` :doc:`pair_style ilp/graphene/hbn ` -**Default:** tap\_flag = 1 +**Default:** tap_flag = 1 ---------- diff --git a/doc/src/pair_cs.rst b/doc/src/pair_cs.rst index c1aeef745e..72332a87b2 100644 --- a/doc/src/pair_cs.rst +++ b/doc/src/pair_cs.rst @@ -132,7 +132,7 @@ to 0.0, which works because the core and shell atoms are bonded to each other. This induces a long-range correction approximation which fails at small distances (~< 10e-8). Therefore, the Coulomb term which is used to calculate the correction factor is extended by a minimal -distance (r\_min = 1.0-6) when the interaction between a core/shell +distance (r_min = 1.0-6) when the interaction between a core/shell pair is treated, as follows .. math:: diff --git a/doc/src/pair_dipole.rst b/doc/src/pair_dipole.rst index 8cbc949e13..38731dcb6d 100644 --- a/doc/src/pair_dipole.rst +++ b/doc/src/pair_dipole.rst @@ -39,7 +39,7 @@ Syntax * cutoff = global cutoff LJ (and Coulombic if only 1 arg) (distance units) * cutoff2 = global cutoff for Coulombic and dipole (optional) (distance units) -* flag\_lj = *long* or *cut* or *off* +* flag_lj = *long* or *cut* or *off* .. parsed-literal:: @@ -47,7 +47,7 @@ Syntax *cut* = use a cutoff on dispersion 1/r\^6 term *off* = omit disperion 1/r\^6 term entirely -* flag\_coul = *long* or *off* +* flag_coul = *long* or *off* .. parsed-literal:: @@ -137,7 +137,7 @@ potential containing extra terms that make both the energy and its derivative go to zero at the cutoff distance; this removes (cutoff-related) problems in energy conservation and any numerical instability in the equations of motion :ref:`(Allen) `. Shifted-force -interactions for the Lennard-Jones (E\_LJ), charge-charge (Eqq), +interactions for the Lennard-Jones (E_LJ), charge-charge (Eqq), charge-dipole (Eqp), dipole-charge (Epq) and dipole-dipole (Epp) potentials are computed by these formulas for the energy (E), force (F), and torque (T) between particles I and J: @@ -221,11 +221,11 @@ been obtained by applying equation 5.13 of :ref:`(Allen) `. The formulas for the corresponding forces and torques have been obtained by applying the 'chain rule' as in appendix C.3 of :ref:`(Allen) `. -If one cutoff is specified in the pair\_style command, it is used for +If one cutoff is specified in the pair_style command, it is used for both the LJ and Coulombic (q,p) terms. If two cutoffs are specified, they are used as cutoffs for the LJ and Coulombic (q,p) terms respectively. This pair style also supports an optional *scale* keyword -as part of a pair\_coeff statement, where the interactions can be +as part of a pair_coeff statement, where the interactions can be scaled according to this factor. This scale factor is also made available for use with fix adapt. @@ -243,19 +243,19 @@ dipole-charge, and charge-charge interactions are all supported, along with the standard 12/6 Lennard-Jones interactions. LJ interactions can be cutoff or long-ranged. -For style *lj/long/dipole/long*\ , if *flag\_lj* is set to *long*\ , no +For style *lj/long/dipole/long*\ , if *flag_lj* is set to *long*\ , no cutoff is used on the LJ 1/r\^6 dispersion term. The long-range -portion is calculated by using the :doc:`kspace_style ewald\_disp ` command. The specified LJ cutoff then +portion is calculated by using the :doc:`kspace_style ewald_disp ` command. The specified LJ cutoff then determines which portion of the LJ interactions are computed directly by the pair potential versus which part is computed in reciprocal -space via the Kspace style. If *flag\_lj* is set to *cut*\ , the LJ -interactions are simply cutoff, as with :doc:`pair_style lj/cut `. If *flag\_lj* is set to *off*\ , LJ interactions +space via the Kspace style. If *flag_lj* is set to *cut*\ , the LJ +interactions are simply cutoff, as with :doc:`pair_style lj/cut `. If *flag_lj* is set to *off*\ , LJ interactions are not computed at all. -If *flag\_coul* is set to *long*\ , no cutoff is used on the Coulombic or +If *flag_coul* is set to *long*\ , no cutoff is used on the Coulombic or dipole interactions. The long-range portion is calculated by using -*ewald\_disp* of the :doc:`kspace_style ` command. If -*flag\_coul* is set to *off*\ , Coulombic and dipole interactions are not +*ewald_disp* of the :doc:`kspace_style ` command. If +*flag_coul* is set to *off*\ , Coulombic and dipole interactions are not computed at all. Atoms with dipole moments should be integrated using the :doc:`fix nve/sphere update dipole ` or the :doc:`fix nvt/sphere update dipole ` command to rotate the @@ -280,7 +280,7 @@ commands, or by mixing as described below: * cutoff2 (distance units) The latter 2 coefficients are optional. If not specified, the global -LJ and Coulombic cutoffs specified in the pair\_style command are used. +LJ and Coulombic cutoffs specified in the pair_style command are used. If only one cutoff is specified, it is used as the cutoff for both LJ and Coulombic interactions for this type pair. If both coefficients are specified, they are used as the LJ and Coulombic cutoffs for this @@ -312,13 +312,13 @@ instructions on how to use the accelerated styles effectively. For atom type pairs I,J and I != J, the epsilon and sigma coefficients and cutoff distances for this pair style can be mixed. The default -mix value is *geometric*\ . See the "pair\_modify" command for details. +mix value is *geometric*\ . See the "pair_modify" command for details. For atom type pairs I,J and I != J, the A, sigma, d1, and d2 coefficients and cutoff distance for this pair style can be mixed. A is an energy value mixed like a LJ epsilon. D1 and d2 are distance values and are mixed like sigma. The default mix value is -*geometric*\ . See the "pair\_modify" command for details. +*geometric*\ . See the "pair_modify" command for details. This pair style does not support the :doc:`pair_modify ` shift option for the energy of the Lennard-Jones portion of the pair @@ -331,7 +331,7 @@ This pair style does not support the :doc:`pair_modify ` tail option for adding long-range tail corrections to energy and pressure. -This pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_dpd.rst b/doc/src/pair_dpd.rst index 560c6f0a03..0a078585c6 100644 --- a/doc/src/pair_dpd.rst +++ b/doc/src/pair_dpd.rst @@ -81,7 +81,7 @@ difference in velocities of the two atoms :math:`= \vec{v}_i - unit variance, dt is the timestep size, and w(r) is a weighting factor that varies between 0 and 1. :math:`r_c` is the cutoff. :math:`\sigma` is set equal to :math:`\sqrt{2 k_B T \gamma}`, where :math:`k_B` is the -Boltzmann constant and T is the temperature parameter in the pair\_style +Boltzmann constant and T is the temperature parameter in the pair_style command. For style *dpd/tstat*\ , the force on atom I due to atom J is the same @@ -174,7 +174,7 @@ These pair style do not support the :doc:`pair_modify ` tail option for adding long-range tail corrections to energy and pressure. -These pair styles writes their information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +These pair styles writes their information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. Note that the user-specified random number seed is stored in the restart file, so when a simulation is restarted, each processor will diff --git a/doc/src/pair_drip.rst b/doc/src/pair_drip.rst index 5628aa6d66..1fa193777a 100644 --- a/doc/src/pair_drip.rst +++ b/doc/src/pair_drip.rst @@ -76,7 +76,7 @@ The :doc:`pair_coeff ` command for DRIP takes *4+N* arguments, where to be *\* \* drip*, the fourth argument is the path to the DRIP parameter file, and the remaining N arguments specifying the mapping between element in the parameter file and atom types. For example, if your LAMMPS simulation has 3 atom -types and you want all of them to be C, you would use the following pair\_coeff +types and you want all of them to be C, you would use the following pair_coeff command: .. code-block:: LAMMPS @@ -99,19 +99,19 @@ model H atoms: The potential parameters developed in :ref:`(Wen) ` are provided with LAMMPS (see the "potentials" directory). Besides those in :ref:`Wen `, an - additional parameter "normal\_cutoff", specific to the LAMMPS implementation, is + additional parameter "normal_cutoff", specific to the LAMMPS implementation, is used to find the three nearest neighbors of an atom to construct the normal. ---------- **Mixing, shift, table, tail correction, and restart info**\ : -This pair style does not support the pair\_modify mix, shift, table, +This pair style does not support the pair_modify mix, shift, table, and tail options. This pair style does not write their information to binary restart files, since -it is stored in potential files. Thus, you need to re-specify the pair\_style and -pair\_coeff commands in an input script that reads a restart file. +it is stored in potential files. Thus, you need to re-specify the pair_style and +pair_coeff commands in an input script that reads a restart file. Restrictions """""""""""" @@ -132,7 +132,7 @@ simulation doesn't use "metal" units. Related commands """""""""""""""" -:doc:`pair_style lebedeva\_z `, +:doc:`pair_style lebedeva_z `, :doc:`pair_style kolmogorov/crespi/z `, :doc:`pair_style kolmogorov/crespi/full `, :doc:`pair_style ilp/graphene/hbn `. diff --git a/doc/src/pair_dsmc.rst b/doc/src/pair_dsmc.rst index daf63a3752..03f6505d47 100644 --- a/doc/src/pair_dsmc.rst +++ b/doc/src/pair_dsmc.rst @@ -10,12 +10,12 @@ Syntax pair_style dsmc max_cell_size seed weighting Tref Nrecompute Nsample -* max\_cell\_size = global maximum cell size for DSMC interactions (distance units) +* max_cell_size = global maximum cell size for DSMC interactions (distance units) * seed = random # seed (positive integer) * weighting = macroparticle weighting * Tref = reference temperature (temperature units) -* Nrecompute = re-compute v\*sigma\_max every this many timesteps (timesteps) -* Nsample = sample this many times in recomputing v\*sigma\_max +* Nrecompute = re-compute v\*sigma_max every this many timesteps (timesteps) +* Nsample = sample this many times in recomputing v\*sigma_max Examples """""""" @@ -34,13 +34,13 @@ direct simulation Monte Carlo (DSMC) model following the exposition in :ref:`(Bird) `. Each collision resets the velocities of the two particles involved. The number of pairwise collisions for each pair or particle types and the length scale within which they occur are -determined by the parameters of the pair\_style and pair\_coeff +determined by the parameters of the pair_style and pair_coeff commands. Stochastic collisions are performed using the variable hard sphere -(VHS) approach, with the user-defined *max\_cell\_size* value used as +(VHS) approach, with the user-defined *max_cell_size* value used as the maximum DSMC cell size, and reference cross-sections for -collisions given using the pair\_coeff command. +collisions given using the pair_coeff command. There is no pairwise energy or virial contributions associated with this pair style. @@ -53,7 +53,7 @@ commands: * sigma (area units, i.e. distance-squared) -The global DSMC *max\_cell\_size* determines the maximum cell length +The global DSMC *max_cell_size* determines the maximum cell length used in the DSMC calculation. A structured mesh is overlayed on the simulation box such that an integer number of cells are created in each direction for each processor's sub-domain. Cell lengths are @@ -119,7 +119,7 @@ This pair style does not support the :doc:`pair_modify ` tail option for adding long-range tail corrections to energy and pressure. -This pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. Note that the user-specified random number seed is stored in the restart file, so when a simulation is restarted, each processor will diff --git a/doc/src/pair_e3b.rst b/doc/src/pair_e3b.rst index 08fd7bc56f..68f8708b27 100644 --- a/doc/src/pair_e3b.rst +++ b/doc/src/pair_e3b.rst @@ -69,7 +69,7 @@ The *e3b* style computes an \"explicit three-body\" (E3B) potential for water :r \end{cases} This potential was developed as a water model that includes the three-body cooperativity of hydrogen bonding explicitly. -To use it in this way, it must be applied in conjunction with a conventional two-body water model, through *pair\_style hybrid/overlay*. +To use it in this way, it must be applied in conjunction with a conventional two-body water model, through *pair_style hybrid/overlay*. The three body interactions are split into three types: A, B, and C. Type A corresponds to anti-cooperative double hydrogen bond donor interactions. Type B corresponds to the cooperative interaction of molecules that both donate and accept a hydrogen bond. @@ -79,9 +79,9 @@ The two-body interactions are designed to correct for the effective many-body in The two-body interactions are cut off sharply at Rc2, because K3 is typically significantly smaller than K2. See :ref:`(Kumar 2008) ` for more details. -Only a single *pair\_coeff* command is used with the *e3b* style. +Only a single *pair_coeff* command is used with the *e3b* style. The 1st two arguments must be \* \*. -The oxygen atom type for the pair style is passed as the only argument to the *pair\_style* command, not in the *pair\_coeff* command. +The oxygen atom type for the pair style is passed as the only argument to the *pair_style* command, not in the *pair_coeff* command. The hydrogen atom type is inferred by the ordering of the atoms. .. note:: @@ -90,14 +90,14 @@ The hydrogen atom type is inferred by the ordering of the atoms. Each water molecule must have consecutive IDs with the oxygen first. This pair style does not test that this criteria is met. -The *pair\_coeff* command must have at least one keyword/value pair, as described above. +The *pair_coeff* command must have at least one keyword/value pair, as described above. The *preset* keyword sets the potential parameters to the values used in :ref:`(Tainter 2011) ` or :ref:`(Tainter 2015) `. -To use the water models defined in those references, the *e3b* style should always be used in conjunction with an *lj/cut/tip4p/long* style through *pair\_style hybrid/overlay*, as demonstrated in the second example above. +To use the water models defined in those references, the *e3b* style should always be used in conjunction with an *lj/cut/tip4p/long* style through *pair_style hybrid/overlay*, as demonstrated in the second example above. The *preset 2011* option should be used with the :doc:`TIP4P water model `. The *preset 2015* option should be used with the :doc:`TIP4P/2005 water model `. If the *preset* keyword is used, no other keyword is needed. Changes to the preset parameters can be made by specifying the *preset* keyword followed by the specific parameter to change, like *Ea*\ . -Note that the other keywords must come after *preset* in the pair\_style command. +Note that the other keywords must come after *preset* in the pair_style command. The *e3b* style can also be used to implement any three-body potential of the same form by specifying all the keywords except *neigh*\ : *Ea*\ , *Eb*\ , *Ec*\ , *E2*\ , *K3*\ , *K2*\ , *Rc3*\ , *Rc2*\ , *Rs*\ , and *bondL*\ . The keyword *bondL* specifies the intramolecular OH bond length of the water model being used. This is needed to include H atoms that are within the cutoff even when the attached oxygen atom is not. @@ -121,7 +121,7 @@ This pair style does not support the :doc:`pair_modify ` shift, table, and tail options. This pair style does not write its information to :doc:`binary restart files `. Thus, you -need to re-specify the pair\_style and pair\_coeff commands in an input +need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style is incompatible with :doc:`respa `. @@ -138,7 +138,7 @@ This pair style requires the :doc:`newton ` setting to be "on" for pair interactions. This pair style requires a fixed number of atoms in the simulation, so it is incompatible with fixes like :doc:`fix deposit `. -If the number of atoms changes between runs, this pair style must be re-initialized by calling the *pair\_style* and *pair\_coeffs* commands. +If the number of atoms changes between runs, this pair style must be re-initialized by calling the *pair_style* and *pair_coeffs* commands. This is not a fundamental limitation of the pair style, but the code currently does not support a variable number of atoms. The *preset* keyword currently only works with real, metal, si, and cgs :doc:`units `. diff --git a/doc/src/pair_eam.rst b/doc/src/pair_eam.rst index 8c3db11687..4710f8a9a1 100644 --- a/doc/src/pair_eam.rst +++ b/doc/src/pair_eam.rst @@ -136,7 +136,7 @@ are parameterized in terms of LAMMPS :doc:`metal units `. .. note:: Note that unlike for other potentials, cutoffs for EAM - potentials are not set in the pair\_style or pair\_coeff command; they + potentials are not set in the pair_style or pair_coeff command; they are specified in the EAM potential files themselves. Likewise, the EAM potential files list atomic masses; thus you do not need to use the :doc:`mass ` command to specify them. @@ -164,11 +164,11 @@ by a Fortran program, it cannot have "D" values in it for exponents. C only recognizes "e" or "E" for scientific notation. Note that unlike for other potentials, cutoffs for EAM potentials are -not set in the pair\_style or pair\_coeff command; they are specified in +not set in the pair_style or pair_coeff command; they are specified in the EAM potential files themselves. For style *eam* a potential file must be assigned to each I,I pair of -atom types by using one or more pair\_coeff commands, each with a +atom types by using one or more pair_coeff commands, each with a single argument: * filename @@ -249,21 +249,21 @@ DYNAMO file was created by a Fortran program, it cannot have "D" values in it for exponents. C only recognizes "e" or "E" for scientific notation. -Only a single pair\_coeff command is used with the *eam/alloy* style +Only a single pair_coeff command is used with the *eam/alloy* style which specifies a DYNAMO *setfl* file, which contains information for M elements. These are mapped to LAMMPS atom types by specifying N -additional arguments after the filename in the pair\_coeff command, +additional arguments after the filename in the pair_coeff command, where N is the number of LAMMPS atom types: * filename * N element names = mapping of *setfl* elements to atom types -As an example, the potentials/NiAlH\_jea.eam.alloy file is a *setfl* +As an example, the potentials/NiAlH_jea.eam.alloy file is a *setfl* file which has tabulated EAM values for 3 elements and their alloy interactions: Ni, Al, and H. See the :doc:`pair_coeff ` doc page for alternate ways to specify the path for the potential file. If your LAMMPS simulation has 4 atoms types and you want the 1st 3 to -be Ni, and the 4th to be Al, you would use the following pair\_coeff +be Ni, and the 4th to be Al, you would use the following pair_coeff command: .. code-block:: LAMMPS @@ -332,7 +332,7 @@ of mixing of alloys over the full composition range, as described in :ref:`(Stukowski) `. Style *eam/cd/old* is an older, slightly different and slower two-site formulation of the model :ref:`(Caro) `. -The pair\_coeff command is specified the same as for the *eam/alloy* +The pair_coeff command is specified the same as for the *eam/alloy* style. However the DYNAMO *setfl* file must has two lines added to it, at the end of the file: @@ -373,7 +373,7 @@ element at that atomic site. The associated :doc:`pair_coeff ` command for style *eam/fs* reads a DYNAMO *setfl* file that has been extended to include -additional rho\_alpha\_beta arrays of tabulated values. A discussion of +additional rho_alpha_beta arrays of tabulated values. A discussion of how FS EAM differs from conventional EAM alloy potentials is given in :ref:`(Ackland1) `. An example of such a potential is the same author's Fe-P FS potential :ref:`(Ackland2) `. Note that while FS @@ -382,7 +382,7 @@ dependence on the total density, the implementation in LAMMPS does not require that; the user can tabulate any functional form desired in the FS potential files. -For style *eam/fs*\ , the form of the pair\_coeff command is exactly the +For style *eam/fs*\ , the form of the pair_coeff command is exactly the same as for style *eam/alloy*\ , e.g. .. code-block:: LAMMPS @@ -461,13 +461,13 @@ instructions on how to use the accelerated styles effectively. For atom type pairs I,J and I != J, where types I and J correspond to two different element types, mixing is performed by LAMMPS as described above with the individual styles. You never need to specify -a pair\_coeff command with I != J arguments for the eam styles. +a pair_coeff command with I != J arguments for the eam styles. This pair style does not support the :doc:`pair_modify ` shift, table, and tail options. The eam pair styles do not write their information to :doc:`binary restart files `, since it is stored in tabulated potential files. -Thus, you need to re-specify the pair\_style and pair\_coeff commands in +Thus, you need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. The eam pair styles can only be used via the *pair* keyword of the diff --git a/doc/src/pair_edip.rst b/doc/src/pair_edip.rst index 0e8a4aab59..02f779bebf 100644 --- a/doc/src/pair_edip.rst +++ b/doc/src/pair_edip.rst @@ -59,10 +59,10 @@ local environment of atom I through its effective coordination number defined by Z, which is unity for a cutoff distance < c and gently goes to 0 at distance = a. -Only a single pair\_coeff command is used with the *edip* style which +Only a single pair_coeff command is used with the *edip* style which specifies a EDIP potential file with parameters for all needed elements. These are mapped to LAMMPS atom types by specifying -N additional arguments after the filename in the pair\_coeff command, +N additional arguments after the filename in the pair_coeff command, where N is the number of LAMMPS atom types: * filename @@ -106,7 +106,7 @@ for three-body interactions. The alpha and cutoffC parameters are used for the coordination environment function only. The EDIP potential file must contain entries for all the -elements listed in the pair\_coeff command. It can also contain +elements listed in the pair_coeff command. It can also contain entries for additional elements not being used in a particular simulation; LAMMPS ignores those entries. @@ -151,7 +151,7 @@ This pair style does not support the :doc:`pair_modify ` shift, table, and tail options. This pair style does not write its information to :doc:`binary restart files `, since it is stored in potential files. Thus, you -need to re-specify the pair\_style and pair\_coeff commands in an input +need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_eff.rst b/doc/src/pair_eff.rst index 6726dee2f9..f163e5afaa 100644 --- a/doc/src/pair_eff.rst +++ b/doc/src/pair_eff.rst @@ -89,9 +89,9 @@ electronically excited and ionized states of matter can occur and coexist. Furthermore, the interactions between particles -nuclei and electrons- reduce to the sum of a set of effective pairwise potentials in the eFF formulation. The *eff/cut* style computes the pairwise -Coulomb interactions between nuclei and electrons (E\_NN,E\_Ne,E\_ee), -and the quantum-derived Pauli (E\_PR) and Kinetic energy interactions -potentials between electrons (E\_KE) for a total energy expression +Coulomb interactions between nuclei and electrons (E_NN,E_Ne,E_ee), +and the quantum-derived Pauli (E_PR) and Kinetic energy interactions +potentials between electrons (E_KE) for a total energy expression given as, .. math:: @@ -108,10 +108,10 @@ The individual terms are defined as follows: E_{ee} = & \frac{1}{{4\pi \varepsilon _0 }}\sum\limits_{i < j} {\frac{1}{{r_{ij} }}Erf\left( {\frac{{\sqrt 2 r_{ij} }}{{\sqrt {s_i^2 + s_j^2 } }}} \right)} \\ E_{Pauli} = & \sum\limits_{\sigma _i = \sigma _j } {E\left( { \uparrow \uparrow } \right)_{ij}} + \sum\limits_{\sigma _i \ne \sigma _j } {E\left( { \uparrow \downarrow } \right)_{ij}} \\ -where, s\_i correspond to the electron sizes, the sigmas i's to the -fixed spins of the electrons, Z\_i to the charges on the nuclei, R\_ij +where, s_i correspond to the electron sizes, the sigmas i's to the +fixed spins of the electrons, Z_i to the charges on the nuclei, R_ij to the distances between the nuclei or the nuclei and electrons, and -r\_ij to the distances between electrons. For additional details see +r_ij to the distances between electrons. For additional details see :ref:`(Jaramillo-Botero) `. The overall electrostatics energy is given in Hartree units of energy @@ -143,11 +143,11 @@ commands, or by mixing as described below: For *eff/cut*\ , the cutoff coefficient is optional. If it is not used (as in some of the examples above), the default global value specified -in the pair\_style command is used. +in the pair_style command is used. For *eff/long* (not yet available) no cutoff will be specified for an individual I,J type pair via the :doc:`pair_coeff ` command. -All type pairs use the same global cutoff specified in the pair\_style +All type pairs use the same global cutoff specified in the pair_style command. ---------- @@ -160,7 +160,7 @@ becoming excessively diffuse at very high temperatures were the Gaussian wave packet representation breaks down, and from expanding as free particles to infinite size. If unset, electron radius is free to increase without bounds. If set, a restraining harmonic potential of -the form E = 1/2k\_ss\^2 for s > L\_box/2, where k\_s = 1 Hartrees/Bohr\^2, +the form E = 1/2k_ss\^2 for s > L_box/2, where k_s = 1 Hartrees/Bohr\^2, is applied on the electron radius. The *pressure/evirials* keyword is used to control between two types @@ -179,7 +179,7 @@ representations, after the "ecp" keyword. .. note:: Default ECP parameters are provided for C, N, O, Al, and Si. - Users can modify these using the pair\_coeff command as exemplified + Users can modify these using the pair_coeff command as exemplified above. For this, the User must distinguish between two different functional forms supported, one that captures the orbital overlap assuming the s-type core interacts with an s-like valence electron @@ -191,7 +191,7 @@ representations, after the "ecp" keyword. .. note:: there are two different pressures that can be reported for eFF - when defining this pair\_style, one (default) that considers electrons + when defining this pair_style, one (default) that considers electrons do not contribute radial virial components (i.e. electrons treated as incompressible 'rigid' spheres) and one that does. The radial electronic contributions to the virials are only tallied if the @@ -264,7 +264,7 @@ dihydride. For atom type pairs I,J and I != J, the cutoff distance for the *eff/cut* style can be mixed. The default mix value is *geometric*\ . -See the "pair\_modify" command for details. +See the "pair_modify" command for details. The :doc:`pair_modify ` shift option is not relevant for these pair styles. @@ -277,7 +277,7 @@ These pair styles do not support the :doc:`pair_modify ` tail option for adding long-range tail corrections to energy and pressure. -These pair styles write their information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +These pair styles write their information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. These pair styles can only be used via the *pair* keyword of the @@ -310,7 +310,7 @@ Related commands Default """"""" -If not specified, limit\_eradius = 0 and pressure\_with\_evirials = 0. +If not specified, limit_eradius = 0 and pressure_with_evirials = 0. ---------- diff --git a/doc/src/pair_eim.rst b/doc/src/pair_eim.rst index 7eb850c5ac..bb09e10ed2 100644 --- a/doc/src/pair_eim.rst +++ b/doc/src/pair_eim.rst @@ -38,8 +38,8 @@ energy of the system E is given by The first term is a double pairwise sum over the J neighbors of all I atoms, where :math:`\phi_{ij}` is a pair potential. The second term sums over -the embedding energy E\_i of atom I, which is a function of its charge -q\_i and the electrical potential :math:`\sigma_i` at its location. E\_i, q\_i, +the embedding energy E_i of atom I, which is a function of its charge +q_i and the electrical potential :math:`\sigma_i` at its location. E_i, q_i, and :math:`sigma_i` are calculated as .. math:: @@ -77,7 +77,7 @@ atoms in the atomic pair. charge on each atom and thus requires you to assign a charge to each atom, e.g. the *charge* or *full* atom styles. This is because the EIM potential infers the charge on an atom from the equation above for - q\_i; you do not assign charges explicitly. + q_i; you do not assign charges explicitly. ---------- @@ -90,15 +90,15 @@ A system with any combination of these elements can be modeled. This file is parameterized in terms of LAMMPS :doc:`metal units `. Note that unlike other potentials, cutoffs for EIM potentials are not -set in the pair\_style or pair\_coeff command; they are specified in the +set in the pair_style or pair_coeff command; they are specified in the EIM potential file itself. Likewise, the EIM potential file lists atomic masses; thus you do not need to use the :doc:`mass ` command to specify them. -Only a single pair\_coeff command is used with the *eim* style which +Only a single pair_coeff command is used with the *eim* style which specifies an EIM potential file and the element(s) to extract information for. The EIM elements are mapped to LAMMPS atom types by -specifying N additional arguments after the filename in the pair\_coeff +specifying N additional arguments after the filename in the pair_coeff command, where N is the number of LAMMPS atom types: * Elem1, Elem2, ... @@ -111,7 +111,7 @@ to specify the path for the potential file. As an example like one of those above, suppose you want to model a system with Na and Cl atoms. If your LAMMPS simulation has 4 atoms types and you want the 1st 3 to be Na, and the 4th to be Cl, you would -use the following pair\_coeff command: +use the following pair_coeff command: .. code-block:: LAMMPS @@ -147,9 +147,9 @@ radius (LAMMPS ignores it), ionic radius (LAMMPS ignores it), cohesive energy (LAMMPS ignores it), and q0 (must be 0). Lines starting with "pair:" are entered as: element 1, element 2, -r\_(c,phi), r\_(c,phi) (redundant for historical reasons), E\_b, r\_e, -alpha, beta, r\_(c,eta), A\_(eta), r\_(s,eta), r\_(c,psi), A\_(psi), zeta, -r\_(s,psi), and p. +r_(c,phi), r_(c,phi) (redundant for historical reasons), E_b, r_e, +alpha, beta, r_(c,eta), A_(eta), r_(s,eta), r_(c,psi), A_(psi), zeta, +r_(s,psi), and p. The lines in the file can be in any order; LAMMPS extracts the info it needs. diff --git a/doc/src/pair_exp6_rx.rst b/doc/src/pair_exp6_rx.rst index 823da19ccc..7f2be1817a 100644 --- a/doc/src/pair_exp6_rx.rst +++ b/doc/src/pair_exp6_rx.rst @@ -164,7 +164,7 @@ I,J pairs must be specified explicitly. This style does not support the :doc:`pair_modify ` shift option for the energy of the exp() and 1/r\^6 portion of the pair interaction. -This style does not support the pair\_modify tail option for adding long-range +This style does not support the pair_modify tail option for adding long-range tail corrections to energy and pressure for the A,C terms in the pair interaction. diff --git a/doc/src/pair_extep.rst b/doc/src/pair_extep.rst index ab15d56d9f..8e5bc3ac9f 100644 --- a/doc/src/pair_extep.rst +++ b/doc/src/pair_extep.rst @@ -33,7 +33,7 @@ none Related commands """""""""""""""" -"pair\_tersoff" pair\_tersoff.html +"pair_tersoff" pair_tersoff.html **Default:** none diff --git a/doc/src/pair_fep_soft.rst b/doc/src/pair_fep_soft.rst index e8cef41eda..c8f7d0d7ab 100644 --- a/doc/src/pair_fep_soft.rst +++ b/doc/src/pair_fep_soft.rst @@ -242,7 +242,7 @@ or by mixing as described below: * cutoff2 (distance units) The latter two coefficients are optional. If not specified, the global -LJ and Coulombic cutoffs specified in the pair\_style command are used. +LJ and Coulombic cutoffs specified in the pair_style command are used. If only one cutoff is specified, it is used as the cutoff for both LJ and Coulombic interactions for this type pair. If both coefficients are specified, they are used as the LJ and Coulombic cutoffs for this @@ -406,7 +406,7 @@ The *morse/soft* pair style does not support the :doc:`pair_modify pressure. All of these pair styles write information to :doc:`binary restart files -`, so pair\_style and pair\_coeff commands do not need to be specified +`, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. ---------- diff --git a/doc/src/pair_gauss.rst b/doc/src/pair_gauss.rst index b1bab752df..1f183c00b9 100644 --- a/doc/src/pair_gauss.rst +++ b/doc/src/pair_gauss.rst @@ -117,22 +117,22 @@ instructions on how to use the accelerated styles effectively. **Mixing, shift, table, tail correction, restart, rRESPA info**\ : -For atom type pairs I,J and I != J, the A, B, H, sigma\_h, r\_mh +For atom type pairs I,J and I != J, the A, B, H, sigma_h, r_mh parameters, and the cutoff distance for these pair styles can be mixed: A (energy units) sqrt(1/B) (distance units, see below) H (energy units) -sigma\_h (distance units) -r\_mh (distance units) +sigma_h (distance units) +r_mh (distance units) cutoff (distance units):ul The default mix value is *geometric*\ . Only *arithmetic* and *geometric* mix values are supported. -See the "pair\_modify" command for details. +See the "pair_modify" command for details. The A and H parameters are mixed using the same rules normally used to mix the "epsilon" parameter in a Lennard Jones interaction. -The sigma\_h, r\_mh, and the cutoff distance are mixed using the same +The sigma_h, r_mh, and the cutoff distance are mixed using the same rules used to mix the "sigma" parameter in a Lennard Jones interaction. The B parameter is converted to a distance (sigma), before mixing (using sigma=B\^-0.5), and converted back to a coefficient @@ -154,7 +154,7 @@ interaction. The :doc:`pair_modify ` table and tail options are not relevant for these pair styles. -These pair styles write their information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +These pair styles write their information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. These pair styles can only be used via the *pair* keyword of the diff --git a/doc/src/pair_gayberne.rst b/doc/src/pair_gayberne.rst index 1d73c6ef8b..e6cf480852 100644 --- a/doc/src/pair_gayberne.rst +++ b/doc/src/pair_gayberne.rst @@ -98,7 +98,7 @@ commands, or by mixing as described below: * cutoff (distance units) The last coefficient is optional. If not specified, the global -cutoff specified in the pair\_style command is used. +cutoff specified in the pair_style command is used. It is typical with the Gay-Berne potential to define :math:`\sigma` as the minimum of the 3 shape diameters of the particles involved in an I,I @@ -108,7 +108,7 @@ meaning for :math:`\sigma` than the :doc:`pair_style resquared The :math:`\epsilon_i` and :math:`\epsilon_j` coefficients are actually defined for atom types, not for pairs of atom types. Thus, in a series -of pair\_coeff commands, they only need to be specified once for each +of pair_coeff commands, they only need to be specified once for each atom type. Specifically, if any of :math:`\epsilon_{i,a}`, :math:`\epsilon_{i,b}`, @@ -116,20 +116,20 @@ Specifically, if any of :math:`\epsilon_{i,a}`, :math:`\epsilon_{i,b}`, atom type I. If all the :math:`\epsilon_i` values are zero, they are ignored. If any of :math:`\epsilon_{j,a}`, :math:`\epsilon_{j,b}`, :math:`\epsilon_{j,c}` are non-zero, the three values are assigned to -atom type J. If all three epsilon\_j values are zero, they are ignored. +atom type J. If all three epsilon_j values are zero, they are ignored. Thus the typical way to define the :math:`\epsilon_i` and -:math:`\epsilon_j` coefficients is to list their values in "pair\_coeff +:math:`\epsilon_j` coefficients is to list their values in "pair_coeff I J" commands when I = J, but set them to 0.0 when I != J. If you do list them when I != J, you should insure they are consistent with their -values in other pair\_coeff commands, since only the last setting will +values in other pair_coeff commands, since only the last setting will be in effect. Note that if this potential is being used as a sub-style of -:doc:`pair_style hybrid `, and there is no "pair\_coeff I I" +:doc:`pair_style hybrid `, and there is no "pair_coeff I I" setting made for Gay-Berne for a particular type I (because I-I interactions are computed by another hybrid pair potential), then you still need to insure the :math:`\epsilon` a,b,c coefficients are assigned to -that type. e.g. in a "pair\_coeff I J" command. +that type. e.g. in a "pair_coeff I J" command. .. note:: @@ -142,13 +142,13 @@ that type. e.g. in a "pair\_coeff I J" command. as the standard LJ parameters. This is much cheaper to compute than the full Gay-Berne formula. To treat the particle as a LJ sphere with sigma = D, you should normally set :math:`\epsilon` a = b = c = - 1.0, set the pair\_coeff :math:`\sigma = D`, and also set the 3 shape + 1.0, set the pair_coeff :math:`\sigma = D`, and also set the 3 shape parameters for the particle to D. The one exception is that if the 3 shape parameters are set to 0.0, which is a valid way in LAMMPS to specify a point particle, then the Gay-Berne potential will treat that as shape parameters of 1.0 (i.e. a LJ particle with :math:`\sigma = 1`), since it requires finite-size particles. In - this case you should still set the pair\_coeff :math:`\sigma` to 1.0 + this case you should still set the pair_coeff :math:`\sigma` to 1.0 as well. ---------- @@ -177,7 +177,7 @@ instructions on how to use the accelerated styles effectively. For atom type pairs I,J and I != J, the epsilon and sigma coefficients and cutoff distance for this pair style can be mixed. The default mix -value is *geometric*\ . See the "pair\_modify" command for details. +value is *geometric*\ . See the "pair_modify" command for details. This pair styles supports the :doc:`pair_modify ` shift option for the energy of the Lennard-Jones portion of the pair @@ -192,7 +192,7 @@ This pair style does not support the :doc:`pair_modify ` tail option for adding long-range tail corrections to energy and pressure. -This pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_gran.rst b/doc/src/pair_gran.rst index 6327f09f35..3cfe946e41 100644 --- a/doc/src/pair_gran.rst +++ b/doc/src/pair_gran.rst @@ -31,8 +31,8 @@ Syntax * style = *gran/hooke* or *gran/hooke/history* or *gran/hertz/history* * Kn = elastic constant for normal particle repulsion (force/distance units or pressure units - see discussion below) * Kt = elastic constant for tangential contact (force/distance units or pressure units - see discussion below) -* gamma\_n = damping coefficient for collisions in normal direction (1/time units or 1/time-distance units - see discussion below) -* gamma\_t = damping coefficient for collisions in tangential direction (1/time units or 1/time-distance units - see discussion below) +* gamma_n = damping coefficient for collisions in normal direction (1/time units or 1/time-distance units - see discussion below) +* gamma_t = damping coefficient for collisions in tangential direction (1/time units or 1/time-distance units - see discussion below) * xmu = static yield criterion (unitless value between 0.0 and 1.0e4) * dampflag = 0 or 1 if tangential damping force is excluded or included @@ -41,8 +41,8 @@ Syntax Versions of LAMMPS before 9Jan09 had different style names for granular force fields. This is to emphasize the fact that the Hertzian equation has changed to model polydispersity more accurately. - A side effect of the change is that the Kn, Kt, gamma\_n, and gamma\_t - coefficients in the pair\_style command must be specified with + A side effect of the change is that the Kn, Kt, gamma_n, and gamma_t + coefficients in the pair_style command must be specified with different values in order to reproduce calculations made with earlier versions of LAMMPS, even for monodisperse systems. See the NOTE below for details. @@ -104,14 +104,14 @@ The other quantities in the equations are as follows: * :math:`K_t` = elastic constant for tangential contact * :math:`\gamma_n` = viscoelastic damping constant for normal contact * :math:`\gamma_t` = viscoelastic damping constant for tangential contact -* :math:`m_{eff} = M_i M_j / (M_i + M_j) =` effective mass of 2 particles of mass M\_i and M\_j +* :math:`m_{eff} = M_i M_j / (M_i + M_j) =` effective mass of 2 particles of mass M_i and M_j * :math:`\mathbf{\Delta s}_t =` tangential displacement vector between 2 particles which is truncated to satisfy a frictional yield criterion * :math:`n_{ij} =` unit vector along the line connecting the centers of the 2 particles * :math:`V_n =` normal component of the relative velocity of the 2 particles * :math:`V_t =` tangential component of the relative velocity of the 2 particles The :math:`K_n`, :math:`K_t`, :math:`\gamma_n`, and :math:`\gamma_t` -coefficients are specified as parameters to the pair\_style command. If +coefficients are specified as parameters to the pair_style command. If a NULL is used for :math:`K_t`, then a default value is used where :math:`K_t = 2/7 K_n`. If a NULL is used for :math:`\gamma_t`, then a default value is used where :math:`\gamma_t = 1/2 \gamma_n`. @@ -170,7 +170,7 @@ Hookean styles may not be a suitable model for polydisperse systems. of diameter 1, all 4 of these coefficients should now be set 2x larger than they were previously. -Xmu is also specified in the pair\_style command and is the upper limit +Xmu is also specified in the pair_style command and is the upper limit of the tangential force through the Coulomb criterion Ft = xmu\*Fn, where Ft and Fn are the total tangential and normal force components in the formulas above. Thus in the Hookean case, the tangential force @@ -186,7 +186,7 @@ holds, though the spring is no longer linear. for modeling of systems which can sustain very large tangential forces. -The effective mass *m\_eff* is given by the formula above for two +The effective mass *m_eff* is given by the formula above for two isolated particles. If either particle is part of a rigid body, its mass is replaced by the mass of the rigid body in the formula above. This is determined by searching for a :doc:`fix rigid ` @@ -194,7 +194,7 @@ command (or its variants). For granular styles there are no additional coefficients to set for each pair of atom types via the :doc:`pair_coeff ` command. -All settings are global and are made via the pair\_style command. +All settings are global and are made via the pair_style command. However you must still use the :doc:`pair_coeff ` for all pairs of granular atom types. For example the command @@ -205,7 +205,7 @@ pairs of granular atom types. For example the command should be used if all atoms in the simulation interact via a granular potential (i.e. one of the pair styles above is used). If a granular potential is used as a sub-style of :doc:`pair_style hybrid `, then specific atom types can be used in the -pair\_coeff command to determine which atoms interact via a granular +pair_coeff command to determine which atoms interact via a granular potential. ---------- @@ -235,7 +235,7 @@ instructions on how to use the accelerated styles effectively. The :doc:`pair_modify ` mix, shift, table, and tail options are not relevant for granular pair styles. -These pair styles write their information to :doc:`binary restart files `, so a pair\_style command does not need to be +These pair styles write their information to :doc:`binary restart files `, so a pair_style command does not need to be specified in an input script that reads a restart file. These pair styles can only be used via the *pair* keyword of the diff --git a/doc/src/pair_granular.rst b/doc/src/pair_granular.rst index d8dc7b3b3e..73b1ec85ec 100644 --- a/doc/src/pair_granular.rst +++ b/doc/src/pair_granular.rst @@ -65,12 +65,12 @@ on a Johnson-Kendall-Roberts normal contact model and 2-2 interactions are based on a DMT cohesive model (see below). In that example, 1-1 and 2-2 interactions have different model forms, in which case mixing of coefficients cannot be determined, so 1-2 interactions must be -explicitly defined via the *pair\_coeff 1 \** command, otherwise an +explicitly defined via the *pair_coeff 1 \** command, otherwise an error would result. ---------- -The first required keyword for the *pair\_coeff* command is the normal +The first required keyword for the *pair_coeff* command is the normal contact model. Currently supported options for normal contact models and their required arguments are: @@ -170,7 +170,7 @@ following general form: Here, :math:`\mathbf{v}_{n,rel} = (\mathbf{v}_j - \mathbf{v}_i) \cdot \mathbf{n} \mathbf{n}` is the component of relative velocity along :math:`\mathbf{n}`. -The optional *damping* keyword to the *pair\_coeff* command followed by +The optional *damping* keyword to the *pair_coeff* command followed by a keyword determines the model form of the damping factor :math:`\eta_n`, and the interpretation of the :math:`\eta_{n0}` or :math:`e` coefficients specified as part of the normal contact model settings. The *damping* @@ -181,7 +181,7 @@ other settings, potentially also the twisting damping). The options for the damping model currently supported are: 1. *velocity* -2. *mass\_velocity* +2. *mass_velocity* 3. *viscoelastic* 4. *tsuji* @@ -198,7 +198,7 @@ user-specified damping coefficient in the *normal* model: Here, :math:`\eta_{n0}` is the damping coefficient specified for the normal contact model, in units of *mass*\ /\ *time*\ . -For *damping mass\_velocity*, the normal damping is given by: +For *damping mass_velocity*, the normal damping is given by: .. math:: @@ -207,7 +207,7 @@ For *damping mass\_velocity*, the normal damping is given by: Here, :math:`\eta_{n0}` is the damping coefficient specified for the normal contact model, in units of *mass*\ /\ *time* and :math:`m_{eff} = m_i m_j/(m_i + m_j)` is the effective mass. -Use *damping mass\_velocity* to reproduce the damping behavior of +Use *damping mass_velocity* to reproduce the damping behavior of *pair gran/hooke/\**. The *damping viscoelastic* model is based on the viscoelastic @@ -251,24 +251,24 @@ damping components: ---------- -The *pair\_coeff* command also requires specification of the tangential +The *pair_coeff* command also requires specification of the tangential contact model. The required keyword *tangential* is expected, followed by the model choice and associated parameters. Currently supported tangential model choices and their expected parameters are as follows: -1. *linear\_nohistory* : :math:`x_{\gamma,t}`, :math:`\mu_s` -2. *linear\_history* : :math:`k_t`, :math:`x_{\gamma,t}`, :math:`\mu_s` +1. *linear_nohistory* : :math:`x_{\gamma,t}`, :math:`\mu_s` +2. *linear_history* : :math:`k_t`, :math:`x_{\gamma,t}`, :math:`\mu_s` 3. *mindlin* : :math:`k_t` or NULL, :math:`x_{\gamma,t}`, :math:`\mu_s` -4. *mindlin\_rescale* : :math:`k_t` or NULL, :math:`x_{\gamma,t}`, :math:`\mu_s` +4. *mindlin_rescale* : :math:`k_t` or NULL, :math:`x_{\gamma,t}`, :math:`\mu_s` Here, :math:`x_{\gamma,t}` is a dimensionless multiplier for the normal damping :math:`\eta_n` that determines the magnitude of the tangential damping, :math:`\mu_t` is the tangential (or sliding) friction coefficient, and :math:`k_t` is the tangential stiffness coefficient. -For *tangential linear\_nohistory*, a simple velocity-dependent Coulomb +For *tangential linear_nohistory*, a simple velocity-dependent Coulomb friction criterion is used, which mimics the behavior of the *pair -gran/hooke* style. The tangential force (\mathbf{F}\_t\) is given by: +gran/hooke* style. The tangential force (\mathbf{F}_t\) is given by: .. math:: @@ -321,10 +321,10 @@ Where :math:`F_{pulloff} = 3\pi \gamma R` for *jkr*\ , and The remaining tangential options all use accumulated tangential displacement (i.e. contact history). This is discussed below in the -context of the *linear\_history* option, but the same treatment of the +context of the *linear_history* option, but the same treatment of the accumulated displacement applies to the other options as well. -For *tangential linear\_history*, the tangential force is given by: +For *tangential linear_history*, the tangential force is given by: .. math:: @@ -387,7 +387,7 @@ overlap region) to induce a torque on each particle according to: \mathbf{\tau}_j = -(R_j - 0.5 \delta) \mathbf{n} \times \mathbf{F}_t -For *tangential mindlin*\ , the :ref:`Mindlin ` no-slip solution is used, which differs from the *linear\_history* +For *tangential mindlin*\ , the :ref:`Mindlin ` no-slip solution is used, which differs from the *linear_history* option by an additional factor of *a*\ , the radius of the contact region. The tangential force is given by: .. math:: @@ -409,7 +409,7 @@ case, mixing of the shear modulus for different particle types *i* and 1/G = 2(2-\nu_i)(1+\nu_i)/E_i + 2(2-\nu_j)(1+\nu_j)/E_j -The *mindlin\_rescale* option uses the same form as *mindlin*\ , but the +The *mindlin_rescale* option uses the same form as *mindlin*\ , but the magnitude of the tangential displacement is re-scaled as the contact unloads, i.e. if :math:`a < a_{t_{n-1}}`: @@ -524,9 +524,9 @@ if the twisting torque exceeds this critical value: For *twisting sds*\ , the coefficients :math:`k_{twist}, \gamma_{twist}` and :math:`\mu_{twist}` are simply the user input parameters that follow -the *twisting sds* keywords in the *pair\_coeff* command. +the *twisting sds* keywords in the *pair_coeff* command. -For *twisting\_marshall*, the coefficients are expressed in terms of +For *twisting_marshall*, the coefficients are expressed in terms of sliding friction coefficients, as discussed in :ref:`Marshall ` (see equations 32 and 33 of that work): @@ -568,22 +568,22 @@ The third example is equivalent to ---------- -LAMMPS automatically sets pairwise cutoff values for *pair\_style +LAMMPS automatically sets pairwise cutoff values for *pair_style granular* based on particle radii (and in the case of *jkr* pull-off distances). In the vast majority of situations, this is adequate. -However, a cutoff value can optionally be appended to the *pair\_style +However, a cutoff value can optionally be appended to the *pair_style granular* command to specify a global cutoff (i.e. a cutoff for all atom types). Additionally, the optional *cutoff* keyword can be passed -to the *pair\_coeff* command, followed by a cutoff value. This will -set a pairwise cutoff for the atom types in the *pair\_coeff* command. +to the *pair_coeff* command, followed by a cutoff value. This will +set a pairwise cutoff for the atom types in the *pair_coeff* command. These options may be useful in some rare cases where the automatic cutoff determination is not sufficient, e.g. if particle diameters are being modified via the *fix adapt* command. In that case, the -global cutoff specified as part of the *pair\_style granular* command +global cutoff specified as part of the *pair_style granular* command is applied to all atom types, unless it is overridden for a given atom type combination by the *cutoff* value specified in the *pair coeff* command. If *cutoff* is only specified in the *pair coeff* command -and no global cutoff is appended to the *pair\_style granular* command, +and no global cutoff is appended to the *pair_style granular* command, then LAMMPS will use that cutoff for the specified atom type combination, and automatically set pairwise cutoffs for the remaining atom types. @@ -620,7 +620,7 @@ most quantities, e.g. if friction coefficient for type 1-type 1 interactions is set to :math:`\mu_1`, and friction coefficient for type 2-type 2 interactions is set to :math:`\mu_2`, the friction coefficient for type1-type2 interactions is computed as :math:`\sqrt{\mu_1\mu_2}` -(unless explicitly specified to a different value by a *pair\_coeff 1 2 +(unless explicitly specified to a different value by a *pair_coeff 1 2 ...* command). The exception to this is elastic modulus, only applicable to *hertz/material*\ , *dmt* and *jkr* normal contact models. In that case, the effective elastic modulus is computed as: @@ -642,7 +642,7 @@ or E_{eff,ij} = \frac{E_{ij}}{2(1-\nu_{ij})} -These pair styles write their information to :doc:`binary restart files `, so a pair\_style command does not need to be +These pair styles write their information to :doc:`binary restart files `, so a pair_style command does not need to be specified in an input script that reads a restart file. These pair styles can only be used via the *pair* keyword of the @@ -661,7 +661,7 @@ particle I. The next entry (8) is the magnitude of the rolling torque. The next entry (9) is the magnitude of the twisting torque acting about the vector connecting the two particle centers. The last 3 (10-12) are the components of the vector connecting -the centers of the two particles (x\_I - x\_J). +the centers of the two particles (x_I - x_J). These extra quantities can be accessed by the :doc:`compute pair/local ` command, as *p1*\ , *p2*\ , ..., *p12*\ . @@ -697,7 +697,7 @@ Related commands Default """"""" -For the *pair\_coeff* settings: *damping viscoelastic*\ , *rolling none*\ , +For the *pair_coeff* settings: *damping viscoelastic*\ , *rolling none*\ , *twisting none*\ . **References:** diff --git a/doc/src/pair_gromacs.rst b/doc/src/pair_gromacs.rst index 234e7c6894..121181a90d 100644 --- a/doc/src/pair_gromacs.rst +++ b/doc/src/pair_gromacs.rst @@ -77,7 +77,7 @@ the coarse-grained models of :ref:`(Marrink) `. coefficients A, B, and C are computed by LAMMPS to perform the shifting and smoothing. The function S(r) is actually applied once to each term of the LJ formula and once to the Coulombic formula, so there are 2 or 3 -sets of A,B,C coefficients depending on which pair\_style is used. The +sets of A,B,C coefficients depending on which pair_style is used. The boundary conditions applied to the smoothing function are as follows: :math:`S'(r_1) = S''(r_1) = 0, S(r_c) = -E(r_c), S'(r_c) = -E'(r_c)`, and :math:`S''(r_c) = -E''(r_c)`, where E(r) is the corresponding term @@ -87,7 +87,7 @@ respectively. The inner and outer cutoff for the LJ and Coulombic terms can be the same or different depending on whether 2 or 4 arguments are used in -the pair\_style command. The inner LJ cutoff must be > 0, but the +the pair_style command. The inner LJ cutoff must be > 0, but the inner Coulombic cutoff can be >= 0. The following coefficients must be defined for each pair of atoms @@ -111,7 +111,7 @@ are used. The last 2 coefficients cannot be used with style *lj/gromacs/coul/gromacs* because this force field does not allow varying cutoffs for individual atom pairs; all pairs use the global -cutoff(s) specified in the pair\_style command. +cutoff(s) specified in the pair_style command. ---------- @@ -139,7 +139,7 @@ instructions on how to use the accelerated styles effectively. For atom type pairs I,J and I != J, the epsilon and sigma coefficients and cutoff distance for all of the lj/cut pair styles can be mixed. -The default mix value is *geometric*\ . See the "pair\_modify" command +The default mix value is *geometric*\ . See the "pair_modify" command for details. None of the GROMACS pair styles support the @@ -155,7 +155,7 @@ None of the GROMACS pair styles support the corrections to energy and pressure, since there are no corrections for a potential that goes to 0.0 at the cutoff. -All of the GROMACS pair styles write their information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do +All of the GROMACS pair styles write their information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. All of the GROMACS pair styles can only be used via the *pair* diff --git a/doc/src/pair_gw.rst b/doc/src/pair_gw.rst index 33ddaf2a10..d2d1283618 100644 --- a/doc/src/pair_gw.rst +++ b/doc/src/pair_gw.rst @@ -41,10 +41,10 @@ to release the code anyway with only the technical explanations. For details of the model and the parameters, please refer to the linked publication. -Only a single pair\_coeff command is used with the *gw* and *gw/zbl* +Only a single pair_coeff command is used with the *gw* and *gw/zbl* styles which specifies a Gao-Weber potential file with parameters for all needed elements. These are mapped to LAMMPS atom types by -specifying N additional arguments after the filename in the pair\_coeff +specifying N additional arguments after the filename in the pair_coeff command, where N is the number of LAMMPS atom types: * filename @@ -55,7 +55,7 @@ to specify the path for the potential file. As an example, imagine a file SiC.gw has Gao-Weber values for Si and C. If your LAMMPS simulation has 4 atoms types and you want the first 3 to -be Si, and the 4th to be C, you would use the following pair\_coeff command: +be Si, and the 4th to be C, you would use the following pair_coeff command: .. code-block:: LAMMPS @@ -89,7 +89,7 @@ This pair style does not support the :doc:`pair_modify ` shift, table, and tail options. This pair style does not write its information to :doc:`binary restart files `, since it is stored in potential files. Thus, you -need to re-specify the pair\_style and pair\_coeff commands in an input +need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_hbond_dreiding.rst b/doc/src/pair_hbond_dreiding.rst index 9c02311008..0f5470d5f9 100644 --- a/doc/src/pair_hbond_dreiding.rst +++ b/doc/src/pair_hbond_dreiding.rst @@ -21,9 +21,9 @@ Syntax * style = *hbond/dreiding/lj* or *hbond/dreiding/morse* * n = cosine angle periodicity -* inner\_distance\_cutoff = global inner cutoff for Donor-Acceptor interactions (distance units) -* outer\_distance\_cutoff = global cutoff for Donor-Acceptor interactions (distance units) -* angle\_cutoff = global angle cutoff for Acceptor-Hydrogen-Donor +* inner_distance_cutoff = global inner cutoff for Donor-Acceptor interactions (distance units) +* outer_distance_cutoff = global cutoff for Donor-Acceptor interactions (distance units) +* angle_cutoff = global angle cutoff for Acceptor-Hydrogen-Donor * interactions (degrees) Examples @@ -112,7 +112,7 @@ on the DREIDING force field. In the original Dreiding force field paper 1-4 non-bonded interactions ARE allowed. If this is desired for your model, use the - special\_bonds command (e.g. "special\_bonds lj 0.0 0.0 1.0") to turn + special_bonds command (e.g. "special_bonds lj 0.0 0.0 1.0") to turn these interactions on. ---------- @@ -125,7 +125,7 @@ in the examples above. Unlike other pair styles and their associated :doc:`pair_coeff ` commands, you do not need to specify - pair\_coeff settings for all possible I,J type pairs. Only I,J type + pair_coeff settings for all possible I,J type pairs. Only I,J type pairs for atoms which act as joint donors/acceptors need to be specified; all other type pairs are assumed to be inactive. @@ -134,11 +134,11 @@ in the examples above. A :doc:`pair_coeff ` command can be specified multiple times for the same donor/acceptor type pair. This enables multiple hydrogen types to be assigned to the same donor/acceptor type pair. - For other pair\_styles, if the pair\_coeff command is re-used for the + For other pair_styles, if the pair_coeff command is re-used for the same I.J type pair, the settings for that type pair are overwritten. For the hydrogen bond potentials this is not the case; the settings are cumulative. This means the only way to turn off a previous - setting, is to re-use the pair\_style command and start over. + setting, is to re-use the pair_style command and start over. For the *hbond/dreiding/lj* style the list of coefficients is as follows: @@ -171,9 +171,9 @@ select multiple types as hydrogen atoms. This takes the form "\*" or "\*n" or "n\*" or "m\*n". See the :doc:`pair_coeff ` command doc page for details. -If the donor flag is *i*\ , then the atom of type I in the pair\_coeff +If the donor flag is *i*\ , then the atom of type I in the pair_coeff command is treated as the donor, and J is the acceptor. If the donor -flag is *j*\ , then the atom of type J in the pair\_coeff command is +flag is *j*\ , then the atom of type J in the pair_coeff command is treated as the donor and I is the donor. This option is required because the :doc:`pair_coeff ` command requires that I <= J. @@ -187,7 +187,7 @@ hydrogen bond potential based on a Morse functional form. The last 3 coefficients for both styles are optional. If not specified, the global n, distance cutoff, and angle cutoff specified -in the pair\_style command are used. If you wish to only override the +in the pair_style command are used. If you wish to only override the 2nd or 3rd optional parameter, you must also specify the preceding optional parameters. @@ -228,7 +228,7 @@ These pair styles do not support the :doc:`pair_modify ` tail option for adding long-range tail corrections to energy and pressure. -These pair styles do not write their information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands need to be +These pair styles do not write their information to :doc:`binary restart files `, so pair_style and pair_coeff commands need to be re-specified in an input script that reads a restart file. These pair styles can only be used via the *pair* keyword of the diff --git a/doc/src/pair_hybrid.rst b/doc/src/pair_hybrid.rst index 9a3c1af423..8e40466faf 100644 --- a/doc/src/pair_hybrid.rst +++ b/doc/src/pair_hybrid.rst @@ -58,7 +58,7 @@ using *lj/cut* and *coul/long* together gives the same result as if the *lj/cut/coul/long* potential were used by itself. In this case, it would be more efficient to use the single combined potential, but in general any combination of pair potentials can be used together in -to produce an interaction that is not encoded in any single pair\_style +to produce an interaction that is not encoded in any single pair_style file, e.g. adding Coulombic forces between granular particles. All pair styles that will be used are listed as "sub-styles" following @@ -76,7 +76,7 @@ a Tersoff potential for pure C for the other set (presumably with some could be listed twice. But if you just want to use a Lennard-Jones or other pairwise potential for several different atom type pairs in your model, then you should just list the sub-style once and use the -pair\_coeff command to assign parameters for the different type pairs. +pair_coeff command to assign parameters for the different type pairs. .. note:: @@ -85,10 +85,10 @@ pair\_coeff command to assign parameters for the different type pairs. This is because the GPU package currently assumes that only one instance of a pair style is being used. -In the pair\_coeff commands, the name of a pair style must be added +In the pair_coeff commands, the name of a pair style must be added after the I,J type specification, with the remaining coefficients being those appropriate to that style. If the pair style is used -multiple times in the pair\_style command, then an additional numeric +multiple times in the pair_style command, then an additional numeric argument must also be specified which is a number from 1 to M where M is the number of times the sub-style was listed in the pair style command. The extra number indicates which instance of the sub-style @@ -129,7 +129,7 @@ each line in the "Pair Coeffs" section, e.g. 1 lj/cut/coul/cut 1.0 1.0 ... -Note that the pair\_coeff command for some potentials such as +Note that the pair_coeff command for some potentials such as :doc:`pair_style eam/alloy ` includes a mapping specification of elements to all atom types, which in the hybrid case, can include atom types not assigned to the *eam/alloy* potential. The NULL @@ -139,18 +139,18 @@ sub-style. For the *hybrid* style, each atom type pair I,J is assigned to exactly one sub-style. Just as with a simulation using a single pair style, -if you specify the same atom type pair in a second pair\_coeff command, +if you specify the same atom type pair in a second pair_coeff command, the previous assignment will be overwritten. For the *hybrid/overlay* style, each atom type pair I,J can be assigned to one or more sub-styles. If you specify the same atom type -pair in a second pair\_coeff command with a new sub-style, then the +pair in a second pair_coeff command with a new sub-style, then the second sub-style is added to the list of potentials that will be calculated for two interacting atoms of those types. If you specify -the same atom type pair in a second pair\_coeff command with a +the same atom type pair in a second pair_coeff command with a sub-style that has already been defined for that pair of atoms, then the new pair coefficients simply override the previous ones, as in the -normal usage of the pair\_coeff command. E.g. these two sets of +normal usage of the pair_coeff command. E.g. these two sets of commands are the same: .. code-block:: LAMMPS @@ -181,7 +181,7 @@ sub-style and use the :doc:`neigh_modify exclude type ` command. You can assign it to some sub-style and set the coefficients so that there is effectively no interaction (e.g. epsilon = 0.0 in a LJ potential). Or, for *hybrid* and *hybrid/overlay* simulations, you -can use this form of the pair\_coeff command in your input script: +can use this form of the pair_coeff command in your input script: .. code-block:: LAMMPS @@ -265,7 +265,7 @@ individual sub-style can be accessed and output via the :doc:`compute pair ` command to exclude certain type pairs from the neighbor list that will be passed to a many-body sub-style. This will alter the calculations made by a many-body @@ -373,12 +373,12 @@ sub-styles of the hybrid potential. For atom type pairs I,J and I != J, if the sub-style assigned to I,I and J,J is the same, and if the sub-style allows for mixing, then the coefficients for I,J can be mixed. This means you do not have to -specify a pair\_coeff command for I,J since the I,J type pair will be +specify a pair_coeff command for I,J since the I,J type pair will be assigned automatically to the sub-style defined for both I,I and J,J and its coefficients generated by the mixing rule used by that sub-style. For the *hybrid/overlay* style, there is an additional requirement that both the I,I and J,J pairs are assigned to a single -sub-style. See the "pair\_modify" command for details of mixing rules. +sub-style. See the "pair_modify" command for details of mixing rules. See the See the doc page for the sub-style to see if allows for mixing. @@ -390,7 +390,7 @@ For the hybrid pair styles, the list of sub-styles and their respective settings are written to :doc:`binary restart files `, so a :doc:`pair_style ` command does not need to specified in an input script that reads a restart file. However, the coefficient information is not stored in the restart -file. Thus, pair\_coeff commands need to be re-specified in the +file. Thus, pair_coeff commands need to be re-specified in the restart input script. These pair styles support the use of the *inner*\ , *middle*\ , and @@ -401,7 +401,7 @@ Restrictions """""""""""" When using a long-range Coulombic solver (via the -:doc:`kspace_style ` command) with a hybrid pair\_style, +:doc:`kspace_style ` command) with a hybrid pair_style, one or more sub-styles will be of the "long" variety, e.g. *lj/cut/coul/long* or *buck/coul/long*\ . You must insure that the short-range Coulombic cutoff used by each of these long pair styles is diff --git a/doc/src/pair_ilp_graphene_hbn.rst b/doc/src/pair_ilp_graphene_hbn.rst index 03ac896f1f..22f4a37380 100644 --- a/doc/src/pair_ilp_graphene_hbn.rst +++ b/doc/src/pair_ilp_graphene_hbn.rst @@ -11,7 +11,7 @@ Syntax pair_style [hybrid/overlay ...] ilp/graphene/hbn cutoff tap_flag * cutoff = global cutoff (distance units) -* tap\_flag = 0/1 to turn off/on the taper function +* tap_flag = 0/1 to turn off/on the taper function Examples """""""" @@ -104,14 +104,14 @@ list for calculating the normals for each atom pair. be found in :ref:`(Ouyang1) ` and :ref:`(Ouyang2) `. This potential must be used in combination with hybrid/overlay. -Other interactions can be set to zero using pair\_style *none*\ . +Other interactions can be set to zero using pair_style *none*\ . This pair style tallies a breakdown of the total interlayer potential energy into sub-categories, which can be accessed via the :doc:`compute pair ` command as a vector of values of length 2. The 2 values correspond to the following sub-categories: -1. *E\_vdW* = vdW (attractive) energy -2. *E\_Rep* = Repulsive energy +1. *E_vdW* = vdW (attractive) energy +2. *E_Rep* = Repulsive energy To print these quantities to the log file (with descriptive column headings) the following commands could be included in an input script: @@ -127,12 +127,12 @@ headings) the following commands could be included in an input script: **Mixing, shift, table, tail correction, restart, rRESPA info**\ : -This pair style does not support the pair\_modify mix, shift, table, and +This pair style does not support the pair_modify mix, shift, table, and tail options. This pair style does not write their information to binary restart files, since it is stored in potential files. Thus, you need to -re-specify the pair\_style and pair\_coeff commands in an input script +re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. Restrictions @@ -157,12 +157,12 @@ Related commands :doc:`pair_none `, :doc:`pair_style hybrid/overlay `, :doc:`pair_style drip `, -:doc:`pair_style pair\_kolmogorov\_crespi\_z `, -:doc:`pair_style pair\_kolmogorov\_crespi\_full `, -:doc:`pair_style pair\_lebedeva\_z `, -:doc:`pair_style pair\_coul\_shield `. +:doc:`pair_style pair_kolmogorov_crespi_z `, +:doc:`pair_style pair_kolmogorov_crespi_full `, +:doc:`pair_style pair_lebedeva_z `, +:doc:`pair_style pair_coul_shield `. -**Default:** tap\_flag = 1 +**Default:** tap_flag = 1 ---------- diff --git a/doc/src/pair_kim.rst b/doc/src/pair_kim.rst index 4a134f7037..7717545f21 100644 --- a/doc/src/pair_kim.rst +++ b/doc/src/pair_kim.rst @@ -33,12 +33,12 @@ KIM API Portable Model Interface (PMI) and can be used by any simulation code that conforms to the KIM API/PMI, and "KIM Simulator Models" that are natively implemented within a single simulation code (like LAMMPS) and can only be used with it. -The *pair\_style kim* command is limited to KIM PMs. It is +The *pair_style kim* command is limited to KIM PMs. It is used by the :doc:`kim_commands interface ` as needed. .. note:: - Since *pair\_style kim* is called by *kim\_interactions* as needed, + Since *pair_style kim* is called by *kim_interactions* as needed, is not recommended to be directly used in input scripts. ---------- @@ -51,17 +51,17 @@ be incompatibilities (for example due to unit matching issues). In the event of an incompatibility, the code will terminate with an error message. Check both the LAMMPS and KIM log files for details. -Only a single *pair\_coeff* command is used with the *kim* style, which +Only a single *pair_coeff* command is used with the *kim* style, which specifies the mapping of LAMMPS atom types to the species supported by the KIM PM. This is done by specifying *N* additional arguments -after the \* \* in the *pair\_coeff* command, where *N* is the number of +after the \* \* in the *pair_coeff* command, where *N* is the number of LAMMPS atom types: * N element names = mapping of KIM elements to atom types For example, consider a KIM PM that supports Si and C species. If the LAMMPS simulation has four atom types, where the first three are Si, -and the fourth is C, the following *pair\_coeff* command would be used: +and the fourth is C, the following *pair_coeff* command would be used: .. code-block:: LAMMPS @@ -92,7 +92,7 @@ This pair style does not support the :doc:`pair_modify ` mix, shift, table, and tail options. This pair style does not write its information to :doc:`binary restart files `, since KIM stores the potential parameters. -Thus, you need to re-specify the pair\_style and pair\_coeff commands in +Thus, you need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the @@ -107,7 +107,7 @@ Restrictions This pair style is part of the KIM package. See details on restrictions in :doc:`kim_commands `. -This current version of pair\_style kim is compatible with the +This current version of pair_style kim is compatible with the kim-api package version 2.0.0 and higher. Related commands diff --git a/doc/src/pair_kolmogorov_crespi_full.rst b/doc/src/pair_kolmogorov_crespi_full.rst index f1a647f7a0..8d9adf0341 100644 --- a/doc/src/pair_kolmogorov_crespi_full.rst +++ b/doc/src/pair_kolmogorov_crespi_full.rst @@ -11,7 +11,7 @@ Syntax pair_style hybrid/overlay kolmogorov/crespi/full cutoff tap_flag * cutoff = global cutoff (distance units) -* tap\_flag = 0/1 to turn off/on the taper function +* tap_flag = 0/1 to turn off/on the taper function Examples """""""" @@ -72,10 +72,10 @@ list for calculating the normals for each atom pair. .. note:: Two new sets of parameters of KC potential for hydrocarbons, CH.KC - (without the taper function) and CH\_taper.KC (with the taper function) + (without the taper function) and CH_taper.KC (with the taper function) are presented in :ref:`(Ouyang1) `. The energy for the KC potential with the taper function goes continuously to zero at the cutoff. The - parameters in both CH.KC and CH\_taper.KC provide a good description in + parameters in both CH.KC and CH_taper.KC provide a good description in both short- and long-range interaction regimes. While the original parameters (CC.KC) published in :ref:`(Kolmogorov) ` are only suitable for long-range interaction regime. This feature is essential @@ -84,14 +84,14 @@ list for calculating the normals for each atom pair. comparison of these parameters can be found in :ref:`(Ouyang1) ` and :ref:`(Ouyang2) `. This potential must be used in combination with hybrid/overlay. -Other interactions can be set to zero using pair\_style *none*\ . +Other interactions can be set to zero using pair_style *none*\ . This pair style tallies a breakdown of the total interlayer potential energy into sub-categories, which can be accessed via the :doc:`compute pair ` command as a vector of values of length 2. The 2 values correspond to the following sub-categories: -1. *E\_vdW* = vdW (attractive) energy -2. *E\_Rep* = Repulsive energy +1. *E_vdW* = vdW (attractive) energy +2. *E_Rep* = Repulsive energy To print these quantities to the log file (with descriptive column headings) the following commands could be included in an input script: @@ -107,12 +107,12 @@ headings) the following commands could be included in an input script: **Mixing, shift, table, tail correction, restart, rRESPA info**\ : -This pair style does not support the pair\_modify mix, shift, table, +This pair style does not support the pair_modify mix, shift, table, and tail options. This pair style does not write their information to binary restart files, since it is stored in potential files. Thus, you need to -re-specify the pair\_style and pair\_coeff commands in an input script +re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. Restrictions @@ -137,11 +137,11 @@ Related commands :doc:`pair_none `, :doc:`pair_style hybrid/overlay `, :doc:`pair_style drip `, -:doc:`pair_style pair\_lebedeva\_z `, +:doc:`pair_style pair_lebedeva_z `, :doc:`pair_style kolmogorov/crespi/z `, :doc:`pair_style ilp/graphene/hbn `. -**Default:** tap\_flag = 0 +**Default:** tap_flag = 0 ---------- diff --git a/doc/src/pair_kolmogorov_crespi_z.rst b/doc/src/pair_kolmogorov_crespi_z.rst index 0ed073d5af..8b961773a3 100644 --- a/doc/src/pair_kolmogorov_crespi_z.rst +++ b/doc/src/pair_kolmogorov_crespi_z.rst @@ -53,7 +53,7 @@ is available to facilitate scaling of energies in accordance with :ref:`(vanWijk) `. This potential must be used in combination with hybrid/overlay. -Other interactions can be set to zero using pair\_style *none*\ . +Other interactions can be set to zero using pair_style *none*\ . Restrictions """""""""""" diff --git a/doc/src/pair_lcbop.rst b/doc/src/pair_lcbop.rst index b39b149a73..4eb7a345ee 100644 --- a/doc/src/pair_lcbop.rst +++ b/doc/src/pair_lcbop.rst @@ -25,10 +25,10 @@ The *lcbop* pair style computes the long-range bond-order potential for carbon (LCBOP) of :ref:`(Los and Fasolino) `. See section II in that paper for the analytic equations associated with the potential. -Only a single pair\_coeff command is used with the *lcbop* style which +Only a single pair_coeff command is used with the *lcbop* style which specifies an LCBOP potential file with parameters for specific elements. These are mapped to LAMMPS atom types by specifying N -additional arguments after the filename in the pair\_coeff command, +additional arguments after the filename in the pair_coeff command, where N is the number of LAMMPS atom types: * filename @@ -38,7 +38,7 @@ See the :doc:`pair_coeff ` doc page for alternate ways to specify the path for the potential file. As an example, if your LAMMPS simulation has 4 atom types and you want -the 1st 3 to be C you would use the following pair\_coeff command: +the 1st 3 to be C you would use the following pair_coeff command: .. code-block:: LAMMPS @@ -64,7 +64,7 @@ This pair style does not support the :doc:`pair_modify ` mix, shift, table, and tail options. This pair style does not write its information to :doc:`binary restart files `, since it is stored in potential files. Thus, you -need to re-specify the pair\_style and pair\_coeff commands in an input +need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_lebedeva_z.rst b/doc/src/pair_lebedeva_z.rst index b8217ccdcc..df81d83999 100644 --- a/doc/src/pair_lebedeva_z.rst +++ b/doc/src/pair_lebedeva_z.rst @@ -48,7 +48,7 @@ The parameter file (e.g. CC.Lebedeva), is intended for use with metal is available to facilitate scaling of energies. This potential must be used in combination with hybrid/overlay. -Other interactions can be set to zero using pair\_style *none*\ . +Other interactions can be set to zero using pair_style *none*\ . Restrictions """""""""""" diff --git a/doc/src/pair_line_lj.rst b/doc/src/pair_line_lj.rst index 908b912aea..70077c61f8 100644 --- a/doc/src/pair_line_lj.rst +++ b/doc/src/pair_line_lj.rst @@ -49,7 +49,7 @@ each pair of points. The LJ interaction between 2 spheres on different line segments (or a sphere on a line segment and a point particles) is computed with sub-particle :math:`\epsilon`, :math:`\sigma`, and *cutoff* values that -are set by the pair\_coeff command, as described below. If the distance +are set by the pair_coeff command, as described below. If the distance between the 2 spheres is greater than the sub-particle cutoff, there is no interaction. This means that some pairs of sub-particles on 2 line segments may interact, but others may not. @@ -57,8 +57,8 @@ segments may interact, but others may not. For purposes of creating the neighbor list for pairs of interacting line segments or lines/point particles, a regular particle-particle cutoff is used, as defined by the *cutoff* setting above in the -pair\_style command or overridden with an optional argument in the -pair\_coeff command for a type pair as discussed below. The distance +pair_style command or overridden with an optional argument in the +pair_coeff command for a type pair as discussed below. The distance between the centers of 2 line segments, or the center of a line segment and a point particle, must be less than this distance (plus the neighbor skin; see the :doc:`neighbor ` command), for @@ -69,7 +69,7 @@ the pair of particles to be included in the neighbor list. This means that a too-short value for the *cutoff* setting can exclude a pair of particles from the neighbor list even if pairs of their sub-particle spheres would interact, based on the sub-particle - cutoff specified in the pair\_coeff command. E.g. sub-particles at the + cutoff specified in the pair_coeff command. E.g. sub-particles at the ends of the line segments that are close to each other. Which may not be what you want, since it means the ends of 2 line segments could pass through each other. It is up to you to specify a *cutoff* @@ -93,7 +93,7 @@ The *sizeI* and *sizeJ* coefficients are the sub-particle sizes for line particles of type I and type J. They are used to define the N sub-particles per segment as described above. These coefficients are actually stored on a per-type basis. Thus if there are multiple -pair\_coeff commands that involve type I, as either the first or +pair_coeff commands that involve type I, as either the first or second atom type, you should use consistent values for sizeI or sizeJ in all of them. If you do not do this, the last value specified for sizeI will apply to all segments of type I. If typeI or typeJ refers diff --git a/doc/src/pair_list.rst b/doc/src/pair_list.rst index e3fc4ac682..93485b3471 100644 --- a/doc/src/pair_list.rst +++ b/doc/src/pair_list.rst @@ -32,7 +32,7 @@ Description Style *list* computes interactions between explicitly listed pairs of atoms with the option to select functional form and parameters for each individual pair. Because the parameters are set in the list -file, the pair\_coeff command has no parameters (but still needs to be +file, the pair_coeff command has no parameters (but still needs to be provided). The *check* and *nocheck* keywords enable/disable a test that checks whether all listed bonds were present and computed. @@ -119,7 +119,7 @@ pair style. The :doc:`pair_modify ` table and tail options are not relevant for this pair style. -This pair style does not write its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands need +This pair style does not write its information to :doc:`binary restart files `, so pair_style and pair_coeff commands need to be specified in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_lj.rst b/doc/src/pair_lj.rst index a0b49ee577..21357ab45f 100644 --- a/doc/src/pair_lj.rst +++ b/doc/src/pair_lj.rst @@ -225,7 +225,7 @@ Style *lj/cut/coul/cut* adds a Coulombic pairwise interaction given by where C is an energy-conversion constant, :math:`q_i` and :math:`q_j` are the charges on the 2 atoms, and :math:`\epsilon` is the dielectric constant which can be set by the :doc:`dielectric ` command. -If one cutoff is specified in the pair\_style command, it is used for +If one cutoff is specified in the pair_style command, it is used for both the LJ and Coulombic terms. If two cutoffs are specified, they are used as cutoffs for the LJ and Coulombic terms respectively. @@ -298,7 +298,7 @@ site located a short distance away from the oxygen atom along the bisector of the HOH angle. The atomic types of the oxygen and hydrogen atoms, the bond and angle types for OH and HOH interactions, and the distance to the massless charge site are specified as -pair\_style arguments. Style *lj/cut/tip4p/cut* uses a cutoff for +pair_style arguments. Style *lj/cut/tip4p/cut* uses a cutoff for Coulomb interactions; style *lj/cut/tip4p/long* is for use with a long-range Coulombic solver (Ewald or PPPM). @@ -337,7 +337,7 @@ Note that :math:`\sigma` is defined in the LJ formula as the zero-crossing distance for the potential, not as the energy minimum at :math:`2^{\frac{1}{6}} \sigma`. The latter 2 coefficients are optional. If not specified, the global -LJ and Coulombic cutoffs specified in the pair\_style command are used. +LJ and Coulombic cutoffs specified in the pair_style command are used. If only one cutoff is specified, it is used as the cutoff for both LJ and Coulombic interactions for this type pair. If both coefficients are specified, they are used as the LJ and Coulombic cutoffs for this @@ -348,7 +348,7 @@ For *lj/cut/coul/long* and *lj/cut/coul/msm* and *lj/cut/tip4p/cut* and *lj/cut/tip4p/long* only the LJ cutoff can be specified since a Coulombic cutoff cannot be specified for an individual I,J type pair. All type pairs use the same global Coulombic cutoff specified in the -pair\_style command. +pair_style command. ---------- @@ -385,7 +385,7 @@ instructions on how to use the accelerated styles effectively. For atom type pairs I,J and I != J, the epsilon and sigma coefficients and cutoff distance for all of the lj/cut pair styles can be mixed. -The default mix value is *geometric*\ . See the "pair\_modify" command +The default mix value is *geometric*\ . See the "pair_modify" command for details. All of the *lj/cut* pair styles support the @@ -401,13 +401,13 @@ All of the *lj/cut* pair styles support the tail correction to the energy and pressure for the Lennard-Jones portion of the pair interaction. -All of the *lj/cut* pair styles write their information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do +All of the *lj/cut* pair styles write their information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. The *lj/cut* and *lj/cut/coul/long* pair styles support the use of the *inner*\ , *middle*\ , and *outer* keywords of the :doc:`run_style respa ` command, meaning the pairwise forces can be partitioned by distance at different levels of the rRESPA hierarchy. -The other styles only support the *pair* keyword of run\_style respa. +The other styles only support the *pair* keyword of run_style respa. See the :doc:`run_style ` command for details. ---------- diff --git a/doc/src/pair_lj96.rst b/doc/src/pair_lj96.rst index 7c81803e34..3799020a05 100644 --- a/doc/src/pair_lj96.rst +++ b/doc/src/pair_lj96.rst @@ -52,7 +52,7 @@ commands, or by mixing as described below: * cutoff (distance units) The last coefficient is optional. If not specified, the global LJ -cutoff specified in the pair\_style command is used. +cutoff specified in the pair_style command is used. ---------- @@ -80,7 +80,7 @@ instructions on how to use the accelerated styles effectively. For atom type pairs I,J and I != J, the epsilon and sigma coefficients and cutoff distance for all of the lj/cut pair styles can be mixed. -The default mix value is *geometric*\ . See the "pair\_modify" command +The default mix value is *geometric*\ . See the "pair_modify" command for details. This pair style supports the :doc:`pair_modify ` shift @@ -93,7 +93,7 @@ This pair style supports the :doc:`pair_modify ` tail option for adding a long-range tail correction to the energy and pressure of the pair interaction. -This pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. This pair style supports the use of the *inner*\ , *middle*\ , and *outer* diff --git a/doc/src/pair_lj_cubic.rst b/doc/src/pair_lj_cubic.rst index 52f42e5e13..5bf5d873e4 100644 --- a/doc/src/pair_lj_cubic.rst +++ b/doc/src/pair_lj_cubic.rst @@ -94,7 +94,7 @@ instructions on how to use the accelerated styles effectively. For atom type pairs I,J and I != J, the epsilon and sigma coefficients and cutoff distance for all of the lj/cut pair styles can be mixed. -The default mix value is *geometric*\ . See the "pair\_modify" command +The default mix value is *geometric*\ . See the "pair_modify" command for details. The lj/cubic pair style does not support the @@ -110,7 +110,7 @@ The lj/cubic pair style does not support the corrections to energy and pressure, since there are no corrections for a potential that goes to 0.0 at the cutoff. -The lj/cubic pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do +The lj/cubic pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. The lj/cubic pair style can only be used via the *pair* diff --git a/doc/src/pair_lj_expand.rst b/doc/src/pair_lj_expand.rst index f27eb83631..1478188bbb 100644 --- a/doc/src/pair_lj_expand.rst +++ b/doc/src/pair_lj_expand.rst @@ -78,7 +78,7 @@ used. For *lj/expand/coul/long* only the LJ cutoff can be specified since a Coulombic cutoff cannot be specified for an individual I,J type pair. All type pairs use the same global Coulombic cutoff specified in the -pair\_style command. +pair_style command. ---------- @@ -107,8 +107,8 @@ instructions on how to use the accelerated styles effectively. For atom type pairs I,J and I != J, the epsilon, sigma, and shift coefficients and cutoff distance for this pair style can be mixed. Shift is always mixed via an *arithmetic* rule. The other -coefficients are mixed according to the pair\_modify mix value. The -default mix value is *geometric*\ . See the "pair\_modify" command for +coefficients are mixed according to the pair_modify mix value. The +default mix value is *geometric*\ . See the "pair_modify" command for details. This pair style supports the :doc:`pair_modify ` shift @@ -121,7 +121,7 @@ This pair style supports the :doc:`pair_modify ` tail option for adding a long-range tail correction to the energy and pressure of the pair interaction. -This pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_lj_long.rst b/doc/src/pair_lj_long.rst index 7a256256fc..682f11b95b 100644 --- a/doc/src/pair_lj_long.rst +++ b/doc/src/pair_lj_long.rst @@ -90,13 +90,13 @@ potential parameters, plus the Coulomb potential, given by: where C is an energy-conversion constant, :math:`q_i` and :math:`q_j` are the charges on the 2 atoms, :math:`\epsilon` is the dielectric constant which can be set by the :doc:`dielectric ` command, and :math:`r_c` is the cutoff. If -one cutoff is specified in the pair\_style command, it is used for both +one cutoff is specified in the pair_style command, it is used for both the LJ and Coulombic terms. If two cutoffs are specified, they are used as cutoffs for the LJ and Coulombic terms respectively. The purpose of this pair style is to capture long-range interactions resulting from both attractive 1/r\^6 Lennard-Jones and Coulombic 1/r -interactions. This is done by use of the *flag\_lj* and *flag\_coul* +interactions. This is done by use of the *flag_lj* and *flag_coul* settings. The :ref:`In 't Veld ` paper has more details on when it is appropriate to include long-range 1/r\^6 interactions, using this potential. @@ -106,7 +106,7 @@ Style *lj/long/tip4p/long* implements the TIP4P water model of short distance away from the oxygen atom along the bisector of the HOH angle. The atomic types of the oxygen and hydrogen atoms, the bond and angle types for OH and HOH interactions, and the distance to the -massless charge site are specified as pair\_style arguments. +massless charge site are specified as pair_style arguments. .. note:: @@ -126,22 +126,22 @@ LJ cutoff >= Coulombic cutoff + 2\*qdist, to shrink the size of the neighbor list. This leads to slightly larger cost for the long-range calculation, so you can test the trade-off for your model. -If *flag\_lj* is set to *long*\ , no cutoff is used on the LJ 1/r\^6 +If *flag_lj* is set to *long*\ , no cutoff is used on the LJ 1/r\^6 dispersion term. The long-range portion can be calculated by using the :doc:`kspace_style ewald/disp or pppm/disp ` commands. The specified LJ cutoff then determines which portion of the LJ interactions are computed directly by the pair potential versus which part is computed in reciprocal space via the Kspace style. If -*flag\_lj* is set to *cut*\ , the LJ interactions are simply cutoff, as +*flag_lj* is set to *cut*\ , the LJ interactions are simply cutoff, as with :doc:`pair_style lj/cut `. -If *flag\_coul* is set to *long*\ , no cutoff is used on the Coulombic +If *flag_coul* is set to *long*\ , no cutoff is used on the Coulombic interactions. The long-range portion can calculated by using any of several :doc:`kspace_style ` command options such as -*pppm* or *ewald*\ . Note that if *flag\_lj* is also set to long, then +*pppm* or *ewald*\ . Note that if *flag_lj* is also set to long, then the *ewald/disp* or *pppm/disp* Kspace style needs to be used to perform the long-range calculations for both the LJ and Coulombic -interactions. If *flag\_coul* is set to *off*\ , Coulombic interactions +interactions. If *flag_coul* is set to *off*\ , Coulombic interactions are not computed. The following coefficients must be defined for each pair of atoms @@ -160,22 +160,22 @@ distance for the potential, not as the energy minimum at 2\^(1/6) sigma. The latter 2 coefficients are optional. If not specified, the global -LJ and Coulombic cutoffs specified in the pair\_style command are used. +LJ and Coulombic cutoffs specified in the pair_style command are used. If only one cutoff is specified, it is used as the cutoff for both LJ and Coulombic interactions for this type pair. If both coefficients are specified, they are used as the LJ and Coulombic cutoffs for this type pair. -Note that if you are using *flag\_lj* set to *long*\ , you +Note that if you are using *flag_lj* set to *long*\ , you cannot specify a LJ cutoff for an atom type pair, since only one -global LJ cutoff is allowed. Similarly, if you are using *flag\_coul* +global LJ cutoff is allowed. Similarly, if you are using *flag_coul* set to *long*\ , you cannot specify a Coulombic cutoff for an atom type pair, since only one global Coulombic cutoff is allowed. For *lj/long/tip4p/long* only the LJ cutoff can be specified since a Coulombic cutoff cannot be specified for an individual I,J type pair. All type pairs use the same global Coulombic cutoff -specified in the pair\_style command. +specified in the pair_style command. ---------- @@ -210,12 +210,12 @@ instructions on how to use the accelerated styles effectively. For atom type pairs I,J and I != J, the epsilon and sigma coefficients and cutoff distance for all of the lj/long pair styles can be mixed. -The default mix value is *geometric*\ . See the "pair\_modify" command +The default mix value is *geometric*\ . See the "pair_modify" command for details. These pair styles support the :doc:`pair_modify ` shift option for the energy of the Lennard-Jones portion of the pair -interaction, assuming *flag\_lj* is *cut*\ . +interaction, assuming *flag_lj* is *cut*\ . These pair styles support the :doc:`pair_modify ` table and table/disp options since they can tabulate the short-range portion of @@ -225,7 +225,7 @@ Thes pair styles do not support the :doc:`pair_modify ` tail option for adding a long-range tail correction to the Lennard-Jones portion of the energy and pressure. -These pair styles write their information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +These pair styles write their information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. The pair lj/long/coul/long styles support the use of the *inner*\ , diff --git a/doc/src/pair_lj_smooth.rst b/doc/src/pair_lj_smooth.rst index 182de5b40c..b2cf6f7493 100644 --- a/doc/src/pair_lj_smooth.rst +++ b/doc/src/pair_lj_smooth.rst @@ -96,8 +96,8 @@ instructions on how to use the accelerated styles effectively. For atom type pairs I,J and I != J, the epsilon, sigma, Rin coefficients and the cutoff distance for this pair style can be mixed. Rin is a cutoff value and is mixed like the cutoff. The other -coefficients are mixed according to the pair\_modify mix option. The -default mix value is *geometric*\ . See the "pair\_modify" command for +coefficients are mixed according to the pair_modify mix option. The +default mix value is *geometric*\ . See the "pair_modify" command for details. This pair style supports the :doc:`pair_modify ` shift @@ -111,7 +111,7 @@ tail option for adding long-range tail corrections to energy and pressure, since the energy of the pair interaction is smoothed to 0.0 at the cutoff. -This pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_lj_smooth_linear.rst b/doc/src/pair_lj_smooth_linear.rst index 41f980d75f..bb93eddd33 100644 --- a/doc/src/pair_lj_smooth_linear.rst +++ b/doc/src/pair_lj_smooth_linear.rst @@ -50,7 +50,7 @@ commands, or by mixing as described below: * cutoff (distance units) The last coefficient is optional. If not specified, the global -LJ cutoff specified in the pair\_style command is used. +LJ cutoff specified in the pair_style command is used. ---------- @@ -78,7 +78,7 @@ instructions on how to use the accelerated styles effectively. For atom type pairs I,J and I != J, the epsilon and sigma coefficients and cutoff distance can be mixed. The default mix value is geometric. -See the "pair\_modify" command for details. +See the "pair_modify" command for details. This pair style does not support the :doc:`pair_modify ` shift option for the energy of the pair interaction, since it goes @@ -92,7 +92,7 @@ tail option for adding long-range tail corrections to energy and pressure, since the energy of the pair interaction is smoothed to 0.0 at the cutoff. -This pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_lj_switch3_coulgauss_long.rst b/doc/src/pair_lj_switch3_coulgauss_long.rst index 9f7ab4cf22..24374658e3 100644 --- a/doc/src/pair_lj_switch3_coulgauss_long.rst +++ b/doc/src/pair_lj_switch3_coulgauss_long.rst @@ -41,7 +41,7 @@ vdW potential E = 4\epsilon \left[ \left(\frac{\sigma}{r}\right)^{12}-\left(\frac{\sigma}{r}\right)^{6} \right] -, which goes smoothly to zero at the cutoff r\_c as defined +, which goes smoothly to zero at the cutoff r_c as defined by the switching function .. math:: diff --git a/doc/src/pair_local_density.rst b/doc/src/pair_local_density.rst index 4b7564266e..f2510686a9 100644 --- a/doc/src/pair_local_density.rst +++ b/doc/src/pair_local_density.rst @@ -47,8 +47,8 @@ upon initialization. .. note:: Thus when used as the only interaction in the system, there is no - corresponding pair\_coeff command and when used with other pair styles using the - hybrid/overlay option, the corresponding pair\_coeff command must be supplied + corresponding pair_coeff command and when used with other pair styles using the + hybrid/overlay option, the corresponding pair_coeff command must be supplied \* \* as placeholders for the atom types. ---------- @@ -139,14 +139,14 @@ which atom types to use in the calculation of the LD; :math:`b_{\beta} = Of course, a system with many atom types may have many different possible LD potentials, each with their own atom type filters, cutoffs, and embedding functions. The most general form of this potential as implemented in the -pair\_style local/density is: +pair_style local/density is: .. math:: U_{LD} = \sum_k U_{LD}^{(k)} = \sum_i \left[ \sum_k a_\alpha^{(k)} F^{(k)} \left(\rho_i^{(k)}\right) \right] where, *k* is an index that spans the (arbitrary) number of applied LD -potentials N\_LD. Each LD is calculated as before with: +potentials N_LD. Each LD is calculated as before with: .. math:: @@ -154,12 +154,12 @@ potentials N\_LD. Each LD is calculated as before with: The superscript on the indicator function phi simply indicates that it is associated with specific values of the cutoff distances R1(k) and R2(k). In -summary, there may be N\_LD distinct LD potentials. With each potential type (k), +summary, there may be N_LD distinct LD potentials. With each potential type (k), one must specify: * the inner and outer cutoffs as R1 and R2 -* the central type filter a(k), where k = 1,2,...N\_LD -* the neighbor type filter b(k), where k = 1,2,...N\_LD +* the central type filter a(k), where k = 1,2,...N_LD +* the neighbor type filter b(k), where k = 1,2,...N_LD * the LD potential function F(k)(rho), typically as a table that is later spline-interpolated ---------- @@ -189,8 +189,8 @@ one must specify: Block N_LD -Lines 5 to 9+N\_rho constitute the first block. Thus the input file is separated -(by blank lines) into N\_LD blocks each representing a separate LD potential and +Lines 5 to 9+N_rho constitute the first block. Thus the input file is separated +(by blank lines) into N_LD blocks each representing a separate LD potential and each specifying its own upper and lower cutoffs, central and neighbor atoms, and potential. In general, blank lines anywhere are ignored. @@ -211,7 +211,7 @@ This pair style does not support the :doc:`pair_modify ` shift, table, and tail options. The local/density pair style does not write its information to :doc:`binary restart files `, since it is stored in tabulated potential files. -Thus, you need to re-specify the pair\_style and pair\_coeff commands in +Thus, you need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. ---------- diff --git a/doc/src/pair_lubricate.rst b/doc/src/pair_lubricate.rst index 602d40de6b..563b88920e 100644 --- a/doc/src/pair_lubricate.rst +++ b/doc/src/pair_lubricate.rst @@ -96,7 +96,7 @@ particles, :math:`U^{\infty}` represents the velocity and the angular velocity of the undisturbed fluid, and :math:`E^{\infty}` represents the rate of strain tensor of the undisturbed fluid with viscosity *mu*\ . Again, note that this is dynamic viscosity which has units of mass/distance/time, not -kinematic viscosity. Volume fraction corrections to R\_FU are included +kinematic viscosity. Volume fraction corrections to R_FU are included as long as *flagVF* is set to 1 (default). .. note:: @@ -110,7 +110,7 @@ Style *lubricate* requires monodisperse spherical particles; style *lubricate/poly* allows for polydisperse spherical particles. The viscosity *mu* can be varied in a time-dependent manner over the -course of a simulation, in which case in which case the pair\_style +course of a simulation, in which case in which case the pair_style setting for *mu* will be overridden. See the :doc:`fix adapt ` command for details. @@ -118,9 +118,9 @@ If the suspension is sheared via the :doc:`fix deform ` command then the pair style uses the shear rate to adjust the hydrodynamic interactions accordingly. Volume changes due to fix deform are accounted for when computing the volume fraction -corrections to R\_FU. +corrections to R_FU. -When computing the volume fraction corrections to R\_FU, the presence +When computing the volume fraction corrections to R_FU, the presence of walls (whether moving or stationary) will affect the volume fraction available to colloidal particles. This is currently accounted for with the following types of walls: :doc:`wall/lj93 `, @@ -151,7 +151,7 @@ commands, or by mixing as described below: * cutoff (distance units) The two coefficients are optional. If neither is specified, the two -cutoffs specified in the pair\_style command are used. Otherwise both +cutoffs specified in the pair_style command are used. Otherwise both must be specified. ---------- @@ -180,7 +180,7 @@ instructions on how to use the accelerated styles effectively. For atom type pairs I,J and I != J, the two cutoff distances for this pair style can be mixed. The default mix value is *geometric*\ . See -the "pair\_modify" command for details. +the "pair_modify" command for details. This pair style does not support the :doc:`pair_modify ` shift option for the energy of the pair interaction. @@ -192,7 +192,7 @@ This pair style does not support the :doc:`pair_modify ` tail option for adding long-range tail corrections to energy and pressure. -This pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the @@ -207,10 +207,10 @@ Restrictions These styles are part of the COLLOID package. They are only enabled if LAMMPS was built with that package. See the :doc:`Build package ` doc page for more info. -Only spherical monodisperse particles are allowed for pair\_style +Only spherical monodisperse particles are allowed for pair_style lubricate. -Only spherical particles are allowed for pair\_style lubricate/poly. +Only spherical particles are allowed for pair_style lubricate/poly. These pair styles will not restart exactly when using the :doc:`read_restart ` command, though they should provide diff --git a/doc/src/pair_lubricateU.rst b/doc/src/pair_lubricateU.rst index eaf71ac79e..5b485746c8 100644 --- a/doc/src/pair_lubricateU.rst +++ b/doc/src/pair_lubricateU.rst @@ -90,7 +90,7 @@ velocities of the undisturbed fluid, and :math:`E^{\infty}` represents the rate of strain tensor of the undisturbed fluid flow with viscosity *mu*\ . Again, note that this is dynamic viscosity which has units of mass/distance/time, not kinematic viscosity. Volume fraction -corrections to R\_FU are included if *flagVF* is set to 1 (default). +corrections to R_FU are included if *flagVF* is set to 1 (default). F\ *rest* represents the forces and torques due to all other types of interactions, e.g. Brownian, electrostatic etc. Note that this @@ -123,9 +123,9 @@ If the suspension is sheared via the :doc:`fix deform ` command then the pair style uses the shear rate to adjust the hydrodynamic interactions accordingly. Volume changes due to fix deform are accounted for when computing the volume fraction -corrections to R\_FU. +corrections to R_FU. -When computing the volume fraction corrections to R\_FU, the presence +When computing the volume fraction corrections to R_FU, the presence of walls (whether moving or stationary) will affect the volume fraction available to colloidal particles. This is currently accounted for with the following types of walls: :doc:`wall/lj93 `, @@ -133,7 +133,7 @@ for with the following types of walls: :doc:`wall/lj93 `, :doc:`wall/harmonic `. For these wall styles, the correct volume fraction will be used when walls do not coincide with the box boundary, as well as when walls move and thereby cause a change in the -volume fraction. To use these wall styles with pair\_style *lubricateU* +volume fraction. To use these wall styles with pair_style *lubricateU* or *lubricateU/poly*\ , the *fld yes* option must be specified in the fix wall command. @@ -156,7 +156,7 @@ commands, or by mixing as described below: * cutoff (distance units) The two coefficients are optional. If neither is specified, the two -cutoffs specified in the pair\_style command are used. Otherwise both +cutoffs specified in the pair_style command are used. Otherwise both must be specified. ---------- @@ -165,7 +165,7 @@ must be specified. For atom type pairs I,J and I != J, the two cutoff distances for this pair style can be mixed. The default mix value is *geometric*\ . See -the "pair\_modify" command for details. +the "pair_modify" command for details. This pair style does not support the :doc:`pair_modify ` shift option for the energy of the pair interaction. @@ -177,7 +177,7 @@ This pair style does not support the :doc:`pair_modify ` tail option for adding long-range tail corrections to energy and pressure. -This pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the @@ -199,10 +199,10 @@ the pair styles, and that no fixes apply additional constraint forces. One exception is the :doc:`fix wall/colloid ` commands, which has an "fld" option to apply their wall forces correctly. -Only spherical monodisperse particles are allowed for pair\_style +Only spherical monodisperse particles are allowed for pair_style lubricateU. -Only spherical particles are allowed for pair\_style lubricateU/poly. +Only spherical particles are allowed for pair_style lubricateU/poly. For sheared suspensions, it is assumed that the shearing is done in the xy plane, with x being the velocity direction and y being the diff --git a/doc/src/pair_mdf.rst b/doc/src/pair_mdf.rst index 52120eab61..983e817f1d 100644 --- a/doc/src/pair_mdf.rst +++ b/doc/src/pair_mdf.rst @@ -80,7 +80,7 @@ outer cutoff radius. ---------- -For the *lj/mdf* pair\_style, the potential energy, *E(r)*\ , is the +For the *lj/mdf* pair_style, the potential energy, *E(r)*\ , is the standard 12-6 Lennard-Jones written in the epsilon/sigma form: .. math:: @@ -88,7 +88,7 @@ standard 12-6 Lennard-Jones written in the epsilon/sigma form: E(r) = 4\epsilon\biggl[\bigl(\frac{\sigma}{r}\bigr)^{12} - \bigl(\frac{\sigma}{r}\bigr)^6\biggr] Either the first two or all of the following coefficients must be -defined for each pair of atoms types via the pair\_coeff command as in +defined for each pair of atoms types via the pair_coeff command as in the examples above, or in the data file read by the :doc:`read_data `. The two cutoffs default to the global values and :math:`\epsilon` and :math:`\sigma` can also be determined by mixing as @@ -101,7 +101,7 @@ described below: ---------- -For the *buck/mdf* pair\_style, the potential energy, *E(r)*\ , is the +For the *buck/mdf* pair_style, the potential energy, *E(r)*\ , is the standard Buckingham potential with three required coefficients. The two cutoffs can be omitted and default to the corresponding global values: @@ -118,7 +118,7 @@ global values: ---------- -For the *lennard/mdf* pair\_style, the potential energy, *E(r)*\ , is the +For the *lennard/mdf* pair_style, the potential energy, *E(r)*\ , is the standard 12-6 Lennard-Jones written in the A/B form: .. math:: @@ -126,8 +126,8 @@ standard 12-6 Lennard-Jones written in the A/B form: E(r) = \frac{A}{r^{12}} - \frac{B}{r^{6}} The following coefficients must be defined for each pair of atoms -types via the pair\_coeff command as in the examples above, or in the -data file read by the read\_data commands, or by mixing as described below. +types via the pair_coeff command as in the examples above, or in the +data file read by the read_data commands, or by mixing as described below. The two cutoffs default to their global values and must be either both given or both left out: @@ -143,7 +143,7 @@ given or both left out: For atom type pairs I,J and I != J, the :math:`\epsilon` and :math:`sigma` coefficients and cutoff distances for the lj/mdf pair style can be mixed. The default mix value is *geometric*\ . See the -"pair\_modify" command for details. The other two pair styles buck/mdf +"pair_modify" command for details. The other two pair styles buck/mdf and lennard/mdf do not support mixing, so all I,J pairs of coefficients must be specified explicitly. @@ -151,7 +151,7 @@ None of the lj/mdf, buck/mdf, or lennard/mdf pair styles supports the :doc:`pair_modify ` shift option or long-range tail corrections to pressure and energy. -These styles write their information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +These styles write their information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. These styles can only be used via the *pair* keyword of the :doc:`run_style respa ` command. They do not support the *inner*\ , diff --git a/doc/src/pair_meam_spline.rst b/doc/src/pair_meam_spline.rst index 7bf82da846..6c4da24625 100644 --- a/doc/src/pair_meam_spline.rst +++ b/doc/src/pair_meam_spline.rst @@ -64,7 +64,7 @@ distribution and have a ".meam.spline" file suffix. All of these files are parameterized in terms of LAMMPS :doc:`metal units `. Note that unlike for other potentials, cutoffs for spline-based MEAM -potentials are not set in the pair\_style or pair\_coeff command; they +potentials are not set in the pair_style or pair_coeff command; they are specified in the potential files themselves. Unlike the EAM pair style, which retrieves the atomic mass from the @@ -72,10 +72,10 @@ potential file, the spline-based MEAM potentials do not include mass information; thus you need to use the :doc:`mass ` command to specify it. -Only a single pair\_coeff command is used with the *meam/spline* style +Only a single pair_coeff command is used with the *meam/spline* style which specifies a potential file with parameters for all needed elements. These are mapped to LAMMPS atom types by specifying N -additional arguments after the filename in the pair\_coeff command, +additional arguments after the filename in the pair_coeff command, where N is the number of LAMMPS atom types: * filename @@ -86,7 +86,7 @@ to specify the path for the potential file. As an example, imagine the Ti.meam.spline file has values for Ti (old style). If your LAMMPS simulation has 3 atoms types and they are all to be -treated with this potentials, you would use the following pair\_coeff +treated with this potentials, you would use the following pair_coeff command: .. code-block:: LAMMPS @@ -143,8 +143,8 @@ This pair style does not support the :doc:`pair_modify ` shift, table, and tail options. The *meam/spline* pair style does not write its information to :doc:`binary restart files `, since it is stored in an external -potential parameter file. Thus, you need to re-specify the pair\_style -and pair\_coeff commands in an input script that reads a restart file. +potential parameter file. Thus, you need to re-specify the pair_style +and pair_coeff commands in an input script that reads a restart file. The *meam/spline* pair style can only be used via the *pair* keyword of the :doc:`run_style respa ` command. They do not support the diff --git a/doc/src/pair_meam_sw_spline.rst b/doc/src/pair_meam_sw_spline.rst index c61ae0a54f..ebb51795c2 100644 --- a/doc/src/pair_meam_sw_spline.rst +++ b/doc/src/pair_meam_sw_spline.rst @@ -50,7 +50,7 @@ distribution and have a ".meam.sw.spline" file suffix. All of these files are parameterized in terms of LAMMPS :doc:`metal units `. Note that unlike for other potentials, cutoffs for spline-based -MEAM+SW potentials are not set in the pair\_style or pair\_coeff +MEAM+SW potentials are not set in the pair_style or pair_coeff command; they are specified in the potential files themselves. Unlike the EAM pair style, which retrieves the atomic mass from the @@ -58,10 +58,10 @@ potential file, the spline-based MEAM+SW potentials do not include mass information; thus you need to use the :doc:`mass ` command to specify it. -Only a single pair\_coeff command is used with the meam/sw/spline style +Only a single pair_coeff command is used with the meam/sw/spline style which specifies a potential file with parameters for all needed elements. These are mapped to LAMMPS atom types by specifying N -additional arguments after the filename in the pair\_coeff command, +additional arguments after the filename in the pair_coeff command, where N is the number of LAMMPS atom types: * filename @@ -72,10 +72,10 @@ to specify the path for the potential file. As an example, imagine the Ti.meam.sw.spline file has values for Ti. If your LAMMPS simulation has 3 atoms types and they are all to be -treated with this potential, you would use the following pair\_coeff +treated with this potential, you would use the following pair_coeff command: -pair\_coeff \* \* Ti.meam.sw.spline Ti Ti Ti +pair_coeff \* \* Ti.meam.sw.spline Ti Ti Ti The 1st 2 arguments must be \* \* so as to span all LAMMPS atom types. The three Ti arguments map LAMMPS atom types 1,2,3 to the Ti element @@ -92,7 +92,7 @@ potentials. systems in the future. Example input scripts that use this pair style are provided -in the examples/USER/misc/meam\_sw\_spline directory. +in the examples/USER/misc/meam_sw_spline directory. ---------- @@ -106,8 +106,8 @@ shift, table, and tail options. The *meam/sw/spline* pair style does not write its information to :doc:`binary restart files `, since it is stored in an external -potential parameter file. Thus, you need to re-specify the pair\_style -and pair\_coeff commands in an input script that reads a restart file. +potential parameter file. Thus, you need to re-specify the pair_style +and pair_coeff commands in an input script that reads a restart file. The *meam/sw/spline* pair style can only be used via the *pair* keyword of the :doc:`run_style respa ` command. They do not diff --git a/doc/src/pair_meamc.rst b/doc/src/pair_meamc.rst index 098c3cb601..850be5b583 100644 --- a/doc/src/pair_meamc.rst +++ b/doc/src/pair_meamc.rst @@ -25,7 +25,7 @@ Description .. note:: The behavior of the MEAM potential for alloy systems has changed - as of November 2010; see description below of the mixture\_ref\_t + as of November 2010; see description below of the mixture_ref_t parameter Style *meam/c* computes pairwise interactions for a variety of materials @@ -65,13 +65,13 @@ distribution with a ".meam" suffix. All of these are parameterized in terms of LAMMPS :doc:`metal units `. Note that unlike for other potentials, cutoffs for MEAM potentials are -not set in the pair\_style or pair\_coeff command; they are specified in +not set in the pair_style or pair_coeff command; they are specified in the MEAM potential files themselves. -Only a single pair\_coeff command is used with the *meam* style which +Only a single pair_coeff command is used with the *meam* style which specifies two MEAM files and the element(s) to extract information for. The MEAM elements are mapped to LAMMPS atom types by specifying -N additional arguments after the 2nd filename in the pair\_coeff +N additional arguments after the 2nd filename in the pair_coeff command, where N is the number of LAMMPS atom types: * MEAM library file @@ -86,7 +86,7 @@ As an example, the potentials/library.meam file has generic MEAM settings for a variety of elements. The potentials/SiC.meam file has specific parameter settings for a Si and C alloy system. If your LAMMPS simulation has 4 atoms types and you want the 1st 3 to be Si, -and the 4th to be C, you would use the following pair\_coeff command: +and the 4th to be C, you would use the following pair_coeff command: .. code-block:: LAMMPS @@ -138,7 +138,7 @@ Cu and lat = dia or fcc. Because the library file is used by Fortran MD codes, these strings may be enclosed in single quotes, but this is not required. The other numeric parameters match values in the formulas above. The value of the "elt" string is what is used in the -pair\_coeff command to identify which settings from the library file +pair_coeff command to identify which settings from the library file you wish to read in. There can be multiple entries in the library file with the same "elt" value; LAMMPS reads the 1st matching entry it finds and ignores the rest. @@ -203,7 +203,7 @@ an index of 1 would refer to Si and an index of 2 to C. The recognized keywords for the parameter file are as follows: Ec, alpha, rho0, delta, lattce, attrac, repuls, nn2, Cmin, Cmax, rc, delr, -augt1, gsmooth\_factor, re +augt1, gsmooth_factor, re where @@ -320,20 +320,20 @@ automatically. When parameter values are fit using the modified density function, as in more recent literature, augt1 should be set to 0. -The mixture\_ref\_t parameter is available to match results with those +The mixture_ref_t parameter is available to match results with those of previous versions of lammps (before January 2011). Newer versions of lammps, by default, use the single-element values of the t parameters to compute the background reference density. This is the proper way to compute these parameters. Earlier versions of lammps used an alloy mixture averaged value of t to compute the background -reference density. Setting mixture\_ref\_t=1 gives the old behavior. -WARNING: using mixture\_ref\_t=1 will give results that are demonstrably +reference density. Setting mixture_ref_t=1 gives the old behavior. +WARNING: using mixture_ref_t=1 will give results that are demonstrably incorrect for second-neighbor MEAM, and non-standard for first-neighbor MEAM; this option is included only for matching with previous versions of lammps and should be avoided if possible. The parameters attrac and repuls, along with the integer selection -parameter erose\_form, can be used to modify the Rose energy function +parameter erose_form, can be used to modify the Rose energy function used to compute the pair potential. This function gives the energy of the reference state as a function of interatomic spacing. The form of this function is: @@ -357,9 +357,9 @@ recent published MEAM parameter sets, such as :ref:`(Valone) ` in March 2009. The current version is correct, but may show different behavior compared with earlier versions of lammps with the attrac and/or repuls parameters are non-zero. To obtain the previous default - form, use erose\_form = 1 (this form does not seem to appear in the + form, use erose_form = 1 (this form does not seem to appear in the literature). An alternative form (see e.g. :ref:`(Lee2) `) is - available using erose\_form = 2. + available using erose_form = 2. ---------- @@ -368,13 +368,13 @@ recent published MEAM parameter sets, such as :ref:`(Valone) ` For atom type pairs I,J and I != J, where types I and J correspond to two different element types, mixing is performed by LAMMPS with user-specifiable parameters as described above. You never need to -specify a pair\_coeff command with I != J arguments for this style. +specify a pair_coeff command with I != J arguments for this style. This pair style does not support the :doc:`pair_modify ` shift, table, and tail options. This pair style does not write its information to :doc:`binary restart files `, since it is stored in potential files. Thus, you -need to re-specify the pair\_style and pair\_coeff commands in an input +need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the @@ -416,7 +416,7 @@ Related commands **(Gullet)** Gullet, Wagner, Slepoy, SANDIA Report 2003-8782 (2003). This report may be accessed on-line via `this link `_. -.. _sandreport: http://infoserve.sandia.gov/sand\_doc/2003/038782.pdf +.. _sandreport: http://infoserve.sandia.gov/sand_doc/2003/038782.pdf .. _Lee: diff --git a/doc/src/pair_mesocnt.rst b/doc/src/pair_mesocnt.rst index c7c9059704..6d9ba79a31 100644 --- a/doc/src/pair_mesocnt.rst +++ b/doc/src/pair_mesocnt.rst @@ -106,7 +106,7 @@ shift, table, and tail options. The *mesocnt* pair style do not write their information to :doc:`binary restart files `, since it is stored in tabulated potential files. -Thus, you need to re-specify the pair\_style and pair\_coeff commands in +Thus, you need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_mesodpd.rst b/doc/src/pair_mesodpd.rst index 72c2a02a72..b2e8507d61 100644 --- a/doc/src/pair_mesodpd.rst +++ b/doc/src/pair_mesodpd.rst @@ -60,7 +60,7 @@ Description The *edpd* style computes the pairwise interactions and heat fluxes for eDPD particles following the formulations in -:ref:`(Li2014\_JCP) ` and :ref:`Li2015\_CC `. The time +:ref:`(Li2014_JCP) ` and :ref:`Li2015_CC `. The time evolution of an eDPD particle is governed by the conservation of momentum and energy given by @@ -106,7 +106,7 @@ where the mesoscopic heat friction :math:`\kappa` is given by \kappa = \frac{315k_B\upsilon }{2\pi \rho C_v r_{ct}^5}\frac{1}{Pr}, with :math:`\upsilon` being the kinematic viscosity. For more details, -see Eq.(15) in :ref:`(Li2014\_JCP) `. +see Eq.(15) in :ref:`(Li2014_JCP) `. The following coefficients must be defined in eDPD system for each pair of atom types via the :doc:`pair_coeff ` command as in @@ -114,11 +114,11 @@ the examples above. * A (force units) * :math:`\gamma` (force/velocity units) -* power\_f (positive real) +* power_f (positive real) * cutoff (distance units) * kappa (thermal conductivity units) -* power\_T (positive real) -* cutoff\_T (distance units) +* power_T (positive real) +* cutoff_T (distance units) * optional keyword = power or kappa The keyword *power* or *kappa* is optional. Both "power" and "kappa" @@ -127,7 +127,7 @@ dependence of the exponent :math:`s(T) = \mathrm{power}_f ( 1+c_1 (T-1) + c_2 (T-1)^2 + c_3 (T-1)^3 + c_4 (T-1)^4 )` and of the mesoscopic heat friction :math:`s_T(T) = \kappa (1 + c_1 (T-1) + c_2 (T-1)^2 + c_3 (T-1)^3 + c_4 (T-1)^4)`. If the keyword *power* or *kappa* is not -specified, the eDPD system will use constant power\_f and +specified, the eDPD system will use constant power_f and :math:`\kappa`, which is independent to temperature changes. ---------- @@ -144,7 +144,7 @@ via the :doc:`pair_coeff ` command as in the examples above. The *mdpd* style computes the many-body interactions between mDPD particles following the formulations in -:ref:`(Li2013\_POF) `. The dissipative and random forces are in +:ref:`(Li2013_POF) `. The dissipative and random forces are in the form same as the classical DPD, but the conservative force is local density dependent, which are given by @@ -166,14 +166,14 @@ The following coefficients must be defined for each pair of atom types via the * A (force units) * B (force units) * :math:`\gamma` (force/velocity units) -* cutoff\_c (distance units) -* cutoff\_d (distance units) +* cutoff_c (distance units) +* cutoff_d (distance units) ---------- The *tdpd* style computes the pairwise interactions and chemical concentration fluxes for tDPD particles following the formulations in -:ref:`(Li2015\_JCP) `. The time evolution of a tDPD particle is +:ref:`(Li2015_JCP) `. The time evolution of a tDPD particle is governed by the conservation of momentum and concentration given by .. math:: @@ -191,7 +191,7 @@ force :math:`F_{ij}^C` are expressed as \mathbf{F}_{ij}^{D} & = -\gamma {\omega_{D}}(r_{ij})(\mathbf{e}_{ij} \cdot \mathbf{v}_{ij})\mathbf{e}_{ij} \\ \mathbf{F}_{ij}^{R} & = \sigma {\omega_{R}}(r_{ij}){\xi_{ij}}\Delta t^{-1/2} \mathbf{e}_{ij} \\ \omega_{C}(r) & = 1 - r/r_c \\ - \omega_{D}(r) & = \omega^2_{R}(r) = (1-r/r_c)^{\rm power\_f} \\ + \omega_{D}(r) & = \omega^2_{R}(r) = (1-r/r_c)^{\rm power_f} \\ \sigma^2 = 2\gamma k_B T The concentration flux between two tDPD particles includes the Fickian @@ -202,13 +202,13 @@ by Q_{ij}^D & = -\kappa_{ij} w_{DC}(r_{ij}) \left( C_i - C_j \right) \\ Q_{ij}^R & = \epsilon_{ij}\left( C_i + C_j \right) w_{RC}(r_{ij}) \xi_{ij} \\ - w_{DC}(r_{ij}) & =w^2_{RC}(r_{ij}) = (1 - r/r_{cc})^{\rm power\_{cc}} \\ + w_{DC}(r_{ij}) & =w^2_{RC}(r_{ij}) = (1 - r/r_{cc})^{\rm power_{cc}} \\ \epsilon_{ij}^2 & = m_s^2\kappa_{ij}\rho where the parameters kappa and epsilon determine the strength of the Fickian and random fluxes. :math:`m_s` is the mass of a single solute molecule. In general, :math:`m_s` is much smaller than the mass of a -tDPD particle *m*\ . For more details, see :ref:`(Li2015\_JCP) +tDPD particle *m*\ . For more details, see :ref:`(Li2015_JCP) `. The following coefficients must be defined for each pair of atom types via the @@ -216,16 +216,16 @@ The following coefficients must be defined for each pair of atom types via the * A (force units) * :math:`\gamma` (force/velocity units) -* power\_f (positive real) +* power_f (positive real) * cutoff (distance units) -* cutoff\_CC (distance units) +* cutoff_CC (distance units) * :math:`\kappa_i` (diffusivity units) * :math:`\epsilon_i` (diffusivity units) -* power\_cc\_i (positive real) +* power_cc_i (positive real) The last 3 values must be repeated Nspecies times, so that values for each of the Nspecies chemical species are specified, as indicated by -the "I" suffix. In the first pair\_coeff example above for pair\_style +the "I" suffix. In the first pair_coeff example above for pair_style tdpd, Nspecies = 1. In the second example, Nspecies = 2, so 3 additional coeffs are specified (for species 2). @@ -236,7 +236,7 @@ additional coeffs are specified (for species 2). There are example scripts for using all these pair styles in examples/USER/meso. The example for an eDPD simulation models heat conduction with source terms analog of periodic Poiseuille flow -problem. The setup follows Fig.12 in :ref:`(Li2014\_JCP) `. The +problem. The setup follows Fig.12 in :ref:`(Li2014_JCP) `. The output of the short eDPD simulation (about 2 minutes on a single core) gives a temperature and density profiles as @@ -245,7 +245,7 @@ gives a temperature and density profiles as The example for a mDPD simulation models the oscillations of a liquid droplet started from a liquid film. The mDPD parameters are adopted -from :ref:`(Li2013\_POF) `. The short mDPD run (about 2 minutes +from :ref:`(Li2013_POF) `. The short mDPD run (about 2 minutes on a single core) generates a particle trajectory which can be visualized as follows. @@ -264,7 +264,7 @@ The example for a tDPD simulation computes the effective diffusion coefficient of a tDPD system using a method analogous to the periodic Poiseuille flow. The tDPD system is specified with two chemical species, and the setup follows Fig.1 in -:ref:`(Li2015\_JCP) `. The output of the short tDPD simulation +:ref:`(Li2015_JCP) `. The output of the short tDPD simulation (about one and a half minutes on a single core) gives the concentration profiles of the two chemical species as @@ -283,7 +283,7 @@ the :doc:`pair_modify ` shift, table, and tail options. The styles *edpd*\ , *mdpd*\ , *mdpd/rhosum* and *tdpd* do not write information to :doc:`binary restart files `. Thus, you need -to re-specify the pair\_style and pair\_coeff commands in an input script +to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. Restrictions @@ -307,22 +307,22 @@ Related commands ---------- -.. _Li2014\_JCP: +.. _Li2014_JCP: -**(Li2014\_JCP)** Li, Tang, Lei, Caswell, Karniadakis, J Comput Phys, +**(Li2014_JCP)** Li, Tang, Lei, Caswell, Karniadakis, J Comput Phys, 265: 113-127 (2014). DOI: 10.1016/j.jcp.2014.02.003. -.. _Li2015\_CC: +.. _Li2015_CC: -**(Li2015\_CC)** Li, Tang, Li, Karniadakis, Chem Commun, 51: 11038-11040 +**(Li2015_CC)** Li, Tang, Li, Karniadakis, Chem Commun, 51: 11038-11040 (2015). DOI: 10.1039/C5CC01684C. -.. _Li2013\_POF: +.. _Li2013_POF: -**(Li2013\_POF)** Li, Hu, Wang, Ma, Zhou, Phys Fluids, 25: 072103 (2013). +**(Li2013_POF)** Li, Hu, Wang, Ma, Zhou, Phys Fluids, 25: 072103 (2013). DOI: 10.1063/1.4812366. -.. _Li2015\_JCP: +.. _Li2015_JCP: -**(Li2015\_JCP)** Li, Yazdani, Tartakovsky, Karniadakis, J Chem Phys, +**(Li2015_JCP)** Li, Yazdani, Tartakovsky, Karniadakis, J Chem Phys, 143: 014101 (2015). DOI: 10.1063/1.4923254. diff --git a/doc/src/pair_mgpt.rst b/doc/src/pair_mgpt.rst index 562f1f5802..57fec82a7b 100644 --- a/doc/src/pair_mgpt.rst +++ b/doc/src/pair_mgpt.rst @@ -40,16 +40,16 @@ elemental bulk material in the form where the prime on each summation sign indicates the exclusion of all self-interaction terms from the summation. The leading volume term -E\_vol as well as the two-ion central-force pair potential v\_2 and the -three- and four-ion angular-force potentials, v\_3 and v\_4, depend +E_vol as well as the two-ion central-force pair potential v_2 and the +three- and four-ion angular-force potentials, v_3 and v_4, depend explicitly on the atomic volume Omega, but are structure independent and transferable to all bulk ion configurations, either ordered or disordered, and with of without the presence of point and line defects. The simplified model GPT or MGPT (:ref:`Moriarty2 `, -:ref:`Moriarty3 `), which retains the form of E\_tot and permits +:ref:`Moriarty3 `), which retains the form of E_tot and permits more efficient large-scale atomistic simulations, derives from the GPT -through a series of systematic approximations applied to E\_vol and the -potentials v\_n that are valid for mid-period transition metals with +through a series of systematic approximations applied to E_vol and the +potentials v_n that are valid for mid-period transition metals with nearly half-filled d bands. Both analytic (:ref:`Moriarty2 `) and matrix @@ -64,12 +64,12 @@ algorithms have been developed independently by Glosli (:ref:`Oppelstrup `) The *mgpt* pair style calculates forces, energies, and the total -energy per atom, E\_tot/N, using the Oppelstrup matrix-MGPT algorithm. +energy per atom, E_tot/N, using the Oppelstrup matrix-MGPT algorithm. Input potential and control data are entered through the :doc:`pair_coeff ` command. Each material treated requires input parmin and potin potential files, as shown in the above examples, as well as specification by the user of the initial atomic -volume Omega through pair\_coeff. At the beginning of a time step in +volume Omega through pair_coeff. At the beginning of a time step in any simulation, the total volume of the simulation cell V should always be equal to Omega\*N, where N is the number of metal ions present, taking into account the presence of any vacancies and/or @@ -79,25 +79,25 @@ style, Omega, V and N all remain constant throughout the simulation and thus are equal to their initial values. In a constant-stress simulation, the cell volume V will change (slowly) as the simulation proceeds. After each time step, the atomic volume should be updated -by the code as Omega = V/N. In addition, the volume term E\_vol and -the potentials v\_2, v\_3 and v\_4 have to be removed at the end of the +by the code as Omega = V/N. In addition, the volume term E_vol and +the potentials v_2, v_3 and v_4 have to be removed at the end of the time step, and then respecified at the new value of Omega. In all simulations, Omega must remain within the defined volume range for -E\_vol and the potentials for the given material. +E_vol and the potentials for the given material. The default option volpress yes in the :doc:`pair_coeff ` -command includes all volume derivatives of E\_tot required to calculate +command includes all volume derivatives of E_tot required to calculate the stress tensor and pressure correctly. The option volpress no disregards the pressure contribution resulting from the volume term -E\_vol, and can be used for testing and analysis purposes. The +E_vol, and can be used for testing and analysis purposes. The additional optional variable nbody controls the specific terms in -E\_tot that are calculated. The default option and the normal option +E_tot that are calculated. The default option and the normal option for mid-period transition and actinide metals is nbody 1234 for which -all four terms in E\_tot are retained. The option nbody 12, for +all four terms in E_tot are retained. The option nbody 12, for example, retains only the volume term and the two-ion pair potential term and can be used for GPT series-end transition metals that can be -well described without v\_3 and v\_4. The nbody option can also be used -to test or analyze the contribution of any of the four terms in E\_tot +well described without v_3 and v_4. The nbody option can also be used +to test or analyze the contribution of any of the four terms in E_tot to a given calculated property. The *mgpt* pair style makes extensive use of matrix algebra and @@ -155,7 +155,7 @@ This pair style does not support the :doc:`pair_modify ` mix, shift, table, and tail options. This pair style does not write its information to :doc:`binary restart files `, since it is stored in potential files. Thus, you -needs to re-specify the pair\_style and pair\_coeff commands in an input +needs to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the @@ -179,7 +179,7 @@ energies in Rydbergs and distances in Bohr radii. The *mgpt* pair style converts Rydbergs to Hartrees to make the potential files compatible with LAMMPS electron :doc:`units `. -The form of E\_tot used in the *mgpt* pair style is only appropriate +The form of E_tot used in the *mgpt* pair style is only appropriate for elemental bulk solids and liquids. This includes solids with point and extended defects such as vacancies, interstitials, grain boundaries and dislocations. Alloys and free surfaces, however, diff --git a/doc/src/pair_mie.rst b/doc/src/pair_mie.rst index 165ad7a787..527a568728 100644 --- a/doc/src/pair_mie.rst +++ b/doc/src/pair_mie.rst @@ -58,7 +58,7 @@ commands, or by mixing as described below: * cutoff (distance units) The last coefficient is optional. If not specified, the global -cutoff specified in the pair\_style command is used. +cutoff specified in the pair_style command is used. ---------- @@ -69,7 +69,7 @@ and cutoff distance for all of the mie/cut pair styles can be mixed. If not explicitly defined, both the repulsive and attractive gamma exponents for different atoms will be calculated following the same mixing rule defined for distances. The default mix value is -*geometric*\ . See the "pair\_modify" command for details. +*geometric*\ . See the "pair_modify" command for details. This pair style supports the :doc:`pair_modify ` shift option for the energy of the pair interaction. @@ -78,7 +78,7 @@ This pair style supports the :doc:`pair_modify ` tail option for adding a long-range tail correction to the energy and pressure of the pair interaction. -This pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. This pair style supports the use of the *inner*\ , *middle*\ , and *outer* diff --git a/doc/src/pair_mm3_switch3_coulgauss_long.rst b/doc/src/pair_mm3_switch3_coulgauss_long.rst index 537cdde457..1338682b95 100644 --- a/doc/src/pair_mm3_switch3_coulgauss_long.rst +++ b/doc/src/pair_mm3_switch3_coulgauss_long.rst @@ -43,7 +43,7 @@ vdW potential :ref:`(Allinger) ` r_{v,ij} & = r_{v,i} + r_{v,j} \\ \epsilon_{ij} & = \sqrt{\epsilon_i \epsilon_j} -, which goes smoothly to zero at the cutoff r\_c as defined +, which goes smoothly to zero at the cutoff r_c as defined by the switching function .. math:: diff --git a/doc/src/pair_modify.rst b/doc/src/pair_modify.rst index c248a3fcd0..b8969c0131 100644 --- a/doc/src/pair_modify.rst +++ b/doc/src/pair_modify.rst @@ -74,7 +74,7 @@ must be set explicitly, either in the input script via the :doc:`pair_coeff ` command or in the "Pair Coeffs" section of the :doc:`data file `. For some pair styles it is not necessary to specify coefficients when I != J, since a "mixing" rule -will create them from the I,I and J,J settings. The pair\_modify +will create them from the I,I and J,J settings. The pair_modify *mix* value determines what formulas are used to compute the mixed coefficients. In each case, the cutoff distance is mixed the same way as sigma. diff --git a/doc/src/pair_morse.rst b/doc/src/pair_morse.rst index 83fb897cdb..d031c70cd2 100644 --- a/doc/src/pair_morse.rst +++ b/doc/src/pair_morse.rst @@ -85,7 +85,7 @@ so that both, potential energy and force, go to zero at the cut-off: \phi\left(r\right) & = D_0 \left[ e^{- 2 \alpha (r - r_0)} - 2 e^{- \alpha (r - r_0)} \right] \qquad r < r_c \\ E\left(r\right) & = \phi\left(r\right) - \phi\left(R_c\right) - \left(r - R_c\right) \left.\frac{d\phi}{d r} \right|_{r=R_c} \qquad r < R_c -The syntax of the pair\_style and pair\_coeff commands are the same for +The syntax of the pair_style and pair_coeff commands are the same for the *morse* and *morse/smooth/linear* styles. ---------- @@ -134,7 +134,7 @@ None of these pair styles support the :doc:`pair_modify ` tail option for adding long-range tail corrections to energy and pressure. -All of these pair styles write their information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +All of these pair styles write their information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. These pair styles can only be used via the *pair* keyword of the diff --git a/doc/src/pair_multi_lucy.rst b/doc/src/pair_multi_lucy.rst index 4a412ca460..37da1ab965 100644 --- a/doc/src/pair_multi_lucy.rst +++ b/doc/src/pair_multi_lucy.rst @@ -110,7 +110,7 @@ A section begins with a non-blank line whose 1st character is not a "#"; blank lines or lines starting with "#" can be used as comments between sections. The first line begins with a keyword which identifies the section. The line can contain additional text, but the -initial text must match the argument specified in the pair\_coeff +initial text must match the argument specified in the pair_coeff command. The next line lists (in any order) one or more parameters for the table. Each parameter is a keyword followed by one or more numeric values. @@ -118,7 +118,7 @@ numeric values. The parameter "N" is required and its value is the number of table entries that follow. Note that this may be different than the *N* specified in the :doc:`pair_style multi/lucy ` command. -Let Ntable = *N* in the pair\_style command, and Nfile = "N" in the +Let Ntable = *N* in the pair_style command, and Nfile = "N" in the tabulated file. What LAMMPS does is a preliminary interpolation by creating splines using the Nfile tabulated values as nodal points. It uses these to interpolate the density-dependent energy and force at @@ -176,11 +176,11 @@ I,J pairs must be specified explicitly. The :doc:`pair_modify ` shift, table, and tail options are not relevant for this pair style. -This pair style writes the settings for the "pair\_style multi/lucy" command -to :doc:`binary restart files `, so a pair\_style command does +This pair style writes the settings for the "pair_style multi/lucy" command +to :doc:`binary restart files `, so a pair_style command does not need to specified in an input script that reads a restart file. However, the coefficient information is not stored in the restart -file, since it is tabulated in the potential files. Thus, pair\_coeff +file, since it is tabulated in the potential files. Thus, pair_coeff commands do need to be specified in the restart input script. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_multi_lucy_rx.rst b/doc/src/pair_multi_lucy_rx.rst index 6d9b00f1a1..3824ca96cf 100644 --- a/doc/src/pair_multi_lucy_rx.rst +++ b/doc/src/pair_multi_lucy_rx.rst @@ -138,7 +138,7 @@ A section begins with a non-blank line whose 1st character is not a "#"; blank lines or lines starting with "#" can be used as comments between sections. The first line begins with a keyword which identifies the section. The line can contain additional text, but the -initial text must match the argument specified in the pair\_coeff +initial text must match the argument specified in the pair_coeff command. The next line lists (in any order) one or more parameters for the table. Each parameter is a keyword followed by one or more numeric values. @@ -146,7 +146,7 @@ numeric values. The parameter "N" is required and its value is the number of table entries that follow. Note that this may be different than the *N* specified in the :doc:`pair_style multi/lucy/rx ` -command. Let Ntable = *N* in the pair\_style command, and Nfile = "N" +command. Let Ntable = *N* in the pair_style command, and Nfile = "N" in the tabulated file. What LAMMPS does is a preliminary interpolation by creating splines using the Nfile tabulated values as nodal points. It uses these to interpolate the density-dependent @@ -204,11 +204,11 @@ I,J pairs must be specified explicitly. The :doc:`pair_modify ` shift, table, and tail options are not relevant for this pair style. -This pair style writes the settings for the "pair\_style multi/lucy/rx" command -to :doc:`binary restart files `, so a pair\_style command does +This pair style writes the settings for the "pair_style multi/lucy/rx" command +to :doc:`binary restart files `, so a pair_style command does not need to specified in an input script that reads a restart file. However, the coefficient information is not stored in the restart -file, since it is tabulated in the potential files. Thus, pair\_coeff +file, since it is tabulated in the potential files. Thus, pair_coeff commands do need to be specified in the restart input script. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_nb3b_harmonic.rst b/doc/src/pair_nb3b_harmonic.rst index e039accd1a..c4f3f3c3e8 100644 --- a/doc/src/pair_nb3b_harmonic.rst +++ b/doc/src/pair_nb3b_harmonic.rst @@ -30,13 +30,13 @@ energy E of a system of atoms as where :math:`\theta_0` is the equilibrium value of the angle and *K* is a prefactor. Note that the usual 1/2 factor is included in *K*\ . The form -of the potential is identical to that used in angle\_style *harmonic*\ , +of the potential is identical to that used in angle_style *harmonic*\ , but in this case, the atoms do not need to be explicitly bonded. -Only a single pair\_coeff command is used with this style which +Only a single pair_coeff command is used with this style which specifies a potential file with parameters for specified elements. These are mapped to LAMMPS atom types by specifying N additional -arguments after the filename in the pair\_coeff command, where N is the +arguments after the filename in the pair_coeff command, where N is the number of LAMMPS atom types: * filename @@ -48,7 +48,7 @@ to specify the path for the potential file. As an example, imagine a file SiC.nb3b.harmonic has potential values for Si and C. If your LAMMPS simulation has 4 atoms types and you want the 1st 3 to be Si, and the 4th to be C, you would use the -following pair\_coeff command: +following pair_coeff command: .. code-block:: LAMMPS @@ -61,10 +61,10 @@ type 4 to the C element in the potential file. If a mapping value is specified as NULL, the mapping is not performed. This can be used when the potential is used as part of the *hybrid* pair style. The NULL values are placeholders for atom types that will be used with -other potentials. An example of a pair\_coeff command for use with the +other potentials. An example of a pair_coeff command for use with the *hybrid* pair style is: -pair\_coeff \* \* nb3b/harmonic MgOH.nb3b.harmonic Mg O H +pair_coeff \* \* nb3b/harmonic MgOH.nb3b.harmonic Mg O H Three-body non-bonded harmonic files in the *potentials* directory of the LAMMPS distribution have a ".nb3b.harmonic" suffix. Lines that @@ -86,7 +86,7 @@ the entry is for the *K* and :math:`\theta_0` parameters (the cutoff in this case is irrelevant). It is required that the potential file contains entries for *all* -permutations of the elements listed in the pair\_coeff command. +permutations of the elements listed in the pair_coeff command. If certain combinations are not parameterized the corresponding parameters should be set to zero. The potential file can also contain entries for additional elements which are not used in diff --git a/doc/src/pair_nm.rst b/doc/src/pair_nm.rst index c600432a06..196747b291 100644 --- a/doc/src/pair_nm.rst +++ b/doc/src/pair_nm.rst @@ -80,7 +80,7 @@ Style *nm/cut/coul/cut* adds a Coulombic pairwise interaction given by where :math:`C` is an energy-conversion constant, :math:`q_i` and :math:`q_j` are the charges on the 2 atoms, and epsilon is the dielectric constant which can be set by the :doc:`dielectric ` command. If one cutoff is -specified in the pair\_style command, it is used for both the N-M and Coulombic +specified in the pair_style command, it is used for both the N-M and Coulombic terms. If two cutoffs are specified, they are used as cutoffs for the N-M and Coulombic terms respectively. @@ -108,7 +108,7 @@ commands. * cutoff2 (distance units) The latter 2 coefficients are optional. If not specified, the global -N-M and Coulombic cutoffs specified in the pair\_style command are used. +N-M and Coulombic cutoffs specified in the pair_style command are used. If only one cutoff is specified, it is used as the cutoff for both N-M and Coulombic interactions for this type pair. If both coefficients are specified, they are used as the N-M and Coulombic cutoffs for this @@ -118,7 +118,7 @@ has no Coulombic terms. For *nm/cut/coul/long* only the N-M cutoff can be specified since a Coulombic cutoff cannot be specified for an individual I,J type pair. All type pairs use the same global Coulombic cutoff specified in the -pair\_style command. +pair_style command. ---------- @@ -139,7 +139,7 @@ All of the *nm* pair styles support the :doc:`pair_modify ` tail option for adding a long-range tail correction to the energy and pressure for the N-M portion of the pair interaction. -All of the *nm* pair styles write their information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +All of the *nm* pair styles write their information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. All of the *nm* pair styles can only be used via the *pair* keyword of diff --git a/doc/src/pair_peri.rst b/doc/src/pair_peri.rst index 2d95785fff..2b3d3e9b99 100644 --- a/doc/src/pair_peri.rst +++ b/doc/src/pair_peri.rst @@ -73,8 +73,8 @@ R. Rahman and J. T. Foster at University of Texas at San Antonio. The original VES formulation is described in "(Mitchell2011)" and the original EPS formulation is in "(Mitchell2011a)". Additional PDF docs that describe the VES and EPS implementations are include in the -LAMMPS distribution in `doc/PDF/PDLammps\_VES.pdf `_ and -`doc/PDF/PDLammps\_EPS.pdf `_. For questions +LAMMPS distribution in `doc/PDF/PDLammps_VES.pdf `_ and +`doc/PDF/PDLammps_EPS.pdf `_. For questions regarding the VES and EPS models in LAMMPS you can contact R. Rahman (rezwanur.rahman at utsa.edu). @@ -118,15 +118,15 @@ For the *peri/ves* style: * horizon (distance units) * s00 (unitless) * :math:`\alpha` (unitless) -* m\_lambdai (unitless) -* m\_taubi (unitless) +* m_lambdai (unitless) +* m_taubi (unitless) K is the bulk modulus and G is the shear modulus. The horizon is a cutoff distance for truncating interactions, and s00 and :math:`\alpha` are -used as a bond breaking criteria. m\_lambdai and m\_taubi are the +used as a bond breaking criteria. m_lambdai and m_taubi are the viscoelastic relaxation parameter and time constant, -respectively. m\_lambdai varies within zero to one. For very small -values of m\_lambdai the viscoelastic model responds very similar to a +respectively. m_lambdai varies within zero to one. For very small +values of m_lambdai the viscoelastic model responds very similar to a linear elastic model. For details please see the description in "(Mtchell2011)". @@ -137,11 +137,11 @@ For the *peri/eps* style: * horizon (distance units) * s00 (unitless) * :math:`\alpha` (unitless) -* m\_yield\_stress (force/area units) +* m_yield_stress (force/area units) K is the bulk modulus and G is the shear modulus. The horizon is a cutoff distance and s00 and :math:`\alpha` are used as a bond breaking -criteria. m\_yield\_stress is the yield stress of the material. For +criteria. m_yield_stress is the yield stress of the material. For details please see the description in "(Mtchell2011a)". ---------- @@ -177,7 +177,7 @@ shift option. The :doc:`pair_modify ` table and tail options are not relevant for these pair styles. -These pair styles write their information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +These pair styles write their information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. These pair styles can only be used via the *pair* keyword of the diff --git a/doc/src/pair_polymorphic.rst b/doc/src/pair_polymorphic.rst index 93de3fe65f..e06e9e7855 100644 --- a/doc/src/pair_polymorphic.rst +++ b/doc/src/pair_polymorphic.rst @@ -161,24 +161,24 @@ pair style is different from the sw pair style in this case. It just means that the definitions of the atom energies and atom stresses are different. -Only a single pair\_coeff command is used with the polymorphic style +Only a single pair_coeff command is used with the polymorphic style which specifies an potential file for all needed elements. These are mapped to LAMMPS atom types by specifying N additional arguments after -the filename in the pair\_coeff command, where N is the number of +the filename in the pair_coeff command, where N is the number of LAMMPS atom types: * filename * N element names = mapping of Tersoff elements to atom types -See the pair\_coeff doc page for alternate ways to specify the path for +See the pair_coeff doc page for alternate ways to specify the path for the potential file. Several files for polymorphic potentials are included in the potentials directory of the LAMMPS distribution. They have a "poly" suffix. -As an example, imagine the SiC\_tersoff.poly file has tabulated +As an example, imagine the SiC_tersoff.poly file has tabulated functions for Si-C tersoff potential. If your LAMMPS simulation has 4 atoms types and you want the 1st 3 to be Si, and the 4th to be C, you -would use the following pair\_coeff command: +would use the following pair_coeff command: .. parsed-literal:: @@ -204,7 +204,7 @@ and are ignored by LAMMPS. The next line lists two numbers: Here ntypes represent total number of species defined in the potential file, and :math:`\eta = 0` or 1. The number ntypes must equal the total -number of different species defined in the pair\_coeff command. When +number of different species defined in the pair_coeff command. When :math:`\eta = 1`, :math:\eta_{ij}` defined in the potential functions above is set to :math:`1 - \delta_{ij}`, otherwise :math:`\eta_{ij}` is set to :math:`\delta_{ij}`. The next ntypes lines each lists two numbers @@ -254,7 +254,7 @@ Tabulated functions are specified by spline n x1 x2, where n=number of point, (x1,x2)=range and then followed by n values evaluated uniformly over these argument ranges. The valid argument ranges of the functions are between 0 <= r <= cut for the U(r), V(r), W(r) -functions, -cutmax <= delta\_r <= cutmax for the P(delta\_r) functions, +functions, -cutmax <= delta_r <= cutmax for the P(delta_r) functions, -1 <= :math:`\cos\theta` <= 1 for the G(:math:`\cos\theta`) functions, and 0 <= X <= maxX for the F(X) functions. @@ -264,7 +264,7 @@ This pair styles does not support the :doc:`pair_modify ` shift, table, and tail options. This pair style does not write their information to :doc:`binary restart files `, since it is stored in potential files. Thus, you -need to re-specify the pair\_style and pair\_coeff commands in an input +need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. ---------- @@ -272,8 +272,8 @@ script that reads a restart file. Restrictions """""""""""" -If using create\_atoms command, atomic masses must be defined in the -input script. If using read\_data, atomic masses must be defined in the +If using create_atoms command, atomic masses must be defined in the +input script. If using read_data, atomic masses must be defined in the atomic structure data file. This pair style is part of the MANYBODY package. It is only enabled if diff --git a/doc/src/pair_python.rst b/doc/src/pair_python.rst index 886c9c2b53..fa76d4c16c 100644 --- a/doc/src/pair_python.rst +++ b/doc/src/pair_python.rst @@ -38,10 +38,10 @@ corresponding compiled code. This penalty can be significantly reduced through generating tabulations from the python code through the :doc:`pair_write ` command, which is supported by this style. -Only a single pair\_coeff command is used with the *python* pair style +Only a single pair_coeff command is used with the *python* pair style which specifies a python class inside a python module or file that LAMMPS will look up in the current directory, the folder pointed to by -the LAMMPS\_POTENTIALS environment variable or somewhere in your python +the LAMMPS_POTENTIALS environment variable or somewhere in your python path. A single python module can hold multiple python pair class definitions. The class definitions itself have to follow specific rules that are explained below. @@ -49,15 +49,15 @@ rules that are explained below. Atom types in the python class are specified through symbolic constants, typically strings. These are mapped to LAMMPS atom types by specifying N additional arguments after the class name in the -pair\_coeff command, where N must be the number of currently defined +pair_coeff command, where N must be the number of currently defined atom types: -As an example, imagine a file *py\_pot.py* has a python potential class +As an example, imagine a file *py_pot.py* has a python potential class names *LJCutMelt* with parameters and potential functions for a two Lennard-Jones atom types labeled as 'LJ1' and 'LJ2'. In your LAMMPS input and you would have defined 3 atom types, out of which the first two are supposed to be using the 'LJ1' parameters and the third the -'LJ2' parameters, then you would use the following pair\_coeff command: +'LJ2' parameters, then you would use the following pair_coeff command: .. code-block:: LAMMPS @@ -65,7 +65,7 @@ two are supposed to be using the 'LJ1' parameters and the third the The first two arguments **must** be \* \* so as to span all LAMMPS atom types. The first two LJ1 arguments map LAMMPS atom types 1 and 2 to -the LJ1 atom type in the LJCutMelt class of the py\_pot.py file. The +the LJ1 atom type in the LJCutMelt class of the py_pot.py file. The final LJ2 argument maps LAMMPS atom type 3 to the LJ2 atom type the python file. If a mapping value is specified as NULL, the mapping is not performed, any pair interaction with this atom type will be @@ -119,8 +119,8 @@ which the parameters epsilon and sigma are both 1.0: self.coeff = {'lj' : {'lj' : (48.0,24.0,4.0,4.0)}} The class also has to provide two methods for the computation of the -potential energy and forces, which have be named *compute\_force*, -and *compute\_energy*, which both take 3 numerical arguments: +potential energy and forces, which have be named *compute_force*, +and *compute_energy*, which both take 3 numerical arguments: * rsq = the square of the distance between a pair of atoms (float) * itype = the (numerical) type of the first atom @@ -153,7 +153,7 @@ the *LJCutMelt* example, here are the two functions: .. note:: for consistency with the C++ pair styles in LAMMPS, the - *compute\_force* function follows the conventions of the Pair::single() + *compute_force* function follows the conventions of the Pair::single() methods and does not return the full force, but the force scaled by the distance between the two atoms, so this value only needs to be multiplied by delta x, delta y, and delta z to conveniently obtain the @@ -178,7 +178,7 @@ the *LJCutMelt* example, here are the two functions: pair_write 1 1 2000 rsq 0.01 2.5 lj1_lj2.table lj Note that it is strongly recommended to try to **delete** the potential -table file before generating it. Since the *pair\_write* command will +table file before generating it. Since the *pair_write* command will always **append** to a table file, while pair style table will use the **first match**\ . Thus when changing the potential function in the python class, the table pair style will still read the old variant unless the @@ -209,7 +209,7 @@ This pair style does not support the :doc:`pair_modify ` shift, table, and tail options. This pair style does not write its information to :doc:`binary restart files `, since it is stored in potential files. Thus, you -need to re-specify the pair\_style and pair\_coeff commands in an input +need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_quip.rst b/doc/src/pair_quip.rst index 032519e4b6..7781f3a9fb 100644 --- a/doc/src/pair_quip.rst +++ b/doc/src/pair_quip.rst @@ -31,7 +31,7 @@ interface is chiefly intended to be used to run Gaussian Approximation Potentials (GAP), which are described in the following publications: :ref:`(Bartok et al) ` and :ref:`(PhD thesis of Bartok) `. -Only a single pair\_coeff command is used with the *quip* style that +Only a single pair_coeff command is used with the *quip* style that specifies a QUIP potential file containing the parameters of the potential for all needed elements in XML format. This is followed by a QUIP initialization string. Finally, the QUIP elements are mapped to @@ -64,7 +64,7 @@ This pair style does not support the :doc:`pair_modify ` mix, shift, table, and tail options. This pair style does not write its information to :doc:`binary restart files `, since it is stored in potential files. Thus, you -need to re-specify the pair\_style and pair\_coeff commands in an input +need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the @@ -83,7 +83,7 @@ therefore should be used with LAMMPS metal :doc:`units `. QUIP potentials are generally not designed to work with the scaling factors set by the :doc:`special_bonds ` command. The recommended setting in molecular systems is to include all -interactions, i.e. to use *special\_bonds lj/coul 1.0 1.0 1.0*. Scaling +interactions, i.e. to use *special_bonds lj/coul 1.0 1.0 1.0*. Scaling factors > 0.0 will be ignored and treated as 1.0. The only exception to this rule is if you know that your QUIP potential needs to exclude bonded, 1-3, or 1-4 interactions and does not already do this exclusion @@ -99,12 +99,12 @@ Related commands ---------- -.. _Bartok\_2010: +.. _Bartok_2010: -**(Bartok\_2010)** AP Bartok, MC Payne, R Kondor, and G Csanyi, Physical +**(Bartok_2010)** AP Bartok, MC Payne, R Kondor, and G Csanyi, Physical Review Letters 104, 136403 (2010). -.. _Bartok\_PhD: +.. _Bartok_PhD: -**(Bartok\_PhD)** A Bartok-Partay, PhD Thesis, University of Cambridge, +**(Bartok_PhD)** A Bartok-Partay, PhD Thesis, University of Cambridge, (2010). diff --git a/doc/src/pair_reaxc.rst b/doc/src/pair_reaxc.rst index acaac5fce1..e40fbe60c1 100644 --- a/doc/src/pair_reaxc.rst +++ b/doc/src/pair_reaxc.rst @@ -63,7 +63,7 @@ consideration when using the *reax/c/kk* style is the choice of either half or full neighbor lists. This setting can be changed using the Kokkos :doc:`package ` command. -The *reax/c* style differs from the (obsolete) "pair\_style reax" +The *reax/c* style differs from the (obsolete) "pair_style reax" command in the implementation details. The *reax* style was a Fortran library, linked to LAMMPS. The *reax* style has been removed from LAMMPS after the 12 December 2018 version. @@ -74,7 +74,7 @@ documented in potentials/README.reax. The default ffield.reax contains parameterizations for the following elements: C, H, O, N. The format of these files is identical to that used originally by van -Duin. We have tested the accuracy of *pair\_style reax/c* potential +Duin. We have tested the accuracy of *pair_style reax/c* potential against the original ReaxFF code for the systems mentioned above. You can use other ffield files for specific chemical systems that may be available elsewhere (but note that their accuracy may not have been @@ -108,7 +108,7 @@ below. code. If these are changed by setting control variables in the control file, the results from LAMMPS and the serial code will not agree. -Examples using *pair\_style reax/c* are provided in the examples/reax +Examples using *pair_style reax/c* are provided in the examples/reax sub-directory. Use of this pair style requires that a charge be defined for every @@ -118,7 +118,7 @@ charges. The ReaxFF parameter files provided were created using a charge equilibration (QEq) model for handling the electrostatic interactions. -Therefore, by default, LAMMPS requires that the :doc:`fix qeq/reax ` command be used with *pair\_style reax/c* +Therefore, by default, LAMMPS requires that the :doc:`fix qeq/reax ` command be used with *pair_style reax/c* when simulating a ReaxFF model, to equilibrate charge each timestep. Using the keyword *checkqeq* with the value *no* turns off the check for *fix qeq/reax*\ , @@ -193,10 +193,10 @@ headings) the following commands could be included in an input script: variable eqeq equal c_reax[14] thermo_style custom step temp epair v_eb v_ea [...] v_eqeq -Only a single pair\_coeff command is used with the *reax/c* style which +Only a single pair_coeff command is used with the *reax/c* style which specifies a ReaxFF potential file with parameters for all needed elements. These are mapped to LAMMPS atom types by specifying N -additional arguments after the filename in the pair\_coeff command, +additional arguments after the filename in the pair_coeff command, where N is the number of LAMMPS atom types: * filename @@ -219,7 +219,7 @@ types that will be used with other potentials. As an example, say your LAMMPS simulation has 4 atom types and the elements are ordered as C, H, O, N in the *ffield* file. If you want the LAMMPS atom type 1 and 2 to be C, type 3 to be N, and type 4 to be -H, you would use the following pair\_coeff command: +H, you would use the following pair_coeff command: .. code-block:: LAMMPS @@ -239,16 +239,16 @@ If the value of a control variable is not specified, then default values are used. What follows is the list of variables along with a brief description of their use and default values. -simulation\_name: Output files produced by *pair\_style reax/c* carry +simulation_name: Output files produced by *pair_style reax/c* carry this name + extensions specific to their contents. Partial energies are reported with a ".pot" extension, while the trajectory file has ".trj" extension. -tabulate\_long\_range: To improve performance, long range interactions +tabulate_long_range: To improve performance, long range interactions can optionally be tabulated (0 means no tabulation). Value of this variable denotes the size of the long range interaction table. The range from 0 to long range cutoff (defined in the *ffield* file) is -divided into *tabulate\_long\_range* points. Then at the start of +divided into *tabulate_long_range* points. Then at the start of simulation, we fill in the entries of the long range interaction table by computing the energies and forces resulting from van der Waals and Coulomb interactions between every possible atom type pairs present in @@ -257,42 +257,42 @@ interaction table to estimate the energy and forces between a pair of atoms. Linear interpolation is used for estimation. (default value = 0) -energy\_update\_freq: Denotes the frequency (in number of steps) of +energy_update_freq: Denotes the frequency (in number of steps) of writes into the partial energies file. (default value = 0) -nbrhood\_cutoff: Denotes the near neighbors cutoff (in Angstroms) +nbrhood_cutoff: Denotes the near neighbors cutoff (in Angstroms) regarding the bonded interactions. (default value = 5.0) -hbond\_cutoff: Denotes the cutoff distance (in Angstroms) for hydrogen +hbond_cutoff: Denotes the cutoff distance (in Angstroms) for hydrogen bond interactions.(default value = 7.5. A value of 0.0 turns off hydrogen bonds) -bond\_graph\_cutoff: is the threshold used in determining what is a +bond_graph_cutoff: is the threshold used in determining what is a physical bond, what is not. Bonds and angles reported in the trajectory file rely on this cutoff. (default value = 0.3) -thb\_cutoff: cutoff value for the strength of bonds to be considered in +thb_cutoff: cutoff value for the strength of bonds to be considered in three body interactions. (default value = 0.001) -thb\_cutoff\_sq: cutoff value for the strength of bond order products +thb_cutoff_sq: cutoff value for the strength of bond order products to be considered in three body interactions. (default value = 0.00001) -write\_freq: Frequency of writes into the trajectory file. (default +write_freq: Frequency of writes into the trajectory file. (default value = 0) -traj\_title: Title of the trajectory - not the name of the trajectory +traj_title: Title of the trajectory - not the name of the trajectory file. -atom\_info: 1 means print only atomic positions + charge (default = 0) +atom_info: 1 means print only atomic positions + charge (default = 0) -atom\_forces: 1 adds net forces to atom lines in the trajectory file +atom_forces: 1 adds net forces to atom lines in the trajectory file (default = 0) -atom\_velocities: 1 adds atomic velocities to atoms line (default = 0) +atom_velocities: 1 adds atomic velocities to atoms line (default = 0) -bond\_info: 1 prints bonds in the trajectory file (default = 0) +bond_info: 1 prints bonds in the trajectory file (default = 0) -angle\_info: 1 prints angles in the trajectory file (default = 0) +angle_info: 1 prints angles in the trajectory file (default = 0) ---------- @@ -302,7 +302,7 @@ This pair style does not support the :doc:`pair_modify ` mix, shift, table, and tail options. This pair style does not write its information to :doc:`binary restart files `, since it is stored in potential files. Thus, you -need to re-specify the pair\_style and pair\_coeff commands in an input +need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the @@ -356,9 +356,9 @@ safezone = 1.2, mincap = 50. ---------- -.. _Chenoweth\_20082: +.. _Chenoweth_20082: -**(Chenoweth\_2008)** Chenoweth, van Duin and Goddard, +**(Chenoweth_2008)** Chenoweth, van Duin and Goddard, Journal of Physical Chemistry A, 112, 1040-1053 (2008). .. _Aktulga: @@ -366,7 +366,7 @@ Journal of Physical Chemistry A, 112, 1040-1053 (2008). (Aktulga) Aktulga, Fogarty, Pandit, Grama, Parallel Computing, 38, 245-259 (2012). -.. _Liu\_2011: +.. _Liu_2011: **(Liu)** L. Liu, Y. Liu, S. V. Zybin, H. Sun and W. A. Goddard, Journal of Physical Chemistry A, 115, 11016-11022 (2011). diff --git a/doc/src/pair_resquared.rst b/doc/src/pair_resquared.rst index d133274fa4..34a441b608 100644 --- a/doc/src/pair_resquared.rst +++ b/doc/src/pair_resquared.rst @@ -119,7 +119,7 @@ than the :doc:`pair_style gayberne ` potential uses. The :math:`\epsilon_i` and :math:`\epsilon_j` coefficients are defined for atom types, not for pairs of atom types. Thus, in a series of -pair\_coeff commands, they only need to be specified once for each atom +pair_coeff commands, they only need to be specified once for each atom type. Specifically, if any of :math:`\epsilon_{i,a}`, :math:`\epsilon_{i,b}`, @@ -129,19 +129,19 @@ ignored. If any of :math:`\epsilon_{j,a}`, :math:`\epsilon_{j,b}`, :math:`\epsilon_{j,c}` are non-zero, the three values are assigned to atom type J. If all three :math:`\epsilon_i` values are zero, they are ignored. Thus the typical way to define the :math:`\epsilon_i` and -:math:`\epsilon_j` coefficients is to list their values in "pair\_coeff +:math:`\epsilon_j` coefficients is to list their values in "pair_coeff I J" commands when I = J, but set them to 0.0 when I != J. If you do list them when I != J, you should insure they are consistent with their -values in other pair\_coeff commands. +values in other pair_coeff commands. Note that if this potential is being used as a sub-style of -:doc:`pair_style hybrid `, and there is no "pair\_coeff I I" +:doc:`pair_style hybrid `, and there is no "pair_coeff I I" setting made for RE-squared for a particular type I (because I-I interactions are computed by another hybrid pair potential), then you still need to insure the epsilon a,b,c coefficients are assigned to -that type in a "pair\_coeff I J" command. +that type in a "pair_coeff I J" command. -For large uniform molecules it has been shown that the epsilon\_\*\_\* +For large uniform molecules it has been shown that the epsilon_\*_\* energy parameters are approximately representable in terms of local contact curvatures :ref:`(Everaers) `: @@ -154,7 +154,7 @@ contact curvatures :ref:`(Everaers) `: where a, b, and c give the particle diameters. The last coefficient is optional. If not specified, the global cutoff -specified in the pair\_style command is used. +specified in the pair_style command is used. ---------- @@ -182,7 +182,7 @@ instructions on how to use the accelerated styles effectively. For atom type pairs I,J and I != J, the epsilon and sigma coefficients and cutoff distance can be mixed, but only for sphere pairs. The -default mix value is *geometric*\ . See the "pair\_modify" command for +default mix value is *geometric*\ . See the "pair_modify" command for details. Other type pairs cannot be mixed, due to the different meanings of the energy prefactors used to calculate the interactions and the implicit dependence of the ellipsoid-sphere interaction on the @@ -203,7 +203,7 @@ This pair style does not support the :doc:`pair_modify ` tail option for adding long-range tail corrections to energy and pressure. -This pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_sdk.rst b/doc/src/pair_sdk.rst index 734759477c..2a5167030b 100644 --- a/doc/src/pair_sdk.rst +++ b/doc/src/pair_sdk.rst @@ -96,7 +96,7 @@ above, or in the data file or restart files read by the :doc:`read_data ` or :doc:`read_restart ` commands, or by mixing as described below: -* cg\_type (lj9\_6, lj12\_4, or lj12\_6) +* cg_type (lj9_6, lj12_4, or lj12_6) * epsilon (energy units) * sigma (distance units) * cutoff1 (distance units) @@ -106,7 +106,7 @@ distance for the potential, not as the energy minimum. The prefactors are chosen so that the potential minimum is at -epsilon. The latter 2 coefficients are optional. If not specified, the global -LJ and Coulombic cutoffs specified in the pair\_style command are used. +LJ and Coulombic cutoffs specified in the pair_style command are used. If only one cutoff is specified, it is used as the cutoff for both LJ and Coulombic interactions for this type pair. If both coefficients are specified, they are used as the LJ and Coulombic cutoffs for this @@ -115,7 +115,7 @@ type pair. For *lj/sdk/coul/long* and *lj/sdk/coul/msm* only the LJ cutoff can be specified since a Coulombic cutoff cannot be specified for an individual I,J type pair. All type pairs use the same global -Coulombic cutoff specified in the pair\_style command. +Coulombic cutoff specified in the pair_style command. ---------- @@ -144,7 +144,7 @@ instructions on how to use the accelerated styles effectively. For atom type pairs I,J and I != J, the epsilon and sigma coefficients and cutoff distance for all of the lj/sdk pair styles *cannot* be mixed, since different pairs may have different exponents. So all parameters -for all pairs have to be specified explicitly through the "pair\_coeff" +for all pairs have to be specified explicitly through the "pair_coeff" command. Defining then in a data file is also not supported, due to limitations of that file format. @@ -156,7 +156,7 @@ The *lj/sdk/coul/long* pair styles support the :doc:`pair_modify ` table option since they can tabulate the short-range portion of the long-range Coulombic interaction. -All of the lj/sdk pair styles write their information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do +All of the lj/sdk pair styles write their information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. The lj/sdk and lj/cut/coul/long pair styles do not support diff --git a/doc/src/pair_sdpd_taitwater_isothermal.rst b/doc/src/pair_sdpd_taitwater_isothermal.rst index aeca957071..05e7bbfac0 100644 --- a/doc/src/pair_sdpd_taitwater_isothermal.rst +++ b/doc/src/pair_sdpd_taitwater_isothermal.rst @@ -87,8 +87,8 @@ I,J pairs must be specified explicitly. This style does not support the :doc:`pair_modify ` shift, table, and tail options. -This style does not write information to :doc:`binary restart files `. Thus, you need to re-specify the pair\_style and -pair\_coeff commands in an input script that reads a restart file. +This style does not write information to :doc:`binary restart files `. Thus, you need to re-specify the pair_style and +pair_coeff commands in an input script that reads a restart file. This style can only be used via the *pair* keyword of the :doc:`run_style respa ` command. It does not support the *inner*\ , *middle*\ , *outer* keywords. @@ -112,6 +112,6 @@ The default seed is 0 (before mixing). ---------- -.. _Espanol\_Revenga: +.. _Espanol_Revenga: **(Espanol and Revenga)** Espanol, Revenga, Physical Review E, 67, 026705 (2003). diff --git a/doc/src/pair_smd_hertz.rst b/doc/src/pair_smd_hertz.rst index 53253da3d6..fd7f9c3e01 100644 --- a/doc/src/pair_smd_hertz.rst +++ b/doc/src/pair_smd_hertz.rst @@ -27,14 +27,14 @@ belonging to different physical bodies. The contact forces are calculated using a Hertz potential, which evaluates the overlap between two particles (whose spatial extents are defined via its contact radius). The effect is that a particles -cannot penetrate into each other. The parameter +cannot penetrate into each other. The parameter has units of pressure and should equal roughly one half of the Young's modulus (or bulk modulus in the case of fluids) of the material model associated with the SPH particles. -The parameter *scale\_factor* can be used to scale the particles' +The parameter *scale_factor* can be used to scale the particles' contact radii. This can be useful to control how close particles can -approach each other. Usually, *scale\_factor* =1.0. +approach each other. Usually, *scale_factor* =1.0. ---------- diff --git a/doc/src/pair_smd_triangulated_surface.rst b/doc/src/pair_smd_triangulated_surface.rst index cf271a0393..d1177b2577 100644 --- a/doc/src/pair_smd_triangulated_surface.rst +++ b/doc/src/pair_smd_triangulated_surface.rst @@ -1,6 +1,6 @@ .. index:: pair_style smd/tri_surface -pair_style smd/tri\_surface command +pair_style smd/tri_surface command =================================== Syntax @@ -21,21 +21,21 @@ Examples Description """"""""""" -The *smd/tri\_surface* style calculates contact forces between SPH +The *smd/tri_surface* style calculates contact forces between SPH particles and a rigid wall boundary defined via the -:doc:`smd/wall\_surface ` fix. +:doc:`smd/wall_surface ` fix. The contact forces are calculated using a Hertz potential, which evaluates the overlap between a particle (whose spatial extents are defined via its contact radius) and the triangle. The effect is that a particle cannot penetrate into the triangular surface. The -parameter has units of pressure and should equal +parameter has units of pressure and should equal roughly one half of the Young's modulus (or bulk modulus in the case of fluids) of the material model associated with the SPH particle -The parameter *scale\_factor* can be used to scale the particles' +The parameter *scale_factor* can be used to scale the particles' contact radii. This can be useful to control how close particles can -approach the triangulated surface. Usually, *scale\_factor* =1.0. +approach the triangulated surface. Usually, *scale_factor* =1.0. ---------- diff --git a/doc/src/pair_smd_ulsph.rst b/doc/src/pair_smd_ulsph.rst index 81bcc6364c..6210de2423 100644 --- a/doc/src/pair_smd_ulsph.rst +++ b/doc/src/pair_smd_ulsph.rst @@ -41,7 +41,7 @@ This pair style is invoked similar to the following command: Here, *i* and *j* denote the *LAMMPS* particle types for which this pair style is defined. Note that *i* and *j* can be different, i.e., *ulsph* cross interactions between different particle types are -allowed. However, *i*\ --\ *i* respectively *j*\ --\ *j* pair\_coeff lines have +allowed. However, *i*\ --\ *i* respectively *j*\ --\ *j* pair_coeff lines have to precede a cross interaction. In contrast to the usual *LAMMPS* *pair coeff* definitions, which are given solely a number of floats and integers, the *ulsph* *pair coeff* definition is organized using @@ -55,8 +55,8 @@ diagonal components of the stress tensor), and a material model to compute shear stresses (the off-diagonal components of the stress tensor). -Note that the use of \*GRADIENT\_CORRECTION can lead to severe numerical -instabilities. For a general fluid simulation, \*NO\_GRADIENT\_CORRECTION +Note that the use of \*GRADIENT_CORRECTION can lead to severe numerical +instabilities. For a general fluid simulation, \*NO_GRADIENT_CORRECTION is recommended. Please see the `SMD user guide `_ for a diff --git a/doc/src/pair_smtbq.rst b/doc/src/pair_smtbq.rst index d0d5c1e031..492820124e 100644 --- a/doc/src/pair_smtbq.rst +++ b/doc/src/pair_smtbq.rst @@ -22,8 +22,8 @@ Description """"""""""" This pair style computes a variable charge SMTB-Q (Second-Moment -tight-Binding QEq) potential as described in :ref:`SMTB-Q\_1 ` and -:ref:`SMTB-Q\_2 `. Briefly, the energy of metallic-oxygen systems +tight-Binding QEq) potential as described in :ref:`SMTB-Q_1 ` and +:ref:`SMTB-Q_2 `. Briefly, the energy of metallic-oxygen systems is given by three contributions: .. math:: @@ -45,14 +45,14 @@ smooth convergence to zero interaction. The parameters appearing in the upper expressions are set in the ffield.SMTBQ.Syst file where Syst corresponds to the selected system (e.g. field.SMTBQ.Al2O3). Examples for :math:`\mathrm{TiO_2}`, -:math:`\mathrm{Al_2O_3}` are provided. A single pair\_coeff command +:math:`\mathrm{Al_2O_3}` are provided. A single pair_coeff command is used with the SMTBQ styles which provides the path to the potential file with parameters for needed elements. These are mapped to LAMMPS atom types by specifying additional arguments after the potential -filename in the pair\_coeff command. Note that atom type 1 must always +filename in the pair_coeff command. Note that atom type 1 must always correspond to oxygen atoms. As an example, to simulate a :math:`\mathrm{TiO_2}` system, atom type 1 has to be oxygen and atom type 2 Ti. The following -pair\_coeff command should then be used: +pair_coeff command should then be used: .. code-block:: LAMMPS @@ -72,7 +72,7 @@ Interaction between oxygen, :math:`E_{OO}`, consists of two parts, an attractive and a repulsive part. The attractive part is effective only at short range (< :math:`r_2^{OO}`). The attractive contribution was optimized to study surfaces reconstruction -(e.g. :ref:`SMTB-Q\_2 ` in :math:`\mathrm{TiO_2}`) and is not necessary +(e.g. :ref:`SMTB-Q_2 ` in :math:`\mathrm{TiO_2}`) and is not necessary for oxide bulk modeling. The repulsive part is the Pauli interaction between the electron clouds of oxygen. The Pauli repulsion and the coulombic electrostatic interaction have same cut off value. In the @@ -84,7 +84,7 @@ The short-range interaction between metal-oxygen, :math:`E_{MO}` is based on the second moment approximation of the density of states with a N-body potential for the band energy term, :math:`E^i_{cov}`, and a Born-Mayer type repulsive terms -as indicated by the keyword *'second\_moment'* in the +as indicated by the keyword *'second_moment'* in the ffield.SMTBQ.Syst. The energy band term is given by: .. math:: @@ -110,7 +110,7 @@ anion. In the literature we find many ways to write the hopping integral depending on whether one takes the point of view of the anion or cation. These are equivalent vision. The correspondence between the two visions is explained in appendix A of the article in the -SrTiO3 :ref:`SMTB-Q\_3 ` (parameter :math:`\beta` shown in +SrTiO3 :ref:`SMTB-Q_3 ` (parameter :math:`\beta` shown in this article is in fact the :math:`\beta_O`). To summarize the relationship between the hopping integral :math:`\xi^O` and the others, we have in an oxide :math:`\mathrm{C_n O_m}` the following @@ -128,7 +128,7 @@ the electron clouds of oxygen by changing the slater radius of the charge density around the oxygen atoms through the parameters *rBB, rB and rS* in the ffield.SMTBQ.Syst. This change in radius is performed according to the method developed by E. Maras -:ref:`SMTB-Q\_2 `. This method needs to determine the number of +:ref:`SMTB-Q_2 `. This method needs to determine the number of nearest neighbors around the oxygen. This calculation is based on first (:math:`r_{1n}`) and second (:math:`r_{2n}`) distances neighbors. @@ -176,12 +176,12 @@ For each cations (metal): 3) Potential parameters: * Keyword for element1, element2 and interaction potential - ('second\_moment' or 'buck' or 'buckPlusAttr') between element 1 - and 2. If the potential is 'second\_moment', specify 'oxide' or + ('second_moment' or 'buck' or 'buckPlusAttr') between element 1 + and 2. If the potential is 'second_moment', specify 'oxide' or 'metal' for metal-oxygen or metal-metal interactions respectively. * Potential parameter: - - If type of potential is 'second\_moment' : A (eV), *p*, + - If type of potential is 'second_moment' : A (eV), *p*, :math:`\zeta^0` (eV) and *q*, :math:`r_{c1} (\mathrm{\mathring{A}})`, :math:`r_{c2} (\mathrm{\mathring{A}})` and :math:`r_0 (\mathrm{\mathring{A}})` - If type of potential is 'buck' : *C* (eV) and :math:`\rho (\mathrm{\mathring{A}})` @@ -237,7 +237,7 @@ For each cations (metal): 9) Verbose * If you want the code to work in verbose mode or not : 'true' or 'false' -* If you want to print or not in the file 'Energy\_component.txt' the +* If you want to print or not in the file 'Energy_component.txt' the three main contributions to the energy of the system according to the description presented above : 'true' or 'false' and :math:`N_{Energy}`. This option writes to the file every @@ -247,7 +247,7 @@ For each cations (metal): in group *g*\ , electrostatic part of energy, :math:`E_{ES}`, the interaction between oxygen, :math:`E_{OO}`, and short range metal-oxygen interaction, :math:`E_{MO}`. -* If you want to print to the file 'Electroneg\_component.txt' the +* If you want to print to the file 'Electroneg_component.txt' the electronegativity component (:math:`\frac{\partial E_{tot}}{\partial Q_i}`) or not: 'true' or 'false' and :math:`N_{Electroneg}`. This option writes to the file every :math:`N_{Electroneg}` time steps. If @@ -271,7 +271,7 @@ This pair style does not support the :doc:`pair_modify ` mix, shift, table, and tail options. This pair style does not write its information to :doc:`binary restart files `, since it is stored in potential files. Thus, you -needs to re-specify the pair\_style and pair\_coeff commands in an input +needs to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the @@ -303,19 +303,19 @@ and R. Tetot, Comput. Mater. Sci. 111 (2016) 181-189 ---------- -.. _SMTB-Q\_1: +.. _SMTB-Q_1: -**(SMTB-Q\_1)** N. Salles, O. Politano, E. Amzallag, R. Tetot, +**(SMTB-Q_1)** N. Salles, O. Politano, E. Amzallag, R. Tetot, Comput. Mater. Sci. 111 (2016) 181-189 -.. _SMTB-Q\_2: +.. _SMTB-Q_2: -**(SMTB-Q\_2)** E. Maras, N. Salles, R. Tetot, T. Ala-Nissila, +**(SMTB-Q_2)** E. Maras, N. Salles, R. Tetot, T. Ala-Nissila, H. Jonsson, J. Phys. Chem. C 2015, 119, 10391-10399 -.. _SMTB-Q\_3: +.. _SMTB-Q_3: -**(SMTB-Q\_3)** R. Tetot, N. Salles, S. Landron, E. Amzallag, Surface +**(SMTB-Q_3)** R. Tetot, N. Salles, S. Landron, E. Amzallag, Surface Science 616, 19-8722 28 (2013) .. _Wolf2: diff --git a/doc/src/pair_snap.rst b/doc/src/pair_snap.rst index 246a461070..06ed748a07 100644 --- a/doc/src/pair_snap.rst +++ b/doc/src/pair_snap.rst @@ -50,10 +50,10 @@ The bispectrum calculation is described in more detail in :doc:`compute sna/atom `. Note that unlike for other potentials, cutoffs for SNAP potentials are -not set in the pair\_style or pair\_coeff command; they are specified in +not set in the pair_style or pair_coeff command; they are specified in the SNAP potential files themselves. -Only a single pair\_coeff command is used with the *snap* style which +Only a single pair_coeff command is used with the *snap* style which specifies a SNAP coefficient file followed by a SNAP parameter file and then N additional arguments specifying the mapping of SNAP elements to LAMMPS atom types, where N is the number of @@ -65,7 +65,7 @@ LAMMPS atom types: As an example, if a LAMMPS indium phosphide simulation has 4 atoms types, with the first two being indium and the 3rd and 4th being -phophorous, the pair\_coeff command would look like this: +phophorous, the pair_coeff command would look like this: .. code-block:: LAMMPS @@ -175,13 +175,13 @@ for each element, the upper-triangular elements of alpha. For atom type pairs I,J and I != J, where types I and J correspond to two different element types, mixing is performed by LAMMPS with user-specifiable parameters as described above. You never need to -specify a pair\_coeff command with I != J arguments for this style. +specify a pair_coeff command with I != J arguments for this style. This pair style does not support the :doc:`pair_modify ` shift, table, and tail options. This pair style does not write its information to :doc:`binary restart files `, since it is stored in potential files. Thus, you -need to re-specify the pair\_style and pair\_coeff commands in an input +need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_soft.rst b/doc/src/pair_soft.rst index 460f97194e..3339009052 100644 --- a/doc/src/pair_soft.rst +++ b/doc/src/pair_soft.rst @@ -74,7 +74,7 @@ cutoff is used. The :doc:`fix adapt ` command can be used to vary A for one or more pair types over the course of a simulation, in which case -pair\_coeff settings for A must still be specified, but will be +pair_coeff settings for A must still be specified, but will be overridden. For example these commands will vary the prefactor A for all pairwise interactions from 0.0 at the beginning to 30.0 at the end of a run: @@ -115,9 +115,9 @@ instructions on how to use the accelerated styles effectively. For atom type pairs I,J and I != J, the A coefficient and cutoff distance for this pair style can be mixed. A is always mixed via a -*geometric* rule. The cutoff is mixed according to the pair\_modify +*geometric* rule. The cutoff is mixed according to the pair_modify mix value. The default mix value is *geometric*\ . See the -"pair\_modify" command for details. +"pair_modify" command for details. This pair style does not support the :doc:`pair_modify ` shift option, since the pair interaction goes to 0.0 at the cutoff. @@ -125,7 +125,7 @@ shift option, since the pair interaction goes to 0.0 at the cutoff. The :doc:`pair_modify ` table and tail options are not relevant for this pair style. -This pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_sph_heatconduction.rst b/doc/src/pair_sph_heatconduction.rst index cc265ac8c5..45d064fdf5 100644 --- a/doc/src/pair_sph_heatconduction.rst +++ b/doc/src/pair_sph_heatconduction.rst @@ -44,8 +44,8 @@ I,J pairs must be specified explicitly. This style does not support the :doc:`pair_modify ` shift, table, and tail options. -This style does not write information to :doc:`binary restart files `. Thus, you need to re-specify the pair\_style and -pair\_coeff commands in an input script that reads a restart file. +This style does not write information to :doc:`binary restart files `. Thus, you need to re-specify the pair_style and +pair_coeff commands in an input script that reads a restart file. This style can only be used via the *pair* keyword of the :doc:`run_style respa ` command. It does not support the *inner*\ , *middle*\ , *outer* keywords. @@ -59,6 +59,6 @@ if LAMMPS was built with that package. See the :doc:`Build package `, pair\_sph/rhosum +:doc:`pair_coeff `, pair_sph/rhosum **Default:** none diff --git a/doc/src/pair_sph_idealgas.rst b/doc/src/pair_sph_idealgas.rst index 5d99576aad..fe874797eb 100644 --- a/doc/src/pair_sph_idealgas.rst +++ b/doc/src/pair_sph_idealgas.rst @@ -53,8 +53,8 @@ I,J pairs must be specified explicitly. This style does not support the :doc:`pair_modify ` shift, table, and tail options. -This style does not write information to :doc:`binary restart files `. Thus, you need to re-specify the pair\_style and -pair\_coeff commands in an input script that reads a restart file. +This style does not write information to :doc:`binary restart files `. Thus, you need to re-specify the pair_style and +pair_coeff commands in an input script that reads a restart file. This style can only be used via the *pair* keyword of the :doc:`run_style respa ` command. It does not support the *inner*\ , *middle*\ , *outer* keywords. @@ -68,7 +68,7 @@ if LAMMPS was built with that package. See the :doc:`Build package `, pair\_sph/rhosum +:doc:`pair_coeff `, pair_sph/rhosum **Default:** none diff --git a/doc/src/pair_sph_lj.rst b/doc/src/pair_sph_lj.rst index defb1bb6fe..bdfe530cfb 100644 --- a/doc/src/pair_sph_lj.rst +++ b/doc/src/pair_sph_lj.rst @@ -48,8 +48,8 @@ I,J pairs must be specified explicitly. This style does not support the :doc:`pair_modify ` shift, table, and tail options. -This style does not write information to :doc:`binary restart files `. Thus, you need to re-specify the pair\_style and -pair\_coeff commands in an input script that reads a restart file. +This style does not write information to :doc:`binary restart files `. Thus, you need to re-specify the pair_style and +pair_coeff commands in an input script that reads a restart file. This style can only be used via the *pair* keyword of the :doc:`run_style respa ` command. It does not support the *inner*\ , *middle*\ , *outer* keywords. @@ -66,7 +66,7 @@ if LAMMPS was built with that package. See the :doc:`Build package `, pair\_sph/rhosum +:doc:`pair_coeff `, pair_sph/rhosum **Default:** none diff --git a/doc/src/pair_sph_rhosum.rst b/doc/src/pair_sph_rhosum.rst index ff749eac78..b3148bcd6a 100644 --- a/doc/src/pair_sph_rhosum.rst +++ b/doc/src/pair_sph_rhosum.rst @@ -45,8 +45,8 @@ I,J pairs must be specified explicitly. This style does not support the :doc:`pair_modify ` shift, table, and tail options. -This style does not write information to :doc:`binary restart files `. Thus, you need to re-specify the pair\_style and -pair\_coeff commands in an input script that reads a restart file. +This style does not write information to :doc:`binary restart files `. Thus, you need to re-specify the pair_style and +pair_coeff commands in an input script that reads a restart file. This style can only be used via the *pair* keyword of the :doc:`run_style respa ` command. It does not support the *inner*\ , *middle*\ , *outer* keywords. @@ -60,6 +60,6 @@ if LAMMPS was built with that package. See the :doc:`Build package `, pair\_sph/taitwater +:doc:`pair_coeff `, pair_sph/taitwater **Default:** none diff --git a/doc/src/pair_sph_taitwater.rst b/doc/src/pair_sph_taitwater.rst index 498faccdd1..3431a20319 100644 --- a/doc/src/pair_sph_taitwater.rst +++ b/doc/src/pair_sph_taitwater.rst @@ -57,8 +57,8 @@ I,J pairs must be specified explicitly. This style does not support the :doc:`pair_modify ` shift, table, and tail options. -This style does not write information to :doc:`binary restart files `. Thus, you need to re-specify the pair\_style and -pair\_coeff commands in an input script that reads a restart file. +This style does not write information to :doc:`binary restart files `. Thus, you need to re-specify the pair_style and +pair_coeff commands in an input script that reads a restart file. This style can only be used via the *pair* keyword of the :doc:`run_style respa ` command. It does not support the *inner*\ , *middle*\ , *outer* keywords. @@ -72,7 +72,7 @@ if LAMMPS was built with that package. See the :doc:`Build package `, pair\_sph/rhosum +:doc:`pair_coeff `, pair_sph/rhosum **Default:** none diff --git a/doc/src/pair_sph_taitwater_morris.rst b/doc/src/pair_sph_taitwater_morris.rst index b56be5fa67..9c65fd91ec 100644 --- a/doc/src/pair_sph_taitwater_morris.rst +++ b/doc/src/pair_sph_taitwater_morris.rst @@ -56,8 +56,8 @@ I,J pairs must be specified explicitly. This style does not support the :doc:`pair_modify ` shift, table, and tail options. -This style does not write information to :doc:`binary restart files `. Thus, you need to re-specify the pair\_style and -pair\_coeff commands in an input script that reads a restart file. +This style does not write information to :doc:`binary restart files `. Thus, you need to re-specify the pair_style and +pair_coeff commands in an input script that reads a restart file. This style can only be used via the *pair* keyword of the :doc:`run_style respa ` command. It does not support the *inner*\ , *middle*\ , *outer* keywords. @@ -71,7 +71,7 @@ if LAMMPS was built with that package. See the :doc:`Build package `, pair\_sph/rhosum +:doc:`pair_coeff `, pair_sph/rhosum **Default:** none diff --git a/doc/src/pair_spin_dipole.rst b/doc/src/pair_spin_dipole.rst index 1b6bade399..fae22d5e8a 100644 --- a/doc/src/pair_spin_dipole.rst +++ b/doc/src/pair_spin_dipole.rst @@ -88,7 +88,7 @@ This pair style does not support the :doc:`pair_modify ` tail option for adding long-range tail corrections to energy and pressure. -This pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. Restrictions diff --git a/doc/src/pair_spin_dmi.rst b/doc/src/pair_spin_dmi.rst index 023de43475..dc2d22b30a 100644 --- a/doc/src/pair_spin_dmi.rst +++ b/doc/src/pair_spin_dmi.rst @@ -81,7 +81,7 @@ Restrictions All the *pair/spin* styles are part of the SPIN package. These styles are only enabled if LAMMPS was built with this package, and if the -atom\_style "spin" was declared. See the :doc:`Build package ` doc page for more info. +atom_style "spin" was declared. See the :doc:`Build package ` doc page for more info. Related commands """""""""""""""" diff --git a/doc/src/pair_spin_exchange.rst b/doc/src/pair_spin_exchange.rst index cd3d9a202e..14eefaccec 100644 --- a/doc/src/pair_spin_exchange.rst +++ b/doc/src/pair_spin_exchange.rst @@ -42,7 +42,7 @@ interaction for different neighboring shells. This function is defined as: {J}\left( r_{ij} \right) = 4 a \left( \frac{r_{ij}}{d} \right)^2 \left( 1 - b \left( \frac{r_{ij}}{d} \right)^2 \right) e^{-\left( \frac{r_{ij}}{d} \right)^2 }\Theta (R_c - r_{ij}) where :math:`a`, :math:`b` and :math:`d` are the three constant coefficients defined in the associated -"pair\_coeff" command, and :math:`R_c` is the radius cutoff associated to +"pair_coeff" command, and :math:`R_c` is the radius cutoff associated to the pair interaction (see below for more explanations). The coefficients :math:`a`, :math:`b`, and :math:`d` need to be fitted so that the function above matches with @@ -93,7 +93,7 @@ Restrictions All the *pair/spin* styles are part of the SPIN package. These styles are only enabled if LAMMPS was built with this package, and if the -atom\_style "spin" was declared. See the :doc:`Build package ` doc page for more info. +atom_style "spin" was declared. See the :doc:`Build package ` doc page for more info. Related commands """""""""""""""" diff --git a/doc/src/pair_spin_magelec.rst b/doc/src/pair_spin_magelec.rst index 7caa98d96d..a220299b07 100644 --- a/doc/src/pair_spin_magelec.rst +++ b/doc/src/pair_spin_magelec.rst @@ -60,7 +60,7 @@ Restrictions All the *pair/spin* styles are part of the SPIN package. These styles are only enabled if LAMMPS was built with this package, and if the -atom\_style "spin" was declared. See the :doc:`Build package ` doc page for more info. +atom_style "spin" was declared. See the :doc:`Build package ` doc page for more info. Related commands """""""""""""""" diff --git a/doc/src/pair_spin_neel.rst b/doc/src/pair_spin_neel.rst index 49adce9ed5..4e6eba1f34 100644 --- a/doc/src/pair_spin_neel.rst +++ b/doc/src/pair_spin_neel.rst @@ -56,7 +56,7 @@ the same Bethe-Slater function used to fit the exchange interaction: {J}\left( r_{ij} \right) = 4 a \left( \frac{r_{ij}}{d} \right)^2 \left( 1 - b \left( \frac{r_{ij}}{d} \right)^2 \right) e^{-\left( \frac{r_{ij}}{d} \right)^2 }\Theta (R_c - r_{ij}) where :math:`a`, :math:`b` and :math:`d` are the three constant coefficients defined in the -associated "pair\_coeff" command. +associated "pair_coeff" command. The coefficients :math:`a`, :math:`b`, and :math:`d` need to be fitted so that the function above matches with the values of the magneto-elastic constant of the @@ -80,7 +80,7 @@ Restrictions All the *pair/spin* styles are part of the SPIN package. These styles are only enabled if LAMMPS was built with this package, and if the -atom\_style "spin" was declared. See the :doc:`Build package ` doc page for more info. +atom_style "spin" was declared. See the :doc:`Build package ` doc page for more info. Related commands """""""""""""""" diff --git a/doc/src/pair_srp.rst b/doc/src/pair_srp.rst index cb60a0285d..01517df434 100644 --- a/doc/src/pair_srp.rst +++ b/doc/src/pair_srp.rst @@ -137,7 +137,7 @@ This pair style does not support the :doc:`pair_modify ` tail option for adding long-range tail corrections to energy and pressure. -This pair style writes global and per-atom information to :doc:`binary restart files `. Pair srp should be used with :doc:`pair_style hybrid `, thus the pair\_coeff commands need to be +This pair style writes global and per-atom information to :doc:`binary restart files `. Pair srp should be used with :doc:`pair_style hybrid `, thus the pair_coeff commands need to be specified in the input script when reading a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_style.rst b/doc/src/pair_style.rst index 5533e6440b..0433dfa861 100644 --- a/doc/src/pair_style.rst +++ b/doc/src/pair_style.rst @@ -63,19 +63,19 @@ pairwise interaction between two atoms separated by a distance *r*\ . The force between the atoms is the negative derivative of this expression. -If the pair\_style command has a cutoff argument, it sets global +If the pair_style command has a cutoff argument, it sets global cutoffs for all pairs of atom types. The distance(s) can be smaller or larger than the dimensions of the simulation box. Typically, the global cutoff value can be overridden for a specific pair of atom types by the :doc:`pair_coeff ` command. The pair style settings (including global cutoffs) can be changed by a -subsequent pair\_style command using the same style. This will reset +subsequent pair_style command using the same style. This will reset the cutoffs for all atom type pairs, including those previously set explicitly by a :doc:`pair_coeff ` command. The exceptions -to this are that pair\_style *table* and *hybrid* settings cannot be -reset. A new pair\_style command for these styles will wipe out all -previously specified pair\_coeff values. +to this are that pair_style *table* and *hybrid* settings cannot be +reset. A new pair_style command for these styles will wipe out all +previously specified pair_coeff values. ---------- @@ -83,7 +83,7 @@ Here is an alphabetic list of pair styles defined in LAMMPS. They are also listed in more compact form on the :doc:`Commands pair ` doc page. Click on the style to display the formula it computes, any additional -arguments specified in the pair\_style command, and coefficients +arguments specified in the pair_style command, and coefficients specified by the associated :doc:`pair_coeff ` command. There are also additional accelerated pair styles included in the diff --git a/doc/src/pair_sw.rst b/doc/src/pair_sw.rst index 3cf425536a..f7999c720a 100644 --- a/doc/src/pair_sw.rst +++ b/doc/src/pair_sw.rst @@ -54,10 +54,10 @@ where :math:`\phi_2` is a two-body term and :math:`\phi_3` is a three-body term. The summations in the formula are over all neighbors J and K of atom I within a cutoff distance :math:`a `\sigma`. -Only a single pair\_coeff command is used with the *sw* style which +Only a single pair_coeff command is used with the *sw* style which specifies a Stillinger-Weber potential file with parameters for all needed elements. These are mapped to LAMMPS atom types by specifying -N additional arguments after the filename in the pair\_coeff command, +N additional arguments after the filename in the pair_coeff command, where N is the number of LAMMPS atom types: * filename @@ -69,7 +69,7 @@ to specify the path for the potential file. As an example, imagine a file SiC.sw has Stillinger-Weber values for Si and C. If your LAMMPS simulation has 4 atoms types and you want the 1st 3 to be Si, and the 4th to be C, you would use the following -pair\_coeff command: +pair_coeff command: .. code-block:: LAMMPS @@ -126,7 +126,7 @@ can be separately controlled. If tol = 0.0, then the standard Stillinger-Weber cutoff is used. The Stillinger-Weber potential file must contain entries for all the -elements listed in the pair\_coeff command. It can also contain +elements listed in the pair_coeff command. It can also contain entries for additional elements not being used in a particular simulation; LAMMPS ignores those entries. @@ -200,7 +200,7 @@ This pair style does not support the :doc:`pair_modify ` shift, table, and tail options. This pair style does not write its information to :doc:`binary restart files `, since it is stored in potential files. Thus, you -need to re-specify the pair\_style and pair\_coeff commands in an input +need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_table.rst b/doc/src/pair_table.rst index 6062329fbe..9d1a21f1dc 100644 --- a/doc/src/pair_table.rst +++ b/doc/src/pair_table.rst @@ -94,7 +94,7 @@ table. The format of this file is described below. If your tabulated potential(s) are designed to be used as the short-range part of one of the long-range solvers specified by the :doc:`kspace_style ` command, then you must use one or -more of the optional keywords listed above for the pair\_style command. +more of the optional keywords listed above for the pair_style command. These are *ewald* or *pppm* or *msm* or *dispersion* or *tip4p*\ . This is so LAMMPS can insure the short-range potential and long-range solver are compatible with each other, as it does for other @@ -104,7 +104,7 @@ functional form to be compatible with the matching long-range solver. ---------- -Here are some guidelines for using the pair\_style table command to +Here are some guidelines for using the pair_style table command to best effect: * Vary the number of table points; you may need to use more than you think @@ -113,7 +113,7 @@ best effect: of what the final interpolated potential looks like. This can show up interpolation "features" you may not like. * Start with the linear style; it's the style least likely to have problems. -* Use *N* in the pair\_style command equal to the "N" in the tabulation +* Use *N* in the pair_style command equal to the "N" in the tabulation file, and use the "RSQ" or "BITMAP" parameter, so additional interpolation is not needed. See discussion below. * Make sure that your tabulated forces and tabulated energies are @@ -143,7 +143,7 @@ A section begins with a non-blank line whose 1st character is not a "#"; blank lines or lines starting with "#" can be used as comments between sections. The first line begins with a keyword which identifies the section. The line can contain additional text, but the -initial text must match the argument specified in the pair\_coeff +initial text must match the argument specified in the pair_coeff command. The next line lists (in any order) one or more parameters for the table. Each parameter is a keyword followed by one or more numeric values. @@ -151,7 +151,7 @@ numeric values. The parameter "N" is required and its value is the number of table entries that follow. Note that this may be different than the *N* specified in the :doc:`pair_style table ` command. Let -Ntable = *N* in the pair\_style command, and Nfile = "N" in the +Ntable = *N* in the pair_style command, and Nfile = "N" in the tabulated file. What LAMMPS does is a preliminary interpolation by creating splines using the Nfile tabulated values as nodal points. It uses these to interpolate energy and force values at Ntable different @@ -195,8 +195,8 @@ This ordering is complex, so it is not documented here, since this file is typically produced by the :doc:`pair_write ` command with its *bitmap* option. When the table is in BITMAP format, the "N" parameter in the file must be equal to 2\^M where M is the value -specified in the pair\_style command. Also, a cutoff parameter cannot -be used as an optional 3rd argument in the pair\_coeff command; the +specified in the pair_style command. Also, a cutoff parameter cannot +be used as an optional 3rd argument in the pair_coeff command; the entire table extent as specified in the file must be used. If used, the parameter "FPRIME" is followed by 2 values *fplo* and @@ -247,11 +247,11 @@ I,J pairs must be specified explicitly. The :doc:`pair_modify ` shift, table, and tail options are not relevant for this pair style. -This pair style writes the settings for the "pair\_style table" command -to :doc:`binary restart files `, so a pair\_style command does +This pair style writes the settings for the "pair_style table" command +to :doc:`binary restart files `, so a pair_style command does not need to specified in an input script that reads a restart file. However, the coefficient information is not stored in the restart -file, since it is tabulated in the potential files. Thus, pair\_coeff +file, since it is tabulated in the potential files. Thus, pair_coeff commands do need to be specified in the restart input script. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_table_rx.rst b/doc/src/pair_table_rx.rst index 79e8a8475f..32863cbd29 100644 --- a/doc/src/pair_table_rx.rst +++ b/doc/src/pair_table_rx.rst @@ -99,7 +99,7 @@ the difference is defined to be the internal chemical energy (uChem). ---------- -Here are some guidelines for using the pair\_style table/rx command to +Here are some guidelines for using the pair_style table/rx command to best effect: * Vary the number of table points; you may need to use more than you think @@ -108,7 +108,7 @@ best effect: of what the final interpolated potential looks like. This can show up interpolation "features" you may not like. * Start with the linear style; it's the style least likely to have problems. -* Use *N* in the pair\_style command equal to the "N" in the tabulation +* Use *N* in the pair_style command equal to the "N" in the tabulation file, and use the "RSQ" or "BITMAP" parameter, so additional interpolation is not needed. See discussion below. * Make sure that your tabulated forces and tabulated energies are consistent @@ -137,7 +137,7 @@ A section begins with a non-blank line whose 1st character is not a "#"; blank lines or lines starting with "#" can be used as comments between sections. The first line begins with a keyword which identifies the section. The line can contain additional text, but the -initial text must match the argument specified in the pair\_coeff +initial text must match the argument specified in the pair_coeff command. The next line lists (in any order) one or more parameters for the table. Each parameter is a keyword followed by one or more numeric values. @@ -145,7 +145,7 @@ numeric values. The parameter "N" is required and its value is the number of table entries that follow. Note that this may be different than the *N* specified in the :doc:`pair_style table/rx ` command. Let -Ntable = *N* in the pair\_style command, and Nfile = "N" in the +Ntable = *N* in the pair_style command, and Nfile = "N" in the tabulated file. What LAMMPS does is a preliminary interpolation by creating splines using the Nfile tabulated values as nodal points. It uses these to interpolate as needed to generate energy and force @@ -179,8 +179,8 @@ This ordering is complex, so it is not documented here, since this file is typically produced by the :doc:`pair_write ` command with its *bitmap* option. When the table is in BITMAP format, the "N" parameter in the file must be equal to 2\^M where M is the value -specified in the pair\_style command. Also, a cutoff parameter cannot -be used as an optional 3rd argument in the pair\_coeff command; the +specified in the pair_style command. Also, a cutoff parameter cannot +be used as an optional 3rd argument in the pair_coeff command; the entire table extent as specified in the file must be used. If used, the parameter "FPRIME" is followed by 2 values *fplo* and @@ -211,11 +211,11 @@ I,J pairs must be specified explicitly. The :doc:`pair_modify ` shift, table, and tail options are not relevant for this pair style. -This pair style writes the settings for the "pair\_style table/rx" command -to :doc:`binary restart files `, so a pair\_style command does +This pair style writes the settings for the "pair_style table/rx" command +to :doc:`binary restart files `, so a pair_style command does not need to specified in an input script that reads a restart file. However, the coefficient information is not stored in the restart -file, since it is tabulated in the potential files. Thus, pair\_coeff +file, since it is tabulated in the potential files. Thus, pair_coeff commands do need to be specified in the restart input script. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_tersoff.rst b/doc/src/pair_tersoff.rst index a289c01ccf..7881c8ee70 100644 --- a/doc/src/pair_tersoff.rst +++ b/doc/src/pair_tersoff.rst @@ -46,7 +46,7 @@ Description """"""""""" The *tersoff* style computes a 3-body Tersoff potential -:ref:`(Tersoff\_1) ` for the energy E of a system of atoms as +:ref:`(Tersoff_1) ` for the energy E of a system of atoms as .. math:: @@ -76,10 +76,10 @@ between adjacent table entries. The table length is chosen to be accurate within 10\^-6 with respect to the *tersoff* style energy. The *tersoff/table* should give better performance in terms of speed. -Only a single pair\_coeff command is used with the *tersoff* style +Only a single pair_coeff command is used with the *tersoff* style which specifies a Tersoff potential file with parameters for all needed elements. These are mapped to LAMMPS atom types by specifying -N additional arguments after the filename in the pair\_coeff command, +N additional arguments after the filename in the pair_coeff command, where N is the number of LAMMPS atom types: * filename @@ -91,7 +91,7 @@ to specify the path for the potential file. As an example, imagine the SiC.tersoff file has Tersoff values for Si and C. If your LAMMPS simulation has 4 atoms types and you want the 1st 3 to be Si, and the 4th to be C, you would use the following -pair\_coeff command: +pair_coeff command: .. code-block:: LAMMPS @@ -139,7 +139,7 @@ parameters are used for both two-body and three-body interactions. The non-annotated parameters are unitless. The value of m must be 3 or 1. The Tersoff potential file must contain entries for all the elements -listed in the pair\_coeff command. It can also contain entries for +listed in the pair_coeff command. It can also contain entries for additional elements not being used in a particular simulation; LAMMPS ignores those entries. @@ -171,7 +171,7 @@ be set to 0.0 if desired. Note that the twobody parameters in entries such as SiCC and CSiSi are often the same, due to the common use of symmetric mixing rules, but this is not always the case. For example, the beta and n parameters in -Tersoff\_2 :ref:`(Tersoff\_2) ` are not symmetric. +Tersoff_2 :ref:`(Tersoff_2) ` are not symmetric. We chose the above form so as to enable users to define all commonly used variants of the Tersoff potential. In particular, our form @@ -179,15 +179,15 @@ reduces to the original Tersoff form when m = 3 and gamma = 1, while it reduces to the form of :ref:`Albe et al. ` when beta = 1 and m = 1. Note that in the current Tersoff implementation in LAMMPS, m must be specified as either 3 or 1. Tersoff used a slightly different but -equivalent form for alloys, which we will refer to as Tersoff\_2 -potential :ref:`(Tersoff\_2) `. +equivalent form for alloys, which we will refer to as Tersoff_2 +potential :ref:`(Tersoff_2) `. The *tersoff/table* style implements -Tersoff\_2 parameterization only. +Tersoff_2 parameterization only. -LAMMPS parameter values for Tersoff\_2 can be obtained as follows: +LAMMPS parameter values for Tersoff_2 can be obtained as follows: :math:`\gamma_{ijk} = \omega_{ik}`, :math:`\lambda_3 = 0` and the value of m has no effect. The parameters for species i and j can be calculated -using the Tersoff\_2 mixing rules: +using the Tersoff_2 mixing rules: .. math:: @@ -198,10 +198,10 @@ using the Tersoff\_2 mixing rules: R_{i,j} & = (R_{i}R_{j})^{1/2}\\ S_{i,j} & = (S_{i}S_{j})^{1/2} -Tersoff\_2 parameters R and S must be converted to the LAMMPS +Tersoff_2 parameters R and S must be converted to the LAMMPS parameters R and D (R is different in both forms), using the following relations: R=(R'+S')/2 and D=(S'-R')/2, where the primes indicate the -Tersoff\_2 parameters. +Tersoff_2 parameters. In the potentials directory, the file SiCGe.tersoff provides the LAMMPS parameters for Tersoff's various versions of Si, as well as his @@ -249,7 +249,7 @@ This pair style does not support the :doc:`pair_modify ` shift, table, and tail options. This pair style does not write its information to :doc:`binary restart files `, since it is stored in potential files. Thus, you -need to re-specify the pair\_style and pair\_coeff commands in an input +need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the @@ -282,15 +282,15 @@ Related commands ---------- -.. _Tersoff\_11: +.. _Tersoff_11: -**(Tersoff\_1)** J. Tersoff, Phys Rev B, 37, 6991 (1988). +**(Tersoff_1)** J. Tersoff, Phys Rev B, 37, 6991 (1988). .. _Albe: **(Albe)** J. Nord, K. Albe, P. Erhart, and K. Nordlund, J. Phys.: Condens. Matter, 15, 5649(2003). -.. _Tersoff\_21: +.. _Tersoff_21: -**(Tersoff\_2)** J. Tersoff, Phys Rev B, 39, 5566 (1989); errata (PRB 41, 3248) +**(Tersoff_2)** J. Tersoff, Phys Rev B, 39, 5566 (1989); errata (PRB 41, 3248) diff --git a/doc/src/pair_tersoff_mod.rst b/doc/src/pair_tersoff_mod.rst index e3f26a31b8..3d5bdbdaee 100644 --- a/doc/src/pair_tersoff_mod.rst +++ b/doc/src/pair_tersoff_mod.rst @@ -43,7 +43,7 @@ Description The *tersoff/mod* and *tersoff/mod/c* styles computes a bond-order type interatomic potential :ref:`(Kumagai) ` based on a 3-body Tersoff -potential :ref:`(Tersoff\_1) `, :ref:`(Tersoff\_2) ` with +potential :ref:`(Tersoff_1) `, :ref:`(Tersoff_2) ` with modified cutoff function and angular-dependent term, giving the energy E of a system of atoms as @@ -70,7 +70,7 @@ where :math:`f_R` is a two-body term and :math:`f_A` includes three-body interac The summations in the formula are over all neighbors J and K of atom I within a cutoff distance = R + D. The *tersoff/mod/c* style differs from *tersoff/mod* only in the -formulation of the V\_ij term, where it contains an additional c0 term. +formulation of the V_ij term, where it contains an additional c0 term. .. math:: @@ -87,18 +87,18 @@ form in which the angular-dependent term is improved. The model performs extremely well in describing the crystalline, liquid, and amorphous phases :ref:`(Schelling) `. -Only a single pair\_coeff command is used with the *tersoff/mod* style +Only a single pair_coeff command is used with the *tersoff/mod* style which specifies a Tersoff/MOD potential file with parameters for all needed elements. These are mapped to LAMMPS atom types by specifying -N additional arguments after the filename in the pair\_coeff command, +N additional arguments after the filename in the pair_coeff command, where N is the number of LAMMPS atom types: * filename * N element names = mapping of Tersoff/MOD elements to atom types -As an example, imagine the Si.tersoff\_mod file has Tersoff values for Si. +As an example, imagine the Si.tersoff_mod file has Tersoff values for Si. If your LAMMPS simulation has 3 Si atoms types, you would use the following -pair\_coeff command: +pair_coeff command: .. code-block:: LAMMPS @@ -149,7 +149,7 @@ The c0 term applies to *tersoff/mod/c* only. The non-annotated parameters are unitless. The Tersoff/MOD potential file must contain entries for all the elements -listed in the pair\_coeff command. It can also contain entries for +listed in the pair_coeff command. It can also contain entries for additional elements not being used in a particular simulation; LAMMPS ignores those entries. @@ -187,7 +187,7 @@ This pair style does not support the :doc:`pair_modify ` shift, table, and tail options. This pair style does not write its information to :doc:`binary restart files `, since it is stored in potential files. Thus, you -need to re-specify the pair\_style and pair\_coeff commands in an input +need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the @@ -225,13 +225,13 @@ Related commands **(Kumagai)** T. Kumagai, S. Izumi, S. Hara, S. Sakai, Comp. Mat. Science, 39, 457 (2007). -.. _Tersoff\_12: +.. _Tersoff_12: -**(Tersoff\_1)** J. Tersoff, Phys Rev B, 37, 6991 (1988). +**(Tersoff_1)** J. Tersoff, Phys Rev B, 37, 6991 (1988). -.. _Tersoff\_22: +.. _Tersoff_22: -**(Tersoff\_2)** J. Tersoff, Phys Rev B, 38, 9902 (1988). +**(Tersoff_2)** J. Tersoff, Phys Rev B, 38, 9902 (1988). .. _Murty: diff --git a/doc/src/pair_tersoff_zbl.rst b/doc/src/pair_tersoff_zbl.rst index 854f2630a4..fe86ef2cbb 100644 --- a/doc/src/pair_tersoff_zbl.rst +++ b/doc/src/pair_tersoff_zbl.rst @@ -31,7 +31,7 @@ Description """"""""""" The *tersoff/zbl* style computes a 3-body Tersoff potential -:ref:`(Tersoff\_1) ` with a close-separation pairwise modification +:ref:`(Tersoff_1) ` with a close-separation pairwise modification based on a Coulomb potential and the Ziegler-Biersack-Littmark universal screening function :ref:`(ZBL) `, giving the energy E of a system of atoms as @@ -85,10 +85,10 @@ includes three-body interactions. The summations in the formula are over all neighbors J and K of atom I within a cutoff distance = R + D. -Only a single pair\_coeff command is used with the *tersoff/zbl* style +Only a single pair_coeff command is used with the *tersoff/zbl* style which specifies a Tersoff/ZBL potential file with parameters for all needed elements. These are mapped to LAMMPS atom types by specifying -N additional arguments after the filename in the pair\_coeff command, +N additional arguments after the filename in the pair_coeff command, where N is the number of LAMMPS atom types: * filename @@ -100,7 +100,7 @@ to specify the path for the potential file. As an example, imagine the SiC.tersoff.zbl file has Tersoff/ZBL values for Si and C. If your LAMMPS simulation has 4 atoms types and you want the 1st 3 to be Si, and the 4th to be C, you would use the -following pair\_coeff command: +following pair_coeff command: .. code-block:: LAMMPS @@ -155,7 +155,7 @@ portion of the potential and in the Fermi-like function. The non-annotated parameters are unitless. The value of m must be 3 or 1. The Tersoff/ZBL potential file must contain entries for all the -elements listed in the pair\_coeff command. It can also contain +elements listed in the pair_coeff command. It can also contain entries for additional elements not being used in a particular simulation; LAMMPS ignores those entries. @@ -187,7 +187,7 @@ be set to 0.0 if desired. Note that the twobody parameters in entries such as SiCC and CSiSi are often the same, due to the common use of symmetric mixing rules, but this is not always the case. For example, the beta and n parameters in -Tersoff\_2 :ref:`(Tersoff\_2) ` are not symmetric. +Tersoff_2 :ref:`(Tersoff_2) ` are not symmetric. We chose the above form so as to enable users to define all commonly used variants of the Tersoff portion of the potential. In particular, @@ -196,12 +196,12 @@ our form reduces to the original Tersoff form when m = 3 and gamma = and m = 1. Note that in the current Tersoff implementation in LAMMPS, m must be specified as either 3 or 1. Tersoff used a slightly different but equivalent form for alloys, which we will refer to as -Tersoff\_2 potential :ref:`(Tersoff\_2) `. +Tersoff_2 potential :ref:`(Tersoff_2) `. -LAMMPS parameter values for Tersoff\_2 can be obtained as follows: +LAMMPS parameter values for Tersoff_2 can be obtained as follows: :math:`\gamma = \omega_{ijk}`, :math:`\lambda_3 = 0` and the value of m has no effect. The parameters for species i and j can be calculated -using the Tersoff\_2 mixing rules: +using the Tersoff_2 mixing rules: .. math:: @@ -212,10 +212,10 @@ using the Tersoff\_2 mixing rules: R_{i,j} & = (R_{i}R_{j})^{1/2}\\ S_{i,j} & = (S_{i}S_{j})^{1/2}\\ -Tersoff\_2 parameters R and S must be converted to the LAMMPS +Tersoff_2 parameters R and S must be converted to the LAMMPS parameters R and D (R is different in both forms), using the following relations: R=(R'+S')/2 and D=(S'-R')/2, where the primes indicate the -Tersoff\_2 parameters. +Tersoff_2 parameters. In the potentials directory, the file SiCGe.tersoff provides the LAMMPS parameters for Tersoff's various versions of Si, as well as his @@ -264,7 +264,7 @@ This pair style does not support the :doc:`pair_modify ` shift, table, and tail options. This pair style does not write its information to :doc:`binary restart files `, since it is stored in potential files. Thus, you -need to re-specify the pair\_style and pair\_coeff commands in an input +need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the @@ -298,9 +298,9 @@ Related commands ---------- -.. _zbl-Tersoff\_1: +.. _zbl-Tersoff_1: -**(Tersoff\_1)** J. Tersoff, Phys Rev B, 37, 6991 (1988). +**(Tersoff_1)** J. Tersoff, Phys Rev B, 37, 6991 (1988). .. _zbl-ZBL: @@ -312,6 +312,6 @@ of Ions in Matter' Vol 1, 1985, Pergamon Press. **(Albe)** J. Nord, K. Albe, P. Erhart and K. Nordlund, J. Phys.: Condens. Matter, 15, 5649(2003). -.. _zbl-Tersoff\_2: +.. _zbl-Tersoff_2: -**(Tersoff\_2)** J. Tersoff, Phys Rev B, 39, 5566 (1989); errata (PRB 41, 3248) +**(Tersoff_2)** J. Tersoff, Phys Rev B, 39, 5566 (1989); errata (PRB 41, 3248) diff --git a/doc/src/pair_thole.rst b/doc/src/pair_thole.rst index 4e0ce8844a..7adf267469 100644 --- a/doc/src/pair_thole.rst +++ b/doc/src/pair_thole.rst @@ -56,7 +56,7 @@ containing *coul/cut* or *coul/long* in its style name. The *lj/cut/thole/long* pair style is equivalent to, but more convenient that the frequent combination *hybrid/overlay lj/cut/coul/long cutoff thole damp -cutoff2*\ . It is not only a shorthand for this pair\_style combination, but +cutoff2*\ . It is not only a shorthand for this pair_style combination, but it also allows for mixing pair coefficients instead of listing them all. The *lj/cut/thole/long* pair style is also a bit faster because it avoids an overlay and can benefit from OMP acceleration. Moreover, it uses a more @@ -104,7 +104,7 @@ non-polarizable atoms are also subject to these weighting factors. The Drude particles inherit the 1-2, 1-3 and 1-4 neighbor relations from their respective cores. -For pair\_style *thole*\ , the following coefficients must be defined for +For pair_style *thole*\ , the following coefficients must be defined for each pair of atoms types via the :doc:`pair_coeff ` command as in the example above. @@ -113,7 +113,7 @@ as in the example above. * cutoff (distance units) The last two coefficients are optional. If not specified the global -Thole damping parameter or global cutoff specified in the pair\_style +Thole damping parameter or global cutoff specified in the pair_style command are used. In order to specify a cutoff (third argument) a damp parameter (second argument) must also be specified. @@ -128,7 +128,7 @@ command. * LJ cutoff (distance units) The last two coefficients are optional and default to the global values from -the *pair\_style* command line. +the *pair_style* command line. ---------- @@ -170,7 +170,7 @@ Restrictions These pair styles are part of the USER-DRUDE package. They are only enabled if LAMMPS was built with that package. See the :doc:`Build package ` doc page for more info. -This pair\_style should currently not be used with the :doc:`charmm dihedral style ` if the latter has non-zero 1-4 weighting +This pair_style should currently not be used with the :doc:`charmm dihedral style ` if the latter has non-zero 1-4 weighting factors. This is because the *thole* pair style does not know which pairs are 1-4 partners of which dihedrals. diff --git a/doc/src/pair_tri_lj.rst b/doc/src/pair_tri_lj.rst index 1546d954d5..1dd69778ed 100644 --- a/doc/src/pair_tri_lj.rst +++ b/doc/src/pair_tri_lj.rst @@ -41,16 +41,16 @@ its entirety or not at all. The set of non-overlapping spherical particles that represent a triangle, for purposes of this pair style, are generated in the -following manner. Assume the triangle is of type I, and sigma\_II has +following manner. Assume the triangle is of type I, and sigma_II has been specified. We want a set of spheres with centers in the plane of -the triangle, none of them larger in diameter than sigma\_II, which +the triangle, none of them larger in diameter than sigma_II, which completely cover the triangle's area, but with minimal overlap and a minimal total number of spheres. This is done in a recursive manner. Place a sphere at the centroid of the original triangle. Calculate what diameter it must have to just cover all 3 corner points of the -triangle. If that diameter is equal to or smaller than sigma\_II, then +triangle. If that diameter is equal to or smaller than sigma_II, then include a sphere of the calculated diameter in the set of covering -spheres. It the diameter is larger than sigma\_II, then split the +spheres. It the diameter is larger than sigma_II, then split the triangle into 2 triangles by bisecting its longest side. Repeat the process on each sub-triangle, recursing as far as needed to generate a set of covering spheres. When finished, the original criteria are @@ -62,8 +62,8 @@ The LJ interaction between 2 spheres on different triangles of types I,J is computed with an arithmetic mixing of the sigma values of the 2 spheres and using the specified epsilon value for I,J atom types. Note that because the sigma values for triangles spheres is computed -using only sigma\_II values, specific to the triangles's type, this -means that any specified sigma\_IJ values (for I != J) are effectively +using only sigma_II values, specific to the triangles's type, this +means that any specified sigma_IJ values (for I != J) are effectively ignored. For style *tri/lj*\ , the following coefficients must be defined for @@ -85,7 +85,7 @@ is used. For atom type pairs I,J and I != J, the epsilon and sigma coefficients and cutoff distance for all of this pair style can be mixed. The -default mix value is *geometric*\ . See the "pair\_modify" command for +default mix value is *geometric*\ . See the "pair_modify" command for details. This pair style does not support the :doc:`pair_modify ` diff --git a/doc/src/pair_ufm.rst b/doc/src/pair_ufm.rst index a26dd582be..2562b2fc2f 100644 --- a/doc/src/pair_ufm.rst +++ b/doc/src/pair_ufm.rst @@ -66,7 +66,7 @@ The last coefficient is optional. If not specified, the global *ufm* cutoff is used. The :doc:`fix adapt ` command can be used to vary epsilon and sigma for this pair style over the course of a simulation, in which case -pair\_coeff settings for epsilon and sigma must still be specified, but will be +pair_coeff settings for epsilon and sigma must still be specified, but will be overridden. For example these commands will vary the prefactor epsilon for all pairwise interactions from 10.0 at the beginning to 100.0 at the end of a run: @@ -112,9 +112,9 @@ instructions on how to use the accelerated styles effectively. For atom type pairs I,J and I != J, the A coefficient and cutoff distance for this pair style can be mixed. A is always mixed via a -*geometric* rule. The cutoff is mixed according to the pair\_modify +*geometric* rule. The cutoff is mixed according to the pair_modify mix value. The default mix value is *geometric*\ . See the -"pair\_modify" command for details. +"pair_modify" command for details. This pair style support the :doc:`pair_modify ` shift option for the energy of the pair interaction. @@ -123,7 +123,7 @@ pair style. This pair style does not support the :doc:`pair_modify ` tail option for adding long-range tail corrections to energy and pressure. -This pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_vashishta.rst b/doc/src/pair_vashishta.rst index ca4751d07f..044709d65d 100644 --- a/doc/src/pair_vashishta.rst +++ b/doc/src/pair_vashishta.rst @@ -87,10 +87,10 @@ with moderate to little loss of accuracy for Ntable values between 10000 and 1000000. It is not recommended to use less than 5000 tabulation points. -Only a single pair\_coeff command is used with either style which +Only a single pair_coeff command is used with either style which specifies a Vashishta potential file with parameters for all needed elements. These are mapped to LAMMPS atom types by specifying N -additional arguments after the filename in the pair\_coeff command, +additional arguments after the filename in the pair_coeff command, where N is the number of LAMMPS atom types: * filename @@ -102,7 +102,7 @@ to specify the path for the potential file. As an example, imagine a file SiC.vashishta has parameters for Si and C. If your LAMMPS simulation has 4 atoms types and you want the 1st 3 to be Si, and the 4th to be C, you would use the following -pair\_coeff command: +pair_coeff command: .. code-block:: LAMMPS @@ -143,7 +143,7 @@ and three-body coefficients in the formulae above: The non-annotated parameters are unitless. The Vashishta potential file must contain entries for all the elements listed in the -pair\_coeff command. It can also contain entries for additional +pair_coeff command. It can also contain entries for additional elements not being used in a particular simulation; LAMMPS ignores those entries. For a single-element simulation, only a single entry is required (e.g. SiSiSi). For a two-element simulation, the file @@ -223,7 +223,7 @@ This pair style does not support the :doc:`pair_modify ` shift, table, and tail options. This pair style does not write its information to :doc:`binary restart files `, since it is stored in potential files. Thus, you -need to re-specify the pair\_style and pair\_coeff commands in an input +need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_write.rst b/doc/src/pair_write.rst index e11b631853..acb6de4f13 100644 --- a/doc/src/pair_write.rst +++ b/doc/src/pair_write.rst @@ -71,7 +71,7 @@ must be set before this command can be invoked. Due to how the pairwise force is computed, an inner value > 0.0 must be specified even if the potential has a finite value at r = 0.0. -For EAM potentials, the pair\_write command only tabulates the +For EAM potentials, the pair_write command only tabulates the pairwise portion of the potential, not the embedding portion. Related commands diff --git a/doc/src/pair_yukawa.rst b/doc/src/pair_yukawa.rst index 4170b32275..fad035ed4b 100644 --- a/doc/src/pair_yukawa.rst +++ b/doc/src/pair_yukawa.rst @@ -81,7 +81,7 @@ instructions on how to use the accelerated styles effectively. For atom type pairs I,J and I != J, the A coefficient and cutoff distance for this pair style can be mixed. A is an energy value mixed like a LJ epsilon. The default mix value is *geometric*\ . See the -"pair\_modify" command for details. +"pair_modify" command for details. This pair style supports the :doc:`pair_modify ` shift option for the energy of the pair interaction. @@ -93,7 +93,7 @@ This pair style does not support the :doc:`pair_modify ` tail option for adding long-range tail corrections to energy and pressure. -This pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_yukawa_colloid.rst b/doc/src/pair_yukawa_colloid.rst index 83e834d7f4..f775f37703 100644 --- a/doc/src/pair_yukawa_colloid.rst +++ b/doc/src/pair_yukawa_colloid.rst @@ -44,7 +44,7 @@ In contrast to :doc:`pair_style yukawa `, this functional form arises from the Coulombic interaction between two colloid particles, screened due to the presence of an electrolyte, see the book by :ref:`Safran ` for a derivation in the context of DLVO -theory. :doc:`Pair\_style yukawa ` is a screened Coulombic +theory. :doc:`Pair_style yukawa ` is a screened Coulombic potential between two point-charges and uses no such approximation. This potential applies to nearby particle pairs for which the Derjagin @@ -112,7 +112,7 @@ instructions on how to use the accelerated styles effectively. For atom type pairs I,J and I != J, the A coefficient and cutoff distance for this pair style can be mixed. A is an energy value mixed like a LJ epsilon. The default mix value is *geometric*\ . See the -"pair\_modify" command for details. +"pair_modify" command for details. This pair style supports the :doc:`pair_modify ` shift option for the energy of the pair interaction. @@ -124,7 +124,7 @@ This pair style does not support the :doc:`pair_modify ` tail option for adding long-range tail corrections to energy and pressure. -This pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_zbl.rst b/doc/src/pair_zbl.rst index 59b9b52702..26960f71b3 100644 --- a/doc/src/pair_zbl.rst +++ b/doc/src/pair_zbl.rst @@ -39,7 +39,7 @@ repulsion for describing high-energy collisions between atoms. :ref:`(Ziegler) `. It includes an additional switching function that ramps the energy, force, and curvature smoothly to zero between an inner and outer cutoff. The potential -energy due to a pair of atoms at a distance r\_ij is given by: +energy due to a pair of atoms at a distance r_ij is given by: .. math:: @@ -71,7 +71,7 @@ When used with :doc:`hybrid/overlay ` and pairs are assigned to more than one sub-style, the mixing rule is not used and each pair of types interacting with the ZBL sub-style must -be included in a pair\_coeff command. +be included in a pair_coeff command. .. note:: @@ -115,7 +115,7 @@ specified for with :doc:`hybrid/overlay ` and pairs are assigned to more than one sub-style, the mixing rule is not used and each pair of types interacting with the ZBL sub-style -must be included in a pair\_coeff command. +must be included in a pair_coeff command. The :doc:`pair_modify ` mix option has no effect on the mixing behavior @@ -131,7 +131,7 @@ tail option for adding long-range tail corrections to energy and pressure, since there are no corrections for a potential that goes to 0.0 at the cutoff. -This pair style does not write information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands must be +This pair style does not write information to :doc:`binary restart files `, so pair_style and pair_coeff commands must be specified in an input script that reads a restart file. This pair style can only be used via the *pair* keyword of the diff --git a/doc/src/pair_zero.rst b/doc/src/pair_zero.rst index 86b3fa64fb..a704cf92f2 100644 --- a/doc/src/pair_zero.rst +++ b/doc/src/pair_zero.rst @@ -12,7 +12,7 @@ Syntax * zero = style name of this pair style * cutoff = global cutoff (distance units) -* nocoeff = ignore all pair\_coeff parameters (optional) +* nocoeff = ignore all pair_coeff parameters (optional) Examples """""""" @@ -41,7 +41,7 @@ used to insure communication of ghost atoms even when a pair style is not defined, but it will not trigger neighbor list generation. The optional *nocoeff* flag allows to read data files with a PairCoeff -section for any pair style. Similarly, any pair\_coeff commands +section for any pair style. Similarly, any pair_coeff commands will only be checked for the atom type numbers and the rest ignored. In this case, only the global cutoff will be used. @@ -54,7 +54,7 @@ commands, or by mixing as described below: * cutoff (distance units) This coefficient is optional. If not specified, the global cutoff -specified in the pair\_style command is used. If the pair\_style has +specified in the pair_style command is used. If the pair_style has been specified with the optional *nocoeff* flag, then a cutoff pair coefficient is ignored. @@ -63,12 +63,12 @@ pair coefficient is ignored. **Mixing, shift, table, tail correction, restart, rRESPA info**\ : The cutoff distance for this pair style can be mixed. The default mix -value is *geometric*\ . See the "pair\_modify" command for details. +value is *geometric*\ . See the "pair_modify" command for details. This pair style does not support the :doc:`pair_modify ` shift, table, and tail options. -This pair style writes its information to :doc:`binary restart files `, so pair\_style and pair\_coeff commands do not need +This pair style writes its information to :doc:`binary restart files `, so pair_style and pair_coeff commands do not need to be specified in an input script that reads a restart file. This pair style supports the use of the *inner*\ , *middle*\ , diff --git a/doc/src/partition.rst b/doc/src/partition.rst index be333ba581..be0e1152f5 100644 --- a/doc/src/partition.rst +++ b/doc/src/partition.rst @@ -59,7 +59,7 @@ from 1 to n (inclusive). A trailing asterisk means all partitions from n to Np (inclusive). A middle asterisk means all partitions from m to n (inclusive). -This command can be useful for the "run\_style verlet/split" command +This command can be useful for the "run_style verlet/split" command which imposed requirements on how the :doc:`processors ` command lays out a 3d grid of processors in each of 2 partitions. diff --git a/doc/src/prd.rst b/doc/src/prd.rst index d849c8f5a8..c3bd1ad1d3 100644 --- a/doc/src/prd.rst +++ b/doc/src/prd.rst @@ -11,12 +11,12 @@ Syntax prd N t_event n_dephase t_dephase t_correlate compute-ID seed keyword value ... * N = # of timesteps to run (not including dephasing/quenching) -* t\_event = timestep interval between event checks -* n\_dephase = number of velocity randomizations to perform in each dephase run -* t\_dephase = number of timesteps to run dynamics after each velocity randomization during dephase -* t\_correlate = number of timesteps within which 2 consecutive events are considered to be correlated +* t_event = timestep interval between event checks +* n_dephase = number of velocity randomizations to perform in each dephase run +* t_dephase = number of timesteps to run dynamics after each velocity randomization during dephase +* t_correlate = number of timesteps within which 2 consecutive events are considered to be correlated * compute-ID = ID of the compute used for event detection -* random\_seed = random # seed (positive integer) +* random_seed = random # seed (positive integer) * zero or more keyword/value pairs may be appended * keyword = *min* or *temp* or *vel* @@ -119,9 +119,9 @@ storing the resulting coordinates for reference. In the first stage, dephasing is performed by each replica independently to eliminate correlations between replicas. This is done by choosing a random set of velocities, based on the -*random\_seed* that is specified, and running *t\_dephase* timesteps of -dynamics. This is repeated *n\_dephase* times. At each of the -*n\_dephase* stages, if an event occurs during the *t\_dephase* steps of +*random_seed* that is specified, and running *t_dephase* timesteps of +dynamics. This is repeated *n_dephase* times. At each of the +*n_dephase* stages, if an event occurs during the *t_dephase* steps of dynamics for a particular replica, the replica repeats the stage until no event occurs. @@ -133,7 +133,7 @@ The style of velocity randomization is controlled using the keyword in the :doc:`velocity ` command. In the second stage, each replica runs dynamics continuously, stopping -every *t\_event* steps to check if a transition event has occurred. +every *t_event* steps to check if a transition event has occurred. This check is performed by quenching the system and comparing the resulting atom coordinates to the coordinates from the previous basin. The first time through the PRD loop, the "previous basin" is the set @@ -158,8 +158,8 @@ distance. If so, an "event" has occurred. In the third stage, the replica on which the event occurred (event replica) continues to run dynamics to search for correlated events. -This is done by running dynamics for *t\_correlate* steps, quenching -every *t\_event* steps, and checking if another event has occurred. +This is done by running dynamics for *t_correlate* steps, quenching +every *t_event* steps, and checking if another event has occurred. The first time no correlated event occurs, the final state of the event replica is shared with all replicas, the new basin reference @@ -230,11 +230,11 @@ when a correlated event occurs during the third stage of the loop listed above, i.e. when only one replica is running dynamics. When more than one replica detects an event at the end of the same -event check (every *t\_event* steps) during the second stage, then +event check (every *t_event* steps) during the second stage, then one of them is chosen at random. The number of coincident events is the number of replicas that detected an event. Normally, this value should be 1. If it is often greater than 1, then either the number of -replicas is too large, or *t\_event* is too large. +replicas is too large, or *t_event* is too large. The replica number is the ID of the replica (from 0 to M-1) in which the event occurred. @@ -277,9 +277,9 @@ continued by a new input script in the usual manner. The restart file is generated at the end of the loop listed above. If no correlated events are found, this means it contains a snapshot of -the system at time T + *t\_correlate*, where T is the time at which the +the system at time T + *t_correlate*, where T is the time at which the uncorrelated event occurred. If correlated events were found, then it -contains a snapshot of the system at time T + *t\_correlate*, where T +contains a snapshot of the system at time T + *t_correlate*, where T is the time of the last correlated event. The restart frequency specified in the :doc:`restart ` command @@ -292,7 +292,7 @@ event. When an input script reads a restart file from a previous PRD run, the new script can be run on a different number of replicas or processors. -However, it is assumed that *t\_correlate* in the new PRD command is +However, it is assumed that *t_correlate* in the new PRD command is the same as it was previously. If not, the calculation of the "clock" value for the first event in the new run will be slightly off. @@ -305,8 +305,8 @@ This command can only be used if LAMMPS was built with the REPLICA package. See the :doc:`Build package ` doc page for more info. -The *N* and *t\_correlate* settings must be integer multiples of -*t\_event*. +The *N* and *t_correlate* settings must be integer multiples of +*t_event*. Runs restarted from restart file written during a PRD run will not produce identical results due to changes in the random numbers used diff --git a/doc/src/processors.rst b/doc/src/processors.rst index 8fe13f69eb..899c87f4b0 100644 --- a/doc/src/processors.rst +++ b/doc/src/processors.rst @@ -213,9 +213,9 @@ mapped to the 3d grid of processors. It is only used by the *onelevel* and *twolevel* grid settings. The *cart* style uses the family of MPI Cartesian functions to perform -the mapping, namely MPI\_Cart\_create(), MPI\_Cart\_get(), -MPI\_Cart\_shift(), and MPI\_Cart\_rank(). It invokes the -MPI\_Cart\_create() function with its reorder flag = 0, so that MPI is +the mapping, namely MPI_Cart_create(), MPI_Cart_get(), +MPI_Cart_shift(), and MPI_Cart_rank(). It invokes the +MPI_Cart_create() function with its reorder flag = 0, so that MPI is not free to reorder the processors. The *cart/reorder* style does the same thing as the *cart* style @@ -244,7 +244,7 @@ of the 8 octants of the simulation domain will be: Note that, in principle, an MPI implementation on a particular machine should be aware of both the machine's network topology and the specific subset of processors and nodes that were assigned to your -simulation. Thus its MPI\_Cart calls can optimize the assignment of +simulation. Thus its MPI_Cart calls can optimize the assignment of MPI processes to the 3d grid to minimize communication costs. In practice, however, few if any MPI implementations actually do this. So it is likely that the *cart* and *cart/reorder* styles simply give @@ -328,7 +328,7 @@ I,J,K are the indices of the processor in the regular 3d grid, each from 1 to Nd, where Nd is the number of processors in that dimension of the grid. -The *name* is what is returned by a call to MPI\_Get\_processor\_name() +The *name* is what is returned by a call to MPI_Get_processor_name() and should represent an identifier relevant to the physical processors in your machine. Note that depending on the MPI implementation, multiple cores can have the same *name*\ . diff --git a/doc/src/python.rst b/doc/src/python.rst index 6c54fb8872..70dfbb70ba 100644 --- a/doc/src/python.rst +++ b/doc/src/python.rst @@ -139,14 +139,14 @@ itself. This enables the function to call back to LAMMPS through its library interface as explained below. This allows the Python function to query or set values internal to LAMMPS which can affect the subsequent execution of the input script. A LAMMPS variable can also -be used as an argument, specified as v\_name, where "name" is the name +be used as an argument, specified as v_name, where "name" is the name of the variable. Any style of LAMMPS variable can be used, as defined by the :doc:`variable ` command. Each time the Python function is invoked, the LAMMPS variable is evaluated and its value is passed to the Python function. The *return* keyword is only needed if the Python function returns a -value. The specified *varReturn* must be of the form v\_name, where +value. The specified *varReturn* must be of the form v_name, where "name" is the name of a python-style LAMMPS variable, defined by the :doc:`variable ` command. The Python function can return a numeric or string value, as specified by the *format* keyword. @@ -231,7 +231,7 @@ conflict with the triple-quote parsing that the LAMMPS input script performs. All the Python code you specify via one or more python commands is -loaded into the Python "main" module, i.e. \__main\__. The code can +loaded into the Python "main" module, i.e. __main__. The code can define global variables or statements that are outside of function definitions. It can contain multiple functions, only one of which matches the *func* setting in the python command. This means you can @@ -301,7 +301,7 @@ LAMMPS with that library. Third, if your Python code calls back to LAMMPS (discussed in the next section) and causes LAMMPS to perform an MPI operation requires -global communication (e.g. via MPI\_Allreduce), such as computing the +global communication (e.g. via MPI_Allreduce), such as computing the global temperature of the system, then you must insure all your Python functions (running independently on different processors) call back to LAMMPS. Otherwise the code may hang. @@ -384,15 +384,15 @@ with complex logic, much more so than can be created using the LAMMPS :doc:`jump ` and :doc:`if ` commands. Several LAMMPS library functions are called from the loop function. -Get\_natoms() returns the number of atoms in the simulation, so that it +Get_natoms() returns the number of atoms in the simulation, so that it can be used to normalize the potential energy that is returned by -extract\_compute() for the "thermo\_pe" compute that is defined by -default for LAMMPS thermodynamic output. Set\_variable() sets the +extract_compute() for the "thermo_pe" compute that is defined by +default for LAMMPS thermodynamic output. Set_variable() sets the value of a string variable defined in LAMMPS. This library function is a useful way for a Python function to return multiple values to LAMMPS, more than the single value that can be passed back via a return statement. This cutoff value in the "cut" variable is then -substituted (by LAMMPS) in the pair\_style command that is executed +substituted (by LAMMPS) in the pair_style command that is executed next. Alternatively, the "LAMMPS command option" line could be used in place of the 2 preceding lines, to have Python insert the value into the LAMMPS command string. diff --git a/doc/src/read_data.rst b/doc/src/read_data.rst index 02e47e9c0e..2714cee4c1 100644 --- a/doc/src/read_data.rst +++ b/doc/src/read_data.rst @@ -83,7 +83,7 @@ the :doc:`displace_atoms ` command. Note that atoms read from the data file are also always added to the "all" group. The :doc:`group ` command discusses atom groups, as used in LAMMPS. -The *nocoeff* keyword tells read\_data to ignore force field parameters. +The *nocoeff* keyword tells read_data to ignore force field parameters. The various Coeff sections are still read and have to have the correct number of lines, but they are not applied. This also allows to read a data file without having any pair, bond, angle, dihedral or improper @@ -95,22 +95,22 @@ The use of the *fix* keyword is discussed below. **Reading multiple data files** -The read\_data command can be used multiple times with the same or +The read_data command can be used multiple times with the same or different data files to build up a complex system from components contained in individual data files. For example one data file could contain fluid in a confined domain; a second could contain wall atoms, and the second file could be read a third time to create a wall on the other side of the fluid. The third set of atoms could be rotated to an opposing direction using the :doc:`displace_atoms ` -command, after the third read\_data command is used. +command, after the third read_data command is used. The *add*\ , *offset*\ , *shift*\ , *extra*\ , and *group* keywords are useful in this context. If a simulation box does not yet exist, the *add* keyword -cannot be used; the read\_data command is being used for the first +cannot be used; the read_data command is being used for the first time. If a simulation box does exist, due to using the -:doc:`create_box ` command, or a previous read\_data command, +:doc:`create_box ` command, or a previous read_data command, then the *add* keyword must be used. .. note:: @@ -174,12 +174,12 @@ to move a subset of atoms after they have been read from a data file. Likewise, the :doc:`delete_atoms ` command can be used to remove overlapping atoms. Note that the shift values (Sx, Sy, Sz) are also added to the simulation box information (xlo, xhi, ylo, yhi, zlo, -zhi) in the data file to shift its boundaries. E.g. xlo\_new = xlo + -Sx, xhi\_new = xhi + Sx. +zhi) in the data file to shift its boundaries. E.g. xlo_new = xlo + +Sx, xhi_new = xhi + Sx. -The *extra* keywords can only be used the first time the read\_data +The *extra* keywords can only be used the first time the read_data command is used. They are useful if you intend to add new atom, bond, -angle, etc types later with additional read\_data commands. This is +angle, etc types later with additional read_data commands. This is because the maximum number of allowed atom, bond, angle, etc types is set by LAMMPS when the system is first initialized. If you do not use the *extra* keywords, then the number of these types will be limited @@ -205,10 +205,10 @@ you would still need to specify coefficients for H/Si and O/Si interactions in your input script to have a complete pairwise interaction model. -An alternative to using the *extra* keywords with the read\_data +An alternative to using the *extra* keywords with the read_data command, is to use the :doc:`create_box ` command to initialize the simulation box and all the various type limits you need -via its *extra* keywords. Then use the read\_data command one or more +via its *extra* keywords. Then use the read_data command one or more times to populate the system with atoms, bonds, angles, etc, using the *offset* keyword if desired to alter types used in the various data files you read. @@ -379,13 +379,13 @@ data file. "shrink-wrap" boundary conditions (see the :doc:`boundary ` command), a huge (mostly empty) box may cause a parallel simulation to lose atoms when LAMMPS shrink-wraps the box around the atoms. The - read\_data command will generate an error in this case. + read_data command will generate an error in this case. The "extra bond per atom" setting (angle, dihedral, improper) is only needed if new bonds (angles, dihedrals, impropers) will be added to the system when a simulation runs, e.g. by using the :doc:`fix bond/create ` command. Using this header flag is deprecated; please use the *extra/bond/per/atom* keyword (and -correspondingly for angles, dihedrals and impropers) in the read\_data +correspondingly for angles, dihedrals and impropers) in the read_data command instead. Either will pre-allocate space in LAMMPS data structures for storing the new bonds (angles, dihedrals, impropers). @@ -405,7 +405,7 @@ pages for more discussion of 1-2,1-3,1-4 neighbors. All of the "extra" settings are only applied in the first data file read and when no simulation box has yet been created; as soon as - the simulation box is created (and read\_data implies that), these + the simulation box is created (and read_data implies that), these settings are *locked* and cannot be changed anymore. Please see the description of the *add* keyword above for reading multiple data files. If they appear in later data files, they are ignored. @@ -586,7 +586,7 @@ of analysis. +------------+---------------------------------------------------------------------------+ | dpd | atom-ID atom-type theta x y z | +------------+---------------------------------------------------------------------------+ -| edpd | atom-ID atom-type edpd\_temp edpd\_cv x y z | +| edpd | atom-ID atom-type edpd_temp edpd_cv x y z | +------------+---------------------------------------------------------------------------+ | mdpd | atom-ID atom-type rho x y z | +------------+---------------------------------------------------------------------------+ @@ -616,7 +616,7 @@ of analysis. +------------+---------------------------------------------------------------------------+ | tri | atom-ID molecule-ID atom-type triangleflag density x y z | +------------+---------------------------------------------------------------------------+ -| wavepacket | atom-ID atom-type charge spin eradius etag cs\_re cs\_im x y z | +| wavepacket | atom-ID atom-type charge spin eradius etag cs_re cs_im x y z | +------------+---------------------------------------------------------------------------+ | hybrid | atom-ID atom-type x y z sub-style1 sub-style2 ... | +------------+---------------------------------------------------------------------------+ @@ -628,13 +628,13 @@ The per-atom values have these meanings and units, listed alphabetically: * bodyflag = 1 for body particles, 0 for point particles * cc = chemical concentration for tDPD particles for each species (mole/volume units) * contact-radius = ??? (distance units) -* cs\_re,cs\_im = real/imaginary parts of wave packet coefficients +* cs_re,cs_im = real/imaginary parts of wave packet coefficients * cv = heat capacity (need units) for SPH particles * density = density of particle (mass/distance\^3 or mass/distance\^2 or mass/distance units, depending on dimensionality of particle) * diameter = diameter of spherical atom (distance units) * e = energy (need units) for SPH particles -* edpd\_temp = temperature for eDPD particles (temperature units) -* edpd\_cv = volumetric heat capacity for eDPD particles (energy/temperature/volume units) +* edpd_temp = temperature for eDPD particles (temperature units) +* edpd_cv = volumetric heat capacity for eDPD particles (energy/temperature/volume units) * ellipsoidflag = 1 for ellipsoidal particles, 0 for point particles * eradius = electron radius (or fixed-core radius) * etag = integer ID of electron that each wave packet belongs to @@ -713,12 +713,12 @@ body is unknown. Note that for 2d simulations of spheres, this command will treat them as spheres when converting density to mass. However, they can also be modeled as 2d discs (circles) if the :doc:`set density/disc ` -command is used to reset their mass after the read\_data command is +command is used to reset their mass after the read_data command is used. A *disc* keyword can also be used with time integration fixes, such as :doc:`fix nve/sphere ` and :doc:`fix nvt/sphere ` to time integrate their motion as 2d discs (not 3d spheres), by changing their moment of inertia. -For atom\_style hybrid, following the 5 initial values (ID,type,x,y,z), +For atom_style hybrid, following the 5 initial values (ID,type,x,y,z), specific values for each sub-style must be listed. The order of the sub-styles is the same as they were listed in the :doc:`atom_style ` command. The sub-style specific values @@ -739,7 +739,7 @@ were used in the input script, each atom line would have these fields: Note that if a non-standard value is defined by multiple sub-styles, it must appear multiple times in the atom line. E.g. the atom line -for atom\_style hybrid dipole full would list "q" twice: +for atom_style hybrid dipole full would list "q" twice: .. parsed-literal:: @@ -1176,7 +1176,7 @@ pair style. See the :doc:`pair_style ` and :doc:`pair_coeff ` commands for details. Since pair coefficients for types I != J are not specified, these will be generated automatically by the pair style's mixing rule. See the -individual pair\_style doc pages and the :doc:`pair_modify mix ` command for details. Pair coefficients can also +individual pair_style doc pages and the :doc:`pair_modify mix ` command for details. Pair coefficients can also be set via the :doc:`pair_coeff ` command in the input script. @@ -1206,7 +1206,7 @@ pair style. See the :doc:`pair_style ` and :doc:`pair_coeff ` commands for details. Since pair coefficients for types I != J are all specified, these values will turn off the default mixing rule defined by the pair style. See the -individual pair\_style doc pages and the :doc:`pair_modify mix ` command for details. Pair coefficients can also +individual pair_style doc pages and the :doc:`pair_modify mix ` command for details. Pair coefficients can also be set via the :doc:`pair_coeff ` command in the input script. @@ -1277,7 +1277,7 @@ Vx, vy, vz, and ervel are in :doc:`units ` of velocity. Lx, ly, lz are in units of angular momentum (distance-velocity-mass). Wx, Wy, Wz are in units of angular velocity (radians/time). -For atom\_style hybrid, following the 4 initial values (ID,vx,vy,vz), +For atom_style hybrid, following the 4 initial values (ID,vx,vy,vz), specific values for each sub-style must be listed. The order of the sub-styles is the same as they were listed in the :doc:`atom_style ` command. The sub-style specific values @@ -1306,7 +1306,7 @@ Restrictions """""""""""" To read gzipped data files, you must compile LAMMPS with the --DLAMMPS\_GZIP option. See the :doc:`Build settings ` +-DLAMMPS_GZIP option. See the :doc:`Build settings ` doc page for details. Related commands diff --git a/doc/src/read_dump.rst b/doc/src/read_dump.rst index 3023f719e3..c46c12c951 100644 --- a/doc/src/read_dump.rst +++ b/doc/src/read_dump.rst @@ -80,9 +80,9 @@ commands for alternative methods to do this. Also see the from a dump file. Note that a simulation box must already be defined before using the -read\_dump command. This can be done by the +read_dump command. This can be done by the :doc:`create_box `, :doc:`read_data `, or -:doc:`read_restart ` commands. The read\_dump command can +:doc:`read_restart ` commands. The read_dump command can reset the simulation box dimensions, as explained below. Also note that reading per-atom information from a dump snapshot is @@ -92,7 +92,7 @@ a valid simulation, such as atom charge, or bond topology information for a molecular system, are not read from (or even contained in) dump files. Thus this auxiliary information should be defined in the usual way, e.g. in a data file read in by a :doc:`read_data ` -command, before using the read\_dump command, or by the :doc:`set ` +command, before using the read_dump command, or by the :doc:`set ` command, after the dump snapshot is read. ---------- @@ -196,7 +196,7 @@ always work perfectly. Per-atom information from the dump file snapshot is then read from the dump file snapshot. This corresponds to the specified *fields* listed -in the read\_dump command. It is an error to specify a z-dimension +in the read_dump command. It is an error to specify a z-dimension field, namely *z*\ , *vz*\ , or *iz*\ , for a 2d simulation. For dump files in *native* format, each column of per-atom data has a @@ -371,7 +371,7 @@ Restrictions """""""""""" To read gzipped dump files, you must compile LAMMPS with the --DLAMMPS\_GZIP option. See the :doc:`Build settings ` +-DLAMMPS_GZIP option. See the :doc:`Build settings ` doc page for details. The *molfile* dump file formats are part of the USER-MOLFILE package. diff --git a/doc/src/read_restart.rst b/doc/src/read_restart.rst index 58f6c113fc..ef77cef1af 100644 --- a/doc/src/read_restart.rst +++ b/doc/src/read_restart.rst @@ -44,11 +44,11 @@ changed by the :doc:`balance ` or :doc:`fix balance ` comm Normally, restart files are written by the :doc:`restart ` or :doc:`write_restart ` commands so that all atoms in the restart file are inside the simulation box. - If this is not the case, the read\_restart command will print an error + If this is not the case, the read_restart command will print an error that atoms were "lost" when the file is read. This error should be reported to the LAMMPS developers so the invalid writing of the restart file can be fixed. If you still wish to use the restart file, - the optional *remap* flag can be appended to the read\_restart command. + the optional *remap* flag can be appended to the read_restart command. This should avoid the error, by explicitly remapping each atom back into the simulation box, updating image flags for the atom appropriately. @@ -97,11 +97,11 @@ the run command so it doesn't need to be changed either. If a "%" character appears in the restart filename, LAMMPS expects a set of multiple files to exist. The :doc:`restart ` and :doc:`write_restart ` commands explain how such sets are -created. Read\_restart will first read a filename where "%" is +created. Read_restart will first read a filename where "%" is replaced by "base". This file tells LAMMPS how many processors -created the set and how many files are in it. Read\_restart then reads +created the set and how many files are in it. Read_restart then reads the additional files. For example, if the restart file was specified -as save.% when it was written, then read\_restart reads the files +as save.% when it was written, then read_restart reads the files save.base, save.0, save.1, ... save.P-1, where P is the number of processors that created the restart file. @@ -169,7 +169,7 @@ reading the restart file. The :doc:`newton ` command has two settings, one for pairwise interactions, the other for bonded. Both settings are stored in the restart file. For the bond setting, the value in the file will -overwrite the current value (at the time the read\_restart command is +overwrite the current value (at the time the read_restart command is issued) and warn if the two values are not the same and the current value is not the default. For the pair setting, the value in the file will not overwrite the current value (so that you can override the @@ -224,7 +224,7 @@ its calculations in a consistent manner. There are a handful of commands which can be used before or between runs which may require a system initialization. Examples - include the "balance", "displace\_atoms", "delete\_atoms", "set" (some + include the "balance", "displace_atoms", "delete_atoms", "set" (some options), and "velocity" (some options) commands. This is because they can migrate atoms to new processors. Thus they will also discard unused "state" information from fixes. You will know the discard has diff --git a/doc/src/region.rst b/doc/src/region.rst index f080992311..9f2d996b20 100644 --- a/doc/src/region.rst +++ b/doc/src/region.rst @@ -186,7 +186,7 @@ geometrically equivalent. The *radius* value for style *sphere* and *cylinder* can be specified as an equal-style :doc:`variable `. If the value is a -variable, it should be specified as v\_name, where name is the variable +variable, it should be specified as v_name, where name is the variable name. In this case, the variable will be evaluated each timestep, and its value used to determine the radius of the region. For style *sphere* also the x-, y-, and z- coordinate of the center of the sphere and for @@ -273,7 +273,7 @@ point), though this is not a requirement. The *move* keyword allows one or more :doc:`equal-style variables ` to be used to specify the x,y,z displacement of the region, typically as a function of time. A variable is -specified as v\_name, where name is the variable name. Any of the +specified as v_name, where name is the variable name. Any of the three variables can be specified as NULL, in which case no displacement is calculated in that dimension. @@ -308,7 +308,7 @@ the y direction: The *rotate* keyword rotates the region around a rotation axis *R* = (Rx,Ry,Rz) that goes through a point *P* = (Px,Py,Pz). The rotation angle is calculated, presumably as a function of time, by a variable -specified as v\_theta, where theta is the variable name. The variable +specified as v_theta, where theta is the variable name. The variable should generate its result in radians. The direction of rotation for the region around the rotation axis is consistent with the right-hand rule: if your right-hand thumb points along *R*\ , then your fingers diff --git a/doc/src/rerun.rst b/doc/src/rerun.rst index c92947ac6d..8463fd774b 100644 --- a/doc/src/rerun.rst +++ b/doc/src/rerun.rst @@ -206,7 +206,7 @@ Restrictions """""""""""" To read gzipped dump files, you must compile LAMMPS with the --DLAMMPS\_GZIP option. See the :doc:`Build settings ` +-DLAMMPS_GZIP option. See the :doc:`Build settings ` doc page for details. Related commands diff --git a/doc/src/reset_ids.rst b/doc/src/reset_ids.rst index 42b4047c79..13a374fc29 100644 --- a/doc/src/reset_ids.rst +++ b/doc/src/reset_ids.rst @@ -25,8 +25,8 @@ for bond, angle, dihedral, improper topology data. This will create a set of IDs that are numbered contiguously from 1 to N for a N atoms system. -This can be useful to do after performing a "delete\_atoms" command for -a molecular system. The delete\_atoms compress yes option will not +This can be useful to do after performing a "delete_atoms" command for +a molecular system. The delete_atoms compress yes option will not perform this operation due to the existence of bond topology. It can also be useful to do after any simulation which has lost atoms, e.g. due to atoms moving outside a simulation box with fixed @@ -47,8 +47,8 @@ as the :doc:`create_atoms ` command explains. communication was not sufficient to find atoms in bonds, angles, etc that are owned by other processors. The :doc:`comm_modify cutoff ` command can be used to correct this issue. Or you can define a pair style before using this command. If you do - the former, you should unset the comm\_modify cutoff after using - reset\_ids so that subsequent communication is not inefficient. + the former, you should unset the comm_modify cutoff after using + reset_ids so that subsequent communication is not inefficient. Restrictions """""""""""" diff --git a/doc/src/restart.rst b/doc/src/restart.rst index fbbcdd27b4..fd4c1e9e24 100644 --- a/doc/src/restart.rst +++ b/doc/src/restart.rst @@ -103,7 +103,7 @@ timestep of a run unless it is a multiple of N. A restart file is written on the last timestep of a minimization if N > 0 and the minimization converges. -Instead of a numeric value, N can be specified as an :doc:`equal-style variable `, which should be specified as v\_name, where +Instead of a numeric value, N can be specified as an :doc:`equal-style variable `, which should be specified as v_name, where name is the variable name. In this case, the variable is evaluated at the beginning of a run to determine the next timestep at which a restart file will be written out. On that timestep, the variable will diff --git a/doc/src/run_style.rst b/doc/src/run_style.rst index 5d72f00eaf..474eab2b85 100644 --- a/doc/src/run_style.rst +++ b/doc/src/run_style.rst @@ -83,7 +83,7 @@ partition. This include the :doc:`pair style `, :doc:`bond style ` portion of the calculation is performed on the 2nd partition. -This is most useful for the PPPM kspace\_style when its performance on +This is most useful for the PPPM kspace_style when its performance on a large number of processors degrades due to the cost of communication in its 3d FFTs. In this scenario, splitting your P total processors into 2 subsets of processors, P1 in the 1st partition and P2 in the @@ -196,7 +196,7 @@ levels. This can be useful, for example, to set different timesteps for hybrid coarse-grained/all-atom models. The *hybrid* keyword requires as many level assignments as there are hybrid sub-styles, which assigns each sub-style to a rRESPA level, following their order -of definition in the pair\_style command. Since the *hybrid* keyword +of definition in the pair_style command. Since the *hybrid* keyword operates on pair style computations, it is mutually exclusive with either the *pair* or the *inner*\ /\ *middle*\ /\ *outer* keywords. @@ -326,7 +326,7 @@ Default run_style verlet -For run\_style respa, the default assignment of interactions +For run_style respa, the default assignment of interactions to rRESPA levels is as follows: * bond forces = level 1 (innermost loop) diff --git a/doc/src/server_mc.rst b/doc/src/server_mc.rst index bf02da8e95..e4846a7a33 100644 --- a/doc/src/server_mc.rst +++ b/doc/src/server_mc.rst @@ -41,7 +41,7 @@ processed. The :doc:`server ` doc page gives other options for using LAMMPS See an example of how this command is used in -examples/COUPLE/lammps\_mc/in.server. +examples/COUPLE/lammps_mc/in.server. ---------- @@ -61,8 +61,8 @@ the two codes. See the `CSlib website `_ doc pages for more details on the actual library syntax. The "cs" object in this pseudo code is a pointer to an instance of the CSlib. -See the src/MESSAGE/server\_mc.cpp file for details on how LAMMPS uses -these messages. See the examples/COUPLE/lammps\_mc/mc.cpp file for an +See the src/MESSAGE/server_mc.cpp file for details on how LAMMPS uses +these messages. See the examples/COUPLE/lammps_mc/mc.cpp file for an example of how an MC driver code can use these messages. Define NATOMS=1, EINIT=2, DISPLACE=3, ACCEPT=4, RUN=5. diff --git a/doc/src/server_md.rst b/doc/src/server_md.rst index 11b0db6554..8304c808b2 100644 --- a/doc/src/server_md.rst +++ b/doc/src/server_md.rst @@ -64,10 +64,10 @@ the two codes. See the `CSlib website `_ doc pages for more details on the actual library syntax. The "cs" object in this pseudo code is a pointer to an instance of the CSlib. -See the src/MESSAGE/server\_md.cpp and src/MESSAGE/fix\_client\_md.cpp +See the src/MESSAGE/server_md.cpp and src/MESSAGE/fix_client_md.cpp files for details on how LAMMPS uses these messages. See the -examples/COUPLE/lammps\_vasp/vasp\_wrap.py or -examples/COUPLE/lammps\_nwchem/nwchem\_wrap.py files for examples of how +examples/COUPLE/lammps_vasp/vasp_wrap.py or +examples/COUPLE/lammps_nwchem/nwchem_wrap.py files for examples of how a quantum code (VASP or NWChem) can use these messages. The following pseudo-code uses these values, defined as enums. diff --git a/doc/src/set.rst b/doc/src/set.rst index 6d81eb1936..84792d1a58 100644 --- a/doc/src/set.rst +++ b/doc/src/set.rst @@ -13,7 +13,7 @@ Syntax * style = *atom* or *type* or *mol* or *group* or *region* * ID = atom ID range or type range or mol ID range or group ID or region ID * one or more keyword/value pairs may be appended -* keyword = *type* or *type/fraction* or *type/ratio* or *type/subset* or *mol* or *x* or *y* or *z* or *charge* or *dipole* or *dipole/random* or *quat* or *spin* or *spin/random* or *quat* or *quat/random* or *diameter* or *shape* or *length* or *tri* or *theta* or *theta/random* or *angmom* or *omega* or *mass* or *density* or *density/disc* or *volume* or *image* or *bond* or *angle* or *dihedral* or *improper* or *meso/e* or *meso/cv* or *meso/rho* or *smd/contact/radius* or *smd/mass/density* or *dpd/theta* or *edpd/temp* or *edpd/cv* or *cc* or *i\_name* or *d\_name* +* keyword = *type* or *type/fraction* or *type/ratio* or *type/subset* or *mol* or *x* or *y* or *z* or *charge* or *dipole* or *dipole/random* or *quat* or *spin* or *spin/random* or *quat* or *quat/random* or *diameter* or *shape* or *length* or *tri* or *theta* or *theta/random* or *angmom* or *omega* or *mass* or *density* or *density/disc* or *volume* or *image* or *bond* or *angle* or *dihedral* or *improper* or *meso/e* or *meso/cv* or *meso/rho* or *smd/contact/radius* or *smd/mass/density* or *dpd/theta* or *edpd/temp* or *edpd/cv* or *cc* or *i_name* or *d_name* .. parsed-literal:: @@ -186,7 +186,7 @@ change, for the selected atoms. Note that except where explicitly prohibited below, all of the keywords allow an :doc:`atom-style or atomfile-style variable ` to be used as the specified value(s). If the value is a -variable, it should be specified as v\_name, where name is the +variable, it should be specified as v_name, where name is the variable name. In this case, the variable will be evaluated, and its resulting per-atom value used to determine the value assigned to each selected atom. Note that the per-atom value from the variable will be @@ -463,14 +463,14 @@ Keyword *cc* sets the chemical concentration of a tDPD particle for a specified species as defined by the USER-MESODPD package. Currently, only :doc:`atom_style tdpd ` defines particles with this attribute. An integer for "index" selects a chemical species (1 to -Nspecies) where Nspecies is set by the atom\_style command. The value +Nspecies) where Nspecies is set by the atom_style command. The value for the chemical concentration must be >= 0.0. -Keywords *i\_name* and *d\_name* refer to custom integer and +Keywords *i_name* and *d_name* refer to custom integer and floating-point properties that have been added to each atom via the :doc:`fix property/atom ` command. When that command is used specific names are given to each attribute which are what is -specified as the "name" portion of *i\_name* or *d\_name*. +specified as the "name" portion of *i_name* or *d_name*. Restrictions """""""""""" diff --git a/doc/src/shell.rst b/doc/src/shell.rst index 08c6a8b635..a7646a74d2 100644 --- a/doc/src/shell.rst +++ b/doc/src/shell.rst @@ -101,7 +101,7 @@ would be the same as invoking % my_setup file1 10 file2 -from a command-line prompt. The executable program "my\_setup" is run +from a command-line prompt. The executable program "my_setup" is run with 3 arguments: file1 10 file2. Restrictions diff --git a/doc/src/special_bonds.rst b/doc/src/special_bonds.rst index da5a6279f1..d00467b3e8 100644 --- a/doc/src/special_bonds.rst +++ b/doc/src/special_bonds.rst @@ -65,7 +65,7 @@ atoms should be excluded (or reduced by a weighting factor). sense to define permanent bonds between atoms that interact via these potentials, though such bonds may exist elsewhere in your system, e.g. when using the :doc:`pair_style hybrid ` command. - Thus LAMMPS ignores special\_bonds settings when many-body potentials + Thus LAMMPS ignores special_bonds settings when many-body potentials are calculated. Please note, that the existence of explicit bonds for atoms that are described by a many-body potential will alter the neighbor list and thus can render the computation of those interactions @@ -234,7 +234,7 @@ while only in the second case, you get the desired settings of: This happens because the LJ (and Coul) settings are reset to their default values before modifying them, each time the -*special\_bonds* command is issued. +*special_bonds* command is issued. Restrictions """""""""""" diff --git a/doc/src/suffix.rst b/doc/src/suffix.rst index 68cbf5d25a..ba94214a9b 100644 --- a/doc/src/suffix.rst +++ b/doc/src/suffix.rst @@ -42,7 +42,7 @@ package. These are the variants these packages provide: -* GPU = a handful of pair styles and the PPPM kspace\_style, optimized to +* GPU = a handful of pair styles and the PPPM kspace_style, optimized to run on one or more GPUs or multicore CPU/GPU nodes * USER-INTEL = a collection of pair styles and neighbor routines optimized to run in single, mixed, or double precision on CPUs and @@ -59,7 +59,7 @@ These are the variants these packages provide: As an example, all of the packages provide a :doc:`pair_style lj/cut ` variant, with style names lj/cut/opt, lj/cut/omp, lj/cut/gpu, lj/cut/intel, or lj/cut/kk. A variant styles -can be specified explicitly in your input script, e.g. pair\_style +can be specified explicitly in your input script, e.g. pair_style lj/cut/gpu. If the suffix command is used with the appropriate style, you do not need to modify your input script. The specified suffix (opt,omp,gpu,intel,kk) is automatically appended whenever your @@ -92,9 +92,9 @@ commands in your input script. The default :doc:`run_style ` verlet is invoked prior to reading the input script and is therefore not affected by a suffix command - in the input script. The KOKKOS package requires "run\_style verlet/kk", + in the input script. The KOKKOS package requires "run_style verlet/kk", so when using the KOKKOS package it is necessary to either use the command - line "-sf kk" command or add an explicit "run\_style verlet" command to the + line "-sf kk" command or add an explicit "run_style verlet" command to the input script. Restrictions diff --git a/doc/src/tad.rst b/doc/src/tad.rst index b8de42a7eb..7f4845dc3c 100644 --- a/doc/src/tad.rst +++ b/doc/src/tad.rst @@ -11,14 +11,14 @@ Syntax tad N t_event T_lo T_hi delta tmax compute-ID keyword value ... * N = # of timesteps to run (not including dephasing/quenching) -* t\_event = timestep interval between event checks -* T\_lo = temperature at which event times are desired -* T\_hi = temperature at which MD simulation is performed +* t_event = timestep interval between event checks +* T_lo = temperature at which event times are desired +* T_hi = temperature at which MD simulation is performed * delta = desired confidence level for stopping criterion * tmax = reciprocal of lowest expected pre-exponential factor (time units) * compute-ID = ID of the compute used for event detection * zero or more keyword/value pairs may be appended -* keyword = *min* or *neb* or *min\_style* or *neb\_style* or *neb\_log* +* keyword = *min* or *neb* or *min_style* or *neb_style* or *neb_log* .. parsed-literal:: @@ -119,7 +119,7 @@ initial state and storing the resulting coordinates for reference. Inside the inner loop, dynamics is run continuously according to whatever integrator has been specified by the user, stopping every -*t\_event* steps to check if a transition event has occurred. This +*t_event* steps to check if a transition event has occurred. This check is performed by quenching the system and comparing the resulting atom coordinates to the coordinates from the previous basin. @@ -140,13 +140,13 @@ distance. If so, an "event" has occurred. The NEB calculation is similar to that invoked by the :doc:`neb ` command, except that the final state is generated internally, instead of being read in from a file. The style of minimization performed by -NEB is determined by the *neb\_style* keyword and must be a damped +NEB is determined by the *neb_style* keyword and must be a damped dynamics minimizer. The tolerances and limits for each NEB calculation can be set by the *neb* keyword. As discussed on the :doc:`neb `, it is often advantageous to use a larger timestep for NEB than for normal dynamics. Since the size of the timestep set by the :doc:`timestep ` command is used by TAD for performing -dynamics, there is a *neb\_step* keyword which can be used to set a +dynamics, there is a *neb_step* keyword which can be used to set a larger timestep for each NEB calculation if desired. ---------- @@ -164,11 +164,11 @@ are not well characterized (the most common case), it will be necessary to experiment with the values of *delta* and *tmax* to get a good trade-off between accuracy and performance. -A second key aspect is the choice of *t\_hi*. A larger value greatly +A second key aspect is the choice of *t_hi*. A larger value greatly increases the rate at which new events are generated. However, too large a value introduces errors due to anharmonicity (not accounted for within hTST). Once again, for any given system, experimentation is -necessary to determine the best value of *t\_hi*. +necessary to determine the best value of *t_hi*. ---------- @@ -179,7 +179,7 @@ files, and restart files. Event statistics are printed to the screen and master log.lammps file each time an event is executed. The quantities are the timestep, CPU time, global event number *N*\ , local event number *M*\ , event status, -energy barrier, time margin, *t\_lo* and *delt\_lo*. The timestep is +energy barrier, time margin, *t_lo* and *delt_lo*. The timestep is the usual LAMMPS timestep, which corresponds to the high-temperature time at which the event was detected, in units of timestep. The CPU time is the total processor time since the start of the TAD run. The @@ -194,9 +194,9 @@ The time margin is the ratio of the high temperature time in the current basin to the stopping time. This last number can be used to judge whether the stopping time is too short or too long (see above). -*t\_lo* is the low-temperature event time when the current basin was -entered, in units of timestep. del*t\_lo* is the time of each detected -event, measured relative to *t\_lo*. *delt\_lo* is equal to the +*t_lo* is the low-temperature event time when the current basin was +entered, in units of timestep. del*t_lo* is the time of each detected +event, measured relative to *t_lo*. *delt_lo* is equal to the high-temperature time since entering the current basin, scaled by an exponential factor that depends on the hi/lo temperature ratio and the energy barrier for that event. @@ -205,11 +205,11 @@ On lines for executed events, with status *E*\ , the global event number is incremented by one, the local event number and time margin are reset to zero, while the global event number, energy barrier, and -*delt\_lo* match the last event with status *DF* +*delt_lo* match the last event with status *DF* in the immediately preceding block of detected events. -The low-temperature event time *t\_lo* is incremented by *delt\_lo*. +The low-temperature event time *t_lo* is incremented by *delt_lo*. -NEB statistics are written to the file specified by the *neb\_log* +NEB statistics are written to the file specified by the *neb_log* keyword. If the keyword value is "none", then no NEB statistics are printed out. The statistics are written every *Nevery* timesteps. See the :doc:`neb ` command for a full description of the NEB @@ -276,7 +276,7 @@ This command can only be used if LAMMPS was built with the REPLICA package. See the :doc:`Build package ` doc page for more info. -*N* setting must be integer multiple of *t\_event*. +*N* setting must be integer multiple of *t_event*. Runs restarted from restart files written during a TAD run will only produce identical results if the user-specified integrator supports @@ -301,8 +301,8 @@ Default """"""" The option defaults are *min* = 0.1 0.1 40 50, *neb* = 0.01 100 100 -10, *neb\_style* = *quickmin*\ , *neb\_step* = the same timestep set by -the :doc:`timestep ` command, and *neb\_log* = "none". +10, *neb_style* = *quickmin*\ , *neb_step* = the same timestep set by +the :doc:`timestep ` command, and *neb_log* = "none". ---------- diff --git a/doc/src/temper.rst b/doc/src/temper.rst index 3ac6481ff1..bb470f0cc0 100644 --- a/doc/src/temper.rst +++ b/doc/src/temper.rst @@ -119,7 +119,7 @@ manner: snapshots at 310K, etc. Note that these new dump files will not contain "continuous trajectories" for individual atoms, because two successive snapshots (in time) may be from different replicas. The - reorder\_remd\_traj python script can do the reordering for you + reorder_remd_traj python script can do the reordering for you (and additionally also calculated configurational log-weights of trajectory snapshots in the canonical ensemble). The script can be found in the tools/replica directory while instructions on how to use it is diff --git a/doc/src/thermo.rst b/doc/src/thermo.rst index 3ab789457e..154fd59431 100644 --- a/doc/src/thermo.rst +++ b/doc/src/thermo.rst @@ -32,7 +32,7 @@ The content and format of what is printed is controlled by the :doc:`thermo_style ` and :doc:`thermo_modify ` commands. -Instead of a numeric value, N can be specified as an :doc:`equal-style variable `, which should be specified as v\_name, where +Instead of a numeric value, N can be specified as an :doc:`equal-style variable `, which should be specified as v_name, where name is the variable name. In this case, the variable is evaluated at the beginning of a run to determine the next timestep at which thermodynamic info will be written out. On that timestep, the diff --git a/doc/src/thermo_modify.rst b/doc/src/thermo_modify.rst index b2d4b877fe..3cec230189 100644 --- a/doc/src/thermo_modify.rst +++ b/doc/src/thermo_modify.rst @@ -47,9 +47,9 @@ by LAMMPS. These options apply to the currently defined thermo style. When you specify a :doc:`thermo_style ` command, all thermodynamic settings are restored to their default values, including - those previously reset by a thermo\_modify command. Thus if your input - script specifies a thermo\_style command, you should use the - thermo\_modify command after it. + those previously reset by a thermo_modify command. Thus if your input + script specifies a thermo_style command, you should use the + thermo_modify command after it. The *lost* keyword determines whether LAMMPS checks for lost atoms each time it computes thermodynamics and what it does if atoms are @@ -104,7 +104,7 @@ The *line* keyword determines whether thermodynamics will be output as a series of numeric values on one line or in a multi-line format with 3 quantities with text strings per line and a dashed-line header containing the timestep and CPU time. This modify option overrides -the *one* and *multi* thermo\_style settings. +the *one* and *multi* thermo_style settings. The *format* keyword can be used to change the default numeric format of any of quantities the :doc:`thermo_style ` command @@ -144,7 +144,7 @@ The specified compute ID must have been previously defined by the user via the :doc:`compute ` command and it must be a style of compute that calculates a temperature. As described in the :doc:`thermo_style ` command, thermo output uses a default -compute for temperature with ID = *thermo\_temp*. This option allows +compute for temperature with ID = *thermo_temp*. This option allows the user to override the default. The *press* keyword is used to determine how thermodynamic pressure is @@ -154,13 +154,13 @@ must have been previously defined by the user via the :doc:`compute ` command and it must be a style of compute that calculates a pressure. As described in the :doc:`thermo_style ` command, thermo output uses a default -compute for pressure with ID = *thermo\_press*. This option allows the +compute for pressure with ID = *thermo_press*. This option allows the user to override the default. .. note:: If both the *temp* and *press* keywords are used in a single - thermo\_modify command (or in two separate commands), then the order in + thermo_modify command (or in two separate commands), then the order in which the keywords are specified is important. Note that a :doc:`pressure compute ` defines its own temperature compute as an argument when it is specified. The *temp* keyword will override this (for the pressure compute being used by thermodynamics), but only @@ -183,7 +183,7 @@ Default The option defaults are lost = error, norm = yes for unit style of *lj*\ , norm = no for unit style of *real* and *metal*\ , flush = no, -and temp/press = compute IDs defined by thermo\_style. +and temp/press = compute IDs defined by thermo_style. The defaults for the line and format options depend on the thermo style. For styles "one" and "custom", the line and format defaults diff --git a/doc/src/thermo_style.rst b/doc/src/thermo_style.rst index a51d9aaf5e..dbb634a2b0 100644 --- a/doc/src/thermo_style.rst +++ b/doc/src/thermo_style.rst @@ -100,17 +100,17 @@ Set the style and content for printing thermodynamic data to the screen and log file. Style *one* prints a one-line summary of thermodynamic info that is -the equivalent of "thermo\_style custom step temp epair emol etotal +the equivalent of "thermo_style custom step temp epair emol etotal press". The line contains only numeric values. Style *multi* prints a multiple-line listing of thermodynamic info -that is the equivalent of "thermo\_style custom etotal ke temp pe ebond +that is the equivalent of "thermo_style custom etotal ke temp pe ebond eangle edihed eimp evdwl ecoul elong press". The listing contains numeric values and a string ID for each quantity. Style *custom* is the most general setting and allows you to specify which of the keywords listed above you want printed on each -thermodynamic timestep. Note that the keywords c\_ID, f\_ID, v\_name are +thermodynamic timestep. Note that the keywords c_ID, f_ID, v_name are references to :doc:`computes `, :doc:`fixes `, and equal-style :doc:`variables ` that have been defined elsewhere in the input script or can even be new styles which users have added @@ -124,7 +124,7 @@ outputs if the simulation box volume changes during the simulation. The values printed by the various keywords are instantaneous values, calculated on the current timestep. Time-averaged quantities, which include values from previous timesteps, can be output by using the -f\_ID keyword and accessing a fix that does time-averaging such as the +f_ID keyword and accessing a fix that does time-averaging such as the :doc:`fix ave/time ` command. Options invoked by the :doc:`thermo_modify ` command can @@ -135,11 +135,11 @@ atoms in the system), and the numeric precision of each printed value. .. note:: - When you use a "thermo\_style" command, all thermodynamic + When you use a "thermo_style" command, all thermodynamic settings are restored to their default values, including those previously set by a :doc:`thermo_modify ` command. Thus - if your input script specifies a thermo\_style command, you should use - the thermo\_modify command after it. + if your input script specifies a thermo_style command, you should use + the thermo_modify command after it. ---------- @@ -153,7 +153,7 @@ when LAMMPS starts up, as if this command had been issued: compute thermo_temp all temp See the :doc:`compute temp ` command for details. Note -that the ID of this compute is *thermo\_temp* and the group is *all*\ . +that the ID of this compute is *thermo_temp* and the group is *all*\ . You can change the attributes of this temperature (e.g. its degrees-of-freedom) via the :doc:`compute_modify ` command. Alternatively, you can directly assign a new compute (that @@ -171,7 +171,7 @@ if this command had been issued: compute thermo_press all pressure thermo_temp See the :doc:`compute pressure ` command for details. -Note that the ID of this compute is *thermo\_press* and the group is +Note that the ID of this compute is *thermo_press* and the group is *all*\ . You can change the attributes of this pressure via the :doc:`compute_modify ` command. Alternatively, you can directly assign a new compute (that calculates pressure) which you @@ -189,7 +189,7 @@ command had been issued: compute thermo_pe all pe See the :doc:`compute pe ` command for details. Note that -the ID of this compute is *thermo\_pe* and the group is *all*\ . You can +the ID of this compute is *thermo_pe* and the group is *all*\ . You can change the attributes of this potential energy via the :doc:`compute_modify ` command. @@ -233,7 +233,7 @@ The *dt* keyword is the current timestep size in time simulation time, also in time :doc:`units `, which is simply (step\*dt) if the timestep size has not changed and the timestep has not been reset. If the timestep has changed (e.g. via :doc:`fix dt/reset `) or the timestep has been reset (e.g. via -the "reset\_timestep" command), then the simulation time is effectively +the "reset_timestep" command), then the simulation time is effectively a cumulative value up to the current point. The *cpu* keyword is elapsed CPU seconds since the beginning of this @@ -305,7 +305,7 @@ quantities in terms of the internal LAMMPS cell dimensions *lx*\ , *ly*\ , ---------- For output values from a compute or fix, the bracketed index I used to -index a vector, as in *c\_ID[I]* or *f\_ID[I]*, can be specified +index a vector, as in *c_ID[I]* or *f_ID[I]*, can be specified using a wildcard asterisk with the index to effectively specify multiple values. This takes the form "\*" or "\*n" or "n\*" or "m\*n". If N = the size of the vector (for *mode* = scalar) or the number of @@ -316,7 +316,7 @@ all indices from n to N (inclusive). A middle asterisk means all indices from m to n (inclusive). Using a wildcard is the same as if the individual elements of the -vector had been listed one by one. E.g. these 2 thermo\_style commands +vector had been listed one by one. E.g. these 2 thermo_style commands are equivalent, since the :doc:`compute temp ` command creates a global vector with 6 values. @@ -330,14 +330,14 @@ creates a global vector with 6 values. ---------- -The *c\_ID* and *c\_ID[I]* and *c\_ID[I][J]* keywords allow global +The *c_ID* and *c_ID[I]* and *c_ID[I][J]* keywords allow global values calculated by a compute to be output. As discussed on the :doc:`compute ` doc page, computes can calculate global, per-atom, or local values. Only global values can be referenced by this command. However, per-atom compute values for an individual atom can be referenced in a :doc:`variable ` and the variable -referenced by thermo\_style custom, as discussed below. See the -discussion above for how the I in *c\_ID[I]* can be specified with a +referenced by thermo_style custom, as discussed below. See the +discussion above for how the I in *c_ID[I]* can be specified with a wildcard asterisk to effectively specify multiple values from a global compute vector. @@ -351,18 +351,18 @@ Note that some computes calculate "intensive" global quantities like temperature; others calculate "extensive" global quantities like kinetic energy that are summed over all atoms in the compute group. Intensive quantities are printed directly without normalization by -thermo\_style custom. Extensive quantities may be normalized by the +thermo_style custom. Extensive quantities may be normalized by the total number of atoms in the simulation (NOT the number of atoms in the compute group) when output, depending on the :doc:`thermo_modify norm ` option being used. -The *f\_ID* and *f\_ID[I]* and *f\_ID[I][J]* keywords allow global +The *f_ID* and *f_ID[I]* and *f_ID[I][J]* keywords allow global values calculated by a fix to be output. As discussed on the :doc:`fix ` doc page, fixes can calculate global, per-atom, or local values. Only global values can be referenced by this command. However, per-atom fix values can be referenced for an individual atom in a :doc:`variable ` and the variable referenced by -thermo\_style custom, as discussed below. See the discussion above for -how the I in *f\_ID[I]* can be specified with a wildcard asterisk to +thermo_style custom, as discussed below. See the discussion above for +how the I in *f_ID[I]* can be specified with a wildcard asterisk to effectively specify multiple values from a global fix vector. The ID in the keyword should be replaced by the actual ID of a fix @@ -374,13 +374,13 @@ brackets will reference a scalar value from the fix. Note that some fixes calculate "intensive" global quantities like timestep size; others calculate "extensive" global quantities like energy that are summed over all atoms in the fix group. Intensive -quantities are printed directly without normalization by thermo\_style +quantities are printed directly without normalization by thermo_style custom. Extensive quantities may be normalized by the total number of atoms in the simulation (NOT the number of atoms in the fix group) when output, depending on the :doc:`thermo_modify norm ` option being used. -The *v\_name* keyword allow the current value of a variable to be +The *v_name* keyword allow the current value of a variable to be output. The name in the keyword should be replaced by the variable name that has been defined elsewhere in the input script. Only equal-style and vector-style variables can be referenced; the latter @@ -396,7 +396,7 @@ output. Note that equal-style and vector-style variables are assumed to produce "intensive" global quantities, which are thus printed as-is, -without normalization by thermo\_style custom. You can include a +without normalization by thermo_style custom. You can include a division by "natoms" in the variable formula if this is not the case. ---------- diff --git a/doc/src/third_order.rst b/doc/src/third_order.rst index 63b236148e..2a6de933e0 100644 --- a/doc/src/third_order.rst +++ b/doc/src/third_order.rst @@ -46,7 +46,7 @@ three elements correspond to the three gamma elements for a specific i/alpha/j/b The initial five numbers are i, alpha, j, beta, and k respectively. If the style eskm is selected, the tensor will be using energy units of 10 J/mol. -These units conform to eskm style from the dynamical\_matrix command, which +These units conform to eskm style from the dynamical_matrix command, which will simplify operations using dynamical matrices with third order tensors. Restrictions @@ -66,4 +66,4 @@ Related commands Default """"""" -The default settings are file = "third\_order.dat", binary = no +The default settings are file = "third_order.dat", binary = no diff --git a/doc/src/variable.rst b/doc/src/variable.rst index 354af1ff20..b1d86cd873 100644 --- a/doc/src/variable.rst +++ b/doc/src/variable.rst @@ -194,7 +194,7 @@ There are two exceptions to this rule. First, variables of style allows these style of variables to be redefined multiple times in an input script. In a loop, this means the formula associated with an *equal* or *atom* style variable can change if it contains a -substitution for another variable, e.g. $x or v\_x. +substitution for another variable, e.g. $x or v_x. Second, as described below, if a variable is iterated on to the end of its list of strings via the :doc:`next ` command, it is removed @@ -485,11 +485,11 @@ references, and references to other variables. +--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Atom vectors | id, mass, type, mol, x, y, z, vx, vy, vz, fx, fy, fz, q | +--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Compute references | c\_ID, c\_ID[i], c\_ID[i][j], C\_ID, C\_ID[i] | +| Compute references | c_ID, c_ID[i], c_ID[i][j], C_ID, C_ID[i] | +--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Fix references | f\_ID, f\_ID[i], f\_ID[i][j], F\_ID, F\_ID[i] | +| Fix references | f_ID, f_ID[i], f_ID[i][j], F_ID, F_ID[i] | +--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Other variables | v\_name, v\_name[i] | +| Other variables | v_name, v_name[i] | +--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ Most of the formula elements produce a scalar value. Some produce a @@ -545,7 +545,7 @@ require a :doc:`compute ` to calculate their values such as "temp" or "press", use computes stored and invoked by the :doc:`thermo_style ` command. This means that you can only use those keywords in a variable if the style you are using with -the thermo\_style command (and the thermo keywords associated with that +the thermo_style command (and the thermo keywords associated with that style) also define and use the needed compute. Note that some thermo keywords use a compute indirectly to calculate their value (e.g. the enthalpy keyword uses temp, pe, and pressure). If a variable is @@ -822,15 +822,15 @@ Special functions take specific kinds of arguments, meaning their arguments cannot be formulas themselves. The sum(x), min(x), max(x), ave(x), trap(x), and slope(x) functions -each take 1 argument which is of the form "c\_ID" or "c\_ID[N]" or -"f\_ID" or "f\_ID[N]" or "v\_name". The first two are computes and the +each take 1 argument which is of the form "c_ID" or "c_ID[N]" or +"f_ID" or "f_ID[N]" or "v_name". The first two are computes and the second two are fixes; the ID in the reference should be replaced by the ID of a compute or fix defined elsewhere in the input script. The compute or fix must produce either a global vector or array. If it produces a global vector, then the notation without "[N]" should be used. If it produces a global array, then the notation with "[N]" should be used, when N is an integer, to specify which column of the -global array is being referenced. The last form of argument "v\_name" +global array is being referenced. The last form of argument "v_name" is for a vector-style variable where "name" is replaced by the name of the variable. @@ -875,7 +875,7 @@ variables. It returns a 1 for atoms that are in both the group and region, and a 0 for atoms that are not in both. The next(x) function takes 1 argument which is a variable ID (not -"v\_foo", just "foo"). It must be for a file-style or atomfile-style +"v_foo", just "foo"). It must be for a file-style or atomfile-style variable. Each time the next() function is invoked (i.e. each time the equal-style or atom-style variable is evaluated), the following steps occur. @@ -912,23 +912,23 @@ themselves (only $-style immediate variable expansion is possible). Return value is either 1.0 or 0.0 depending on whether the function evaluates to true or false, respectively. -The *is\_active()* function allows to query for active settings which +The *is_active()* function allows to query for active settings which are grouped by categories. Currently supported categories and arguments are: * *package* (argument = *gpu* or *intel* or *kokkos* or *omp*\ ) * *newton* (argument = *pair* or *bond* or *any*\ ) * *pair* (argument = *single* or *respa* or *manybody* or *tail* or *shift*\ ) -* *comm\_style* (argument = *brick* or *tiled*\ ) -* *min\_style* (argument = any of the compiled in minimizer styles) -* *run\_style* (argument = any of the compiled in run styles) -* *atom\_style* (argument = any of the compiled in atom styles) -* *pair\_style* (argument = any of the compiled in pair styles) -* *bond\_style* (argument = any of the compiled in bond styles) -* *angle\_style* (argument = any of the compiled in angle styles) -* *dihedral\_style* (argument = any of the compiled in dihedral styles) -* *improper\_style* (argument = any of the compiled in improper styles) -* *kspace\_style* (argument = any of the compiled in kspace styles) +* *comm_style* (argument = *brick* or *tiled*\ ) +* *min_style* (argument = any of the compiled in minimizer styles) +* *run_style* (argument = any of the compiled in run styles) +* *atom_style* (argument = any of the compiled in atom styles) +* *pair_style* (argument = any of the compiled in pair styles) +* *bond_style* (argument = any of the compiled in bond styles) +* *angle_style* (argument = any of the compiled in angle styles) +* *dihedral_style* (argument = any of the compiled in dihedral styles) +* *improper_style* (argument = any of the compiled in improper styles) +* *kspace_style* (argument = any of the compiled in kspace styles) Most of the settings are self-explanatory, the *single* argument in the *pair* category allows to check whether a pair style supports a @@ -952,14 +952,14 @@ Example 2: use r-RESPA with inner/outer cutoff, if supported by pair style, othe timestep $(2.0*(1.0+2.0*is_active(pair,respa)) if $(is_active(pair,respa)) then "run_style respa 4 3 2 2 improper 1 inner 2 5.5 7.0 outer 3 kspace 4" else "run_style respa 3 3 2 improper 1 pair 2 kspace 3" -The *is\_defined()* function allows to query categories like *compute*\ , +The *is_defined()* function allows to query categories like *compute*\ , *dump*\ , *fix*\ , *group*\ , *region*\ , and *variable* whether an entry with the provided name or id is defined. -The *is\_available(category,name)* function allows to query whether +The *is_available(category,name)* function allows to query whether a specific optional feature is available, i.e. compiled in. This currently works for the following categories: *command*\ , -*compute*\ , *fix*\ , *pair\_style* and *feature*\ . For all categories +*compute*\ , *fix*\ , *pair_style* and *feature*\ . For all categories except *command* and *feature* also appending active suffixes is tried before reporting failure. @@ -984,14 +984,14 @@ Atom Values and Vectors Atom values take an integer argument I from 1 to N, where I is the atom-ID, e.g. x[243], which means use the x coordinate of the atom -with ID = 243. Or they can take a variable name, specified as v\_name, -where name is the name of the variable, like x[v\_myIndex]. The +with ID = 243. Or they can take a variable name, specified as v_name, +where name is the name of the variable, like x[v_myIndex]. The variable can be of any style except *vector* or *atom* or *atomfile* variables. The variable is evaluated and the result is expected to be numeric and is cast to an integer (i.e. 3.4 becomes 3), to use an index, which must be a value from 1 to N. Note that a "formula" cannot be used as the argument between the brackets, e.g. x[243+10] -or x[v\_myIndex+1] are not allowed. To do this a single variable can +or x[v_myIndex+1] are not allowed. To do this a single variable can be defined that contains the needed formula. Note that the 0 < atom-ID <= N, where N is the largest atom ID @@ -1038,15 +1038,15 @@ reference means, since computes only produce either global or per-atom quantities, never both. +-------------+-------------------------------------------------------------------------------------------------------+ -| c\_ID | global scalar, or per-atom vector | +| c_ID | global scalar, or per-atom vector | +-------------+-------------------------------------------------------------------------------------------------------+ -| c\_ID[I] | Ith element of global vector, or atom I's value in per-atom vector, or Ith column from per-atom array | +| c_ID[I] | Ith element of global vector, or atom I's value in per-atom vector, or Ith column from per-atom array | +-------------+-------------------------------------------------------------------------------------------------------+ -| c\_ID[I][J] | I,J element of global array, or atom I's Jth value in per-atom array | +| c_ID[I][J] | I,J element of global array, or atom I's Jth value in per-atom array | +-------------+-------------------------------------------------------------------------------------------------------+ For I and J indices, integers can be specified or a variable name, -specified as v\_name, where name is the name of the variable. The +specified as v_name, where name is the name of the variable. The rules for this syntax are the same as for the "Atom Values and Vectors" discussion above. @@ -1060,12 +1060,12 @@ vector-style variable: variable a vector c_foo*v_myVec -The reference "c\_foo" could refer to either the global scalar or -global vector produced by compute "foo". In this case, "c\_foo" will -always refer to the global scalar, and "C\_foo" can be used to +The reference "c_foo" could refer to either the global scalar or +global vector produced by compute "foo". In this case, "c_foo" will +always refer to the global scalar, and "C_foo" can be used to reference the global vector. Similarly if the compute produces both a -global vector and global array, then "c\_foo[I]" will always refer to -an element of the global vector, and "C\_foo[I]" can be used to +global vector and global array, then "c_foo[I]" will always refer to +an element of the global vector, and "C_foo[I]" can be used to reference the Ith column of the global array. Note that if a variable containing a compute is evaluated directly in @@ -1092,21 +1092,21 @@ column of an per-atom array. See the doc pages for individual fixes to see what kind of values they produce. The different kinds of fix references are exactly the same as the -compute references listed in the above table, where "c\_" is replaced -by "f\_". Again, there is typically no ambiguity (see exception below) +compute references listed in the above table, where "c_" is replaced +by "f_". Again, there is typically no ambiguity (see exception below) as to what a reference means, since fixes only produce either global or per-atom quantities, never both. +-------------+-------------------------------------------------------------------------------------------------------+ -| f\_ID | global scalar, or per-atom vector | +| f_ID | global scalar, or per-atom vector | +-------------+-------------------------------------------------------------------------------------------------------+ -| f\_ID[I] | Ith element of global vector, or atom I's value in per-atom vector, or Ith column from per-atom array | +| f_ID[I] | Ith element of global vector, or atom I's value in per-atom vector, or Ith column from per-atom array | +-------------+-------------------------------------------------------------------------------------------------------+ -| f\_ID[I][J] | I,J element of global array, or atom I's Jth value in per-atom array | +| f_ID[I][J] | I,J element of global array, or atom I's Jth value in per-atom array | +-------------+-------------------------------------------------------------------------------------------------------+ For I and J indices, integers can be specified or a variable name, -specified as v\_name, where name is the name of the variable. The +specified as v_name, where name is the name of the variable. The rules for this syntax are the same as for the "Atom Values and Vectors" discussion above. @@ -1114,10 +1114,10 @@ One source of ambiguity for fix references is the same ambiguity discussed for compute references above. Namely when a vector-style variable refers to a fix that produces both a global scalar and a global vector. The solution is the same as for compute references. -For a fix with ID "foo", "f\_foo" will always refer to the global -scalar, and "F\_foo" can be used to reference the global vector. And +For a fix with ID "foo", "f_foo" will always refer to the global +scalar, and "F_foo" can be used to reference the global vector. And similarly for distinguishing between a fix's global vector versus -global array with "f\_foo[I]" versus "F\_foo[I]". +global array with "f_foo[I]" versus "F_foo[I]". Note that if a variable containing a fix is evaluated directly in an input script (not during a run), then the values accessed by the fix @@ -1147,7 +1147,7 @@ generate a per-atom vector of numeric values. All other variables store one or more strings. The formula for an equal-style variable can use any style of variable -including a vector\_style or atom-style or atomfile-style. For these +including a vector_style or atom-style or atomfile-style. For these 3 styles, a subscript must be used to access a single value from the vector-, atom-, or atomfile-style variable. If a string-storing variable is used, the string is converted to a numeric value. Note @@ -1169,19 +1169,19 @@ There is no ambiguity as to what a reference means, since variables produce only a global scalar or global vector or per-atom vector. +------------+----------------------------------------------------------------------+ -| v\_name | global scalar from equal-style variable | +| v_name | global scalar from equal-style variable | +------------+----------------------------------------------------------------------+ -| v\_name | global vector from vector-style variable | +| v_name | global vector from vector-style variable | +------------+----------------------------------------------------------------------+ -| v\_name | per-atom vector from atom-style or atomfile-style variable | +| v_name | per-atom vector from atom-style or atomfile-style variable | +------------+----------------------------------------------------------------------+ -| v\_name[I] | Ith element of a global vector from vector-style variable | +| v_name[I] | Ith element of a global vector from vector-style variable | +------------+----------------------------------------------------------------------+ -| v\_name[I] | value of atom with ID = I from atom-style or atomfile-style variable | +| v_name[I] | value of atom with ID = I from atom-style or atomfile-style variable | +------------+----------------------------------------------------------------------+ For the I index, an integer can be specified or a variable name, -specified as v\_name, where name is the name of the variable. The +specified as v_name, where name is the name of the variable. The rules for this syntax are the same as for the "Atom Values and Vectors" discussion above. @@ -1199,16 +1199,16 @@ formula immediately without using the variable command to define a named variable. More generally, there is a difference between referencing a variable -with a leading $ sign (e.g. $x or ${abc}) versus with a leading "v\_" -(e.g. v\_x or v\_abc). The former can be used in any input script +with a leading $ sign (e.g. $x or ${abc}) versus with a leading "v_" +(e.g. v_x or v_abc). The former can be used in any input script command, including a variable command. The input script parser evaluates the reference variable immediately and substitutes its value into the command. As explained on the :doc:`Commands parse ` doc page, you can also use un-named "immediate" variables for this purpose. For example, a string like -this $((xlo+xhi)/2+sqrt(v\_area)) in an input script command evaluates +this $((xlo+xhi)/2+sqrt(v_area)) in an input script command evaluates the string between the parenthesis as an equal-style variable formula. -Referencing a variable with a leading "v\_" is an optional or required +Referencing a variable with a leading "v_" is an optional or required kind of argument for some commands (e.g. the :doc:`fix ave/chunk ` or :doc:`dump custom ` or :doc:`thermo_style ` commands) if you wish it to evaluate a variable periodically during a run. It can also be used in a @@ -1226,7 +1226,7 @@ define the variable "v" as before a run where the simulation box size changes. You might think this will assign the initial volume to the variable "v". That is not the case. Rather it assigns a formula which evaluates the volume -(using the thermo\_style keyword "vol") to the variable "v". If you +(using the thermo_style keyword "vol") to the variable "v". If you use the variable "v" in some other command like :doc:`fix ave/time ` then the current volume of the box will be evaluated continuously during the run. diff --git a/doc/src/velocity.rst b/doc/src/velocity.rst index 7b34f80f86..59ce0a19f6 100644 --- a/doc/src/velocity.rst +++ b/doc/src/velocity.rst @@ -74,7 +74,7 @@ The *set* style sets the velocities of all atoms in the group to the specified values. If any component is specified as NULL, then it is not set. Any of the vx,vy,vz velocity components can be specified as an equal-style or atom-style :doc:`variable `. If the value -is a variable, it should be specified as v\_name, where name is the +is a variable, it should be specified as v_name, where name is the variable name. In this case, the variable will be evaluated, and its value used to determine the velocity component. Note that if a variable is used, the velocity it calculates must be in box units, not diff --git a/doc/src/write_coeff.rst b/doc/src/write_coeff.rst index e2aa7bcc62..71cfe9cb02 100644 --- a/doc/src/write_coeff.rst +++ b/doc/src/write_coeff.rst @@ -30,7 +30,7 @@ the Coeffs sections from a data file into a separate file. .. note:: - The write\_coeff command is not yet fully implemented as + The write_coeff command is not yet fully implemented as some pair styles do not output their coefficient information. This means you will need to add/copy this information manually. diff --git a/doc/src/write_data.rst b/doc/src/write_data.rst index c157dff546..13a6476ac4 100644 --- a/doc/src/write_data.rst +++ b/doc/src/write_data.rst @@ -51,7 +51,7 @@ value. the :doc:`pair_coeff ` command. Second, a few of the :doc:`atom styles ` (body, ellipsoid, line, tri) that store auxiliary "bonus" information about aspherical particles, do not yet write the bonus info into the data file. Both these functionalities - will be added to the write\_data command later. + will be added to the write_data command later. Because a data file is in text format, if you use a data file written out by this command to restart a simulation, the initial state of the diff --git a/doc/src/write_dump.rst b/doc/src/write_dump.rst index d0daa73052..f0f57bd674 100644 --- a/doc/src/write_dump.rst +++ b/doc/src/write_dump.rst @@ -49,14 +49,14 @@ added. The latter is so that the full range of :doc:`dump_modify ` options can be specified for the single snapshot, just as they can be for multiple snapshots. The *modify* keyword separates the arguments that would normally be passed to the -*dump* command from those that would be given the *dump\_modify*. Both +*dump* command from those that would be given the *dump_modify*. Both support optional arguments and thus LAMMPS needs to be able to cleanly separate the two sets of args. Note that if the specified filename uses wildcard characters "\*" or "%", as supported by the :doc:`dump ` command, they will operate in the same fashion to create the new filename(s). Normally, :doc:`dump image ` files require a filename with a "\*" character -for the timestep. That is not the case for the write\_dump command; no +for the timestep. That is not the case for the write_dump command; no wildcard "\*" character is necessary. ---------- diff --git a/doc/src/write_restart.rst b/doc/src/write_restart.rst index 41193d05b7..bdb77dd4b4 100644 --- a/doc/src/write_restart.rst +++ b/doc/src/write_restart.rst @@ -37,7 +37,7 @@ Write a binary restart file of the current state of the simulation. During a long simulation, the :doc:`restart ` command is typically used to output restart files periodically. The -write\_restart command is useful after a minimization or whenever you +write_restart command is useful after a minimization or whenever you wish to write out a single current restart file. Similar to :doc:`dump ` files, the restart filename can contain -- GitLab From a990f1dc899474903027bbc7bad0b4024f3d4f81 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 13 Mar 2020 16:42:08 -0400 Subject: [PATCH 265/689] some minor fixups --- doc/src/improper_ring.rst | 6 +++--- doc/src/pair_adp.rst | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/src/improper_ring.rst b/doc/src/improper_ring.rst index df4a73760e..0634405c0e 100644 --- a/doc/src/improper_ring.rst +++ b/doc/src/improper_ring.rst @@ -39,9 +39,9 @@ equilibrium value. If the 4 atoms in an improper quadruplet (listed in the data file read by the :doc:`read_data ` command) are ordered i,j,k,l then -theta_\ *ijl* is the angle between atoms i,j and l, theta_\ *ijk* is the -angle between atoms i,j and k, theta_\ *kjl* is the angle between atoms -j,k, and l. +:math:`\theta_{ijl}` is the angle between atoms i,j and l, +:math:`\theta_{ijk}` is the angle between atoms i,j and k, +:math:`\theta_{kjl}` is the angle between atoms j,k, and l. The "ring" improper style implements the improper potential introduced by Destree et al., in Equation (9) of :ref:`(Destree) `. This diff --git a/doc/src/pair_adp.rst b/doc/src/pair_adp.rst index 2e2be63430..6c4796fb85 100644 --- a/doc/src/pair_adp.rst +++ b/doc/src/pair_adp.rst @@ -105,13 +105,13 @@ command for further details on the *setfl* format. * lines 1,2,3 = comments (ignored) * line 4: :math:`N_{\text{elements}}` Element1 Element2 ... ElementN -* line 5: :math:`N_\rho`, :math:`d_\rho`, :math:`N_r`, :math:`d_r`, cutoff +* line 5: :math:`N_{\rho}`, :math:`d_{\rho}`, :math:`N_r`, :math:`d_r`, cutoff Following the 5 header lines are :math:`N_{\text{elements}}` sections, one for each element, each with the following format: * line 1 = atomic number, mass, lattice constant, lattice type (e.g. FCC) -* embedding function :math:`F(\rho)` (:math:`N_\rho` values) +* embedding function :math:`F(\rho)` (:math:`N_{\rho}` values) * density function :math:`\rho(r)` (:math:`N_r` values) Following the :math:`N_{\text{elements}}` sections, :math:`N_r` values for each pair potential -- GitLab From 0c0308db3e1b6da7b9e6dc0d49cab95e5d33c800 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 13 Mar 2020 16:59:24 -0400 Subject: [PATCH 266/689] some more fixups --- doc/src/Errors_messages.rst | 2 +- doc/src/Examples.rst | 4 ++-- doc/src/Howto_manifold.rst | 8 ++++---- doc/src/Python_examples.rst | 6 +++--- doc/src/compute_chunk_atom.rst | 6 +++--- doc/src/compute_global_atom.rst | 12 +++++------ doc/src/compute_reduce.rst | 6 +++--- doc/src/compute_slice.rst | 6 +++--- doc/src/dump_image.rst | 2 +- doc/src/dump_modify.rst | 2 +- doc/src/fix.rst | 6 +++--- doc/src/fix_ave_atom.rst | 6 +++--- doc/src/fix_ave_chunk.rst | 6 +++--- doc/src/fix_ave_correlate.rst | 6 +++--- doc/src/fix_ave_histo.rst | 6 +++--- doc/src/fix_ave_time.rst | 6 +++--- doc/src/fix_controller.rst | 8 ++++---- doc/src/fix_rx.rst | 2 +- doc/src/fix_vector.rst | 6 +++--- doc/src/pair_resquared.rst | 2 +- doc/src/variable.rst | 36 ++++++++++++++++----------------- 21 files changed, 72 insertions(+), 72 deletions(-) diff --git a/doc/src/Errors_messages.rst b/doc/src/Errors_messages.rst index 6e52573b3e..82c9d0bd78 100644 --- a/doc/src/Errors_messages.rst +++ b/doc/src/Errors_messages.rst @@ -301,7 +301,7 @@ Doc page with :doc:`WARNING messages ` Specified bond type is not valid. *Bad fix ID in fix append/atoms command* - The value of the fix_id for keyword spatial must start with 'f_'. + The value of the fix_id for keyword spatial must start with "f\_". *Bad grid of processors* The 3d grid of processors defined by the processors command does not diff --git a/doc/src/Examples.rst b/doc/src/Examples.rst index 36b486d31f..21ab13e2d4 100644 --- a/doc/src/Examples.rst +++ b/doc/src/Examples.rst @@ -132,7 +132,7 @@ Lowercase directories +-------------+------------------------------------------------------------------+ | reax | RDX and TATB models using the ReaxFF | +-------------+------------------------------------------------------------------+ -| rerun | use of rerun and read_dump commands | +| rerun | use of rerun and read_dump commands | +-------------+------------------------------------------------------------------+ | rigid | rigid bodies modeled as independent or coupled | +-------------+------------------------------------------------------------------+ @@ -195,7 +195,7 @@ Uppercase directories +------------+--------------------------------------------------------------------------------------------------+ | ELASTIC | compute elastic constants at zero temperature | +------------+--------------------------------------------------------------------------------------------------+ -| ELASTIC_T | compute elastic constants at finite temperature | +| ELASTIC_T | compute elastic constants at finite temperature | +------------+--------------------------------------------------------------------------------------------------+ | HEAT | compute thermal conductivity for LJ and water via fix ehex | +------------+--------------------------------------------------------------------------------------------------+ diff --git a/doc/src/Howto_manifold.rst b/doc/src/Howto_manifold.rst index 239c32b342..41e1fb6a4c 100644 --- a/doc/src/Howto_manifold.rst +++ b/doc/src/Howto_manifold.rst @@ -19,17 +19,17 @@ to the relevant fixes. +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ | cylinder | R | x\^2 + y\^2 - R\^2 = 0 | Cylinder along z-axis, axis going through (0,0,0) | +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ -| cylinder_dent | R l a | x\^2 + y\^2 - r(z)\^2 = 0, r(x) = R if \| z \| > l, r(z) = R - a\*(1 + cos(z/l))/2 otherwise | A cylinder with a dent around z = 0 | +| cylinder_dent | R l a | x\^2 + y\^2 - r(z)\^2 = 0, r(x) = R if \| z \| > l, r(z) = R - a\*(1 + cos(z/l))/2 otherwise | A cylinder with a dent around z = 0 | +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ | dumbbell | a A B c | -( x\^2 + y\^2 ) + (a\^2 - z\^2/c\^2) \* ( 1 + (A\*sin(B\*z\^2))\^4) = 0 | A dumbbell | +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ | ellipsoid | a b c | (x/a)\^2 + (y/b)\^2 + (z/c)\^2 = 0 | An ellipsoid | +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ -| gaussian_bump | A l rc1 rc2 | if( x < rc1) -z + A \* exp( -x\^2 / (2 l\^2) ); else if( x < rc2 ) -z + a + b\*x + c\*x\^2 + d\*x\^3; else z | A Gaussian bump at x = y = 0, smoothly tapered to a flat plane z = 0. | +| gaussian_bump | A l rc1 rc2 | if( x < rc1) -z + A \* exp( -x\^2 / (2 l\^2) ); else if( x < rc2 ) -z + a + b\*x + c\*x\^2 + d\*x\^3; else z | A Gaussian bump at x = y = 0, smoothly tapered to a flat plane z = 0. | +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ | plane | a b c x0 y0 z0 | a\*(x-x0) + b\*(y-y0) + c\*(z-z0) = 0 | A plane with normal (a,b,c) going through point (x0,y0,z0) | +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ -| plane_wiggle | a w | z - a\*sin(w\*x) = 0 | A plane with a sinusoidal modulation on z along x. | +| plane_wiggle | a w | z - a\*sin(w\*x) = 0 | A plane with a sinusoidal modulation on z along x. | +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ | sphere | R | x\^2 + y\^2 + z\^2 - R\^2 = 0 | A sphere of radius R | +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ @@ -37,7 +37,7 @@ to the relevant fixes. +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ | spine | a, A, B, B2, c | -(x\^2 + y\^2) + (a\^2 - z\^2/f(z)\^2)\*(1 + (A\*sin(g(z)\*z\^2))\^4), f(z) = c if z > 0, 1 otherwise; g(z) = B if z > 0, B2 otherwise | An approximation to a dendritic spine | +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ -| spine_two | a, A, B, B2, c | -(x\^2 + y\^2) + (a\^2 - z\^2/f(z)\^2)\*(1 + (A\*sin(g(z)\*z\^2))\^2), f(z) = c if z > 0, 1 otherwise; g(z) = B if z > 0, B2 otherwise | Another approximation to a dendritic spine | +| spine_two | a, A, B, B2, c | -(x\^2 + y\^2) + (a\^2 - z\^2/f(z)\^2)\*(1 + (A\*sin(g(z)\*z\^2))\^2), f(z) = c if z > 0, 1 otherwise; g(z) = B if z > 0, B2 otherwise | Another approximation to a dendritic spine | +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ | thylakoid | wB LB lB | Various, see :ref:`(Paquay) ` | A model grana thylakoid consisting of two block-like compartments connected by a bridge of width wB, length LB and taper length lB | +----------------+----------------+----------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+ diff --git a/doc/src/Python_examples.rst b/doc/src/Python_examples.rst index c3b0381e64..976358801e 100644 --- a/doc/src/Python_examples.rst +++ b/doc/src/Python_examples.rst @@ -20,11 +20,11 @@ distribution. +----------------------------------------------------------------+--------------------------------------------------+ | GUI go/stop/temperature-slider to control LAMMPS | plot.py | +----------------------------------------------------------------+--------------------------------------------------+ -| real-time temperature plot with GnuPlot via Pizza.py | viz_tool.py | +| real-time temperature plot with GnuPlot via Pizza.py | viz_tool.py | +----------------------------------------------------------------+--------------------------------------------------+ -| real-time viz via some viz package | vizplotgui_tool.py | +| real-time viz via some viz package | vizplotgui_tool.py | +----------------------------------------------------------------+--------------------------------------------------+ -| combination of viz_tool.py and plot.py and gui.py | | +| combination of viz_tool.py and plot.py and gui.py | | +----------------------------------------------------------------+--------------------------------------------------+ ---------- diff --git a/doc/src/compute_chunk_atom.rst b/doc/src/compute_chunk_atom.rst index aa404fd4da..ead17e3f7c 100644 --- a/doc/src/compute_chunk_atom.rst +++ b/doc/src/compute_chunk_atom.rst @@ -270,14 +270,14 @@ chunk ID to the atom. *Nchunk* is set to the largest chunk ID. Note that this excludes atoms which are not in the specified group or optional region. -If the style begins with "c_", a compute ID must follow which has been +If the style begins with "c\_", a compute ID must follow which has been previously defined in the input script. If no bracketed integer is appended, the per-atom vector calculated by the compute is used. If a bracketed integer is appended, the Ith column of the per-atom array calculated by the compute is used. Users can also write code for their own compute styles and :doc:`add them to LAMMPS `. -If the style begins with "f_", a fix ID must follow which has been +If the style begins with "f\_", a fix ID must follow which has been previously defined in the input script. If no bracketed integer is appended, the per-atom vector calculated by the fix is used. If a bracketed integer is appended, the Ith column of the per-atom array @@ -286,7 +286,7 @@ their values on certain timesteps, which must be compatible with the timestep on which this compute accesses the fix, else an error results. Users can also write code for their own fix styles and :doc:`add them to LAMMPS `. -If a value begins with "v_", a variable name for an *atom* or +If a value begins with "v\_", a variable name for an *atom* or *atomfile* style :doc:`variable ` must follow which has been previously defined in the input script. Variables of style *atom* can reference thermodynamic keywords and various per-atom attributes, or diff --git a/doc/src/compute_global_atom.rst b/doc/src/compute_global_atom.rst index 1b301f700e..e9adb0317b 100644 --- a/doc/src/compute_global_atom.rst +++ b/doc/src/compute_global_atom.rst @@ -133,7 +133,7 @@ simple rounded down to convert the value to integer indices. The final values should range from 1 to N (inclusive), since they are used to access values from N-length vectors. -If *index* begins with "c_", a compute ID must follow which has been +If *index* begins with "c\_", a compute ID must follow which has been previously defined in the input script. The compute must generate per-atom quantities. See the individual :doc:`compute ` doc page for details. If no bracketed integer is appended, the per-atom @@ -144,7 +144,7 @@ styles and :doc:`add them to LAMMPS `. See the discussion above for how I can be specified with a wildcard asterisk to effectively specify multiple values. -If *index* begins with "f_", a fix ID must follow which has been +If *index* begins with "f\_", a fix ID must follow which has been previously defined in the input script. The Fix must generate per-atom quantities. See the individual :doc:`fix ` doc page for details. Note that some fixes only produce their values on certain @@ -157,7 +157,7 @@ own fix style and :doc:`add them to LAMMPS `. See the discussion above for how I can be specified with a wildcard asterisk to effectively specify multiple values. -If *index* begins with "v_", a variable name must follow which has +If *index* begins with "v\_", a variable name must follow which has been previously defined in the input script. It must be an :doc:`atom-style variable `. Atom-style variables can reference thermodynamic keywords and various per-atom attributes, or @@ -171,7 +171,7 @@ This section explains the kinds of *input* values that can be used. Note that inputs reference global values, as contrasted with the *index* parameter which must reference per-atom values. -If a value begins with "c_", a compute ID must follow which has been +If a value begins with "c\_", a compute ID must follow which has been previously defined in the input script. The compute must generate a global vector or array. See the individual :doc:`compute ` doc page for details. If no bracketed integer is appended, the vector @@ -181,7 +181,7 @@ used. Users can also write code for their own compute styles and :doc:`add them I can be specified with a wildcard asterisk to effectively specify multiple values. -If a value begins with "f_", a fix ID must follow which has been +If a value begins with "f\_", a fix ID must follow which has been previously defined in the input script. The fix must generate a global vector or array. See the individual :doc:`fix ` doc page for details. Note that some fixes only produce their values on @@ -194,7 +194,7 @@ own fix style and :doc:`add them to LAMMPS `. See the discussion above for how I can be specified with a wildcard asterisk to effectively specify multiple values. -If a value begins with "v_", a variable name must follow which has +If a value begins with "v\_", a variable name must follow which has been previously defined in the input script. It must be a :doc:`vector-style variable `. Vector-style variables can reference thermodynamic keywords and various other attributes of diff --git a/doc/src/compute_reduce.rst b/doc/src/compute_reduce.rst index 3391f3c3cb..7599343d2e 100644 --- a/doc/src/compute_reduce.rst +++ b/doc/src/compute_reduce.rst @@ -122,7 +122,7 @@ self-explanatory. Note that other atom attributes can be used as inputs to this fix by using the :doc:`compute property/atom ` command and then specifying an input value from that compute. -If a value begins with "c_", a compute ID must follow which has been +If a value begins with "c\_", a compute ID must follow which has been previously defined in the input script. Computes can generate per-atom or local quantities. See the individual :doc:`compute ` doc page for details. If no bracketed integer @@ -133,7 +133,7 @@ compute styles and :doc:`add them to LAMMPS `. See the discussion above for how I can be specified with a wildcard asterisk to effectively specify multiple values. -If a value begins with "f_", a fix ID must follow which has been +If a value begins with "f\_", a fix ID must follow which has been previously defined in the input script. Fixes can generate per-atom or local quantities. See the individual :doc:`fix ` doc page for details. Note that some fixes only produce their values on certain @@ -145,7 +145,7 @@ is used. Users can also write code for their own fix style and :doc:`add them t be specified with a wildcard asterisk to effectively specify multiple values. -If a value begins with "v_", a variable name must follow which has +If a value begins with "v\_", a variable name must follow which has been previously defined in the input script. It must be an :doc:`atom-style variable `. Atom-style variables can reference thermodynamic keywords and various per-atom attributes, or diff --git a/doc/src/compute_slice.rst b/doc/src/compute_slice.rst index 7262f2c368..c8211269bc 100644 --- a/doc/src/compute_slice.rst +++ b/doc/src/compute_slice.rst @@ -55,7 +55,7 @@ vector. Each listed input must be a global vector or column of a global array calculated by another :doc:`compute ` or :doc:`fix `. -If an input value begins with "c_", a compute ID must follow which has +If an input value begins with "c\_", a compute ID must follow which has been previously defined in the input script and which generates a global vector or array. See the individual :doc:`compute ` doc page for details. If no bracketed integer is appended, the vector @@ -63,7 +63,7 @@ calculated by the compute is used. If a bracketed integer is appended, the Ith column of the array calculated by the compute is used. Users can also write code for their own compute styles and :doc:`add them to LAMMPS `. -If a value begins with "f_", a fix ID must follow which has been +If a value begins with "f\_", a fix ID must follow which has been previously defined in the input script and which generates a global vector or array. See the individual :doc:`fix ` doc page for details. Note that some fixes only produce their values on certain @@ -73,7 +73,7 @@ appended, the vector calculated by the fix is used. If a bracketed integer is appended, the Ith column of the array calculated by the fix is used. Users can also write code for their own fix style and :doc:`add them to LAMMPS `. -If an input value begins with "v_", a variable name must follow which +If an input value begins with "v\_", a variable name must follow which has been previously defined in the input script. Only vector-style variables can be referenced. See the :doc:`variable ` command for details. Note that variables of style *vector* define a formula diff --git a/doc/src/dump_image.rst b/doc/src/dump_image.rst index fabe2643b1..0477e5d718 100644 --- a/doc/src/dump_image.rst +++ b/doc/src/dump_image.rst @@ -193,7 +193,7 @@ atoms rendered in the image. They can be any atom attribute defined for the :doc:`dump custom ` command, including *type* and *element*\ . This includes per-atom quantities calculated by a :doc:`compute `, :doc:`fix `, or :doc:`variable `, -which are prefixed by "c_", "f_", or "v_" respectively. Note that the +which are prefixed by "c\_", "f\_", or "v\_" respectively. Note that the *diameter* setting can be overridden with a numeric value applied to all atoms by the optional *adiam* keyword. diff --git a/doc/src/dump_modify.rst b/doc/src/dump_modify.rst index 465f92ecfb..5f7f42b4be 100644 --- a/doc/src/dump_modify.rst +++ b/doc/src/dump_modify.rst @@ -461,7 +461,7 @@ The *refresh* keyword only applies to the dump *custom*\ , *cfg*\ , *image*\ , and *movie* styles. It allows an "incremental" dump file to be written, by refreshing a compute that is used as a threshold for determining which atoms are included in a dump snapshot. The -specified *c_ID* gives the ID of the compute. It is prefixed by "c_" +specified *c_ID* gives the ID of the compute. It is prefixed by "c\_" to indicate a compute, which is the only current option. At some point, other options may be added, e.g. fixes or variables. diff --git a/doc/src/fix.rst b/doc/src/fix.rst index 263ce9991c..2182ce7460 100644 --- a/doc/src/fix.rst +++ b/doc/src/fix.rst @@ -103,11 +103,11 @@ discussed below, it can be referenced via the following bracket notation, where ID is the ID of the fix: +-------------+--------------------------------------------+ -| f_ID | entire scalar, vector, or array | +| f_ID | entire scalar, vector, or array | +-------------+--------------------------------------------+ -| f_ID[I] | one element of vector, one column of array | +| f_ID[I] | one element of vector, one column of array | +-------------+--------------------------------------------+ -| f_ID[I][J] | one element of array | +| f_ID[I][J] | one element of array | +-------------+--------------------------------------------+ In other words, using one bracket reduces the dimension of the diff --git a/doc/src/fix_ave_atom.rst b/doc/src/fix_ave_atom.rst index 40c61239cb..93ff48ce0f 100644 --- a/doc/src/fix_ave_atom.rst +++ b/doc/src/fix_ave_atom.rst @@ -121,7 +121,7 @@ an input value from that compute. which can be provided by the :doc:`compute property/atom ` command via its xu,yu,zu attributes. -If a value begins with "c_", a compute ID must follow which has been +If a value begins with "c\_", a compute ID must follow which has been previously defined in the input script. If no bracketed term is appended, the per-atom vector calculated by the compute is used. If a bracketed term containing an index I is appended, the Ith column of @@ -130,7 +130,7 @@ write code for their own compute styles and :doc:`add them to LAMMPS `. be specified with a wildcard asterisk to effectively specify multiple values. -If a value begins with "f_", a fix ID must follow which has been +If a value begins with "f\_", a fix ID must follow which has been previously defined in the input script. If no bracketed term is appended, the per-atom vector calculated by the fix is used. If a bracketed term containing an index I is appended, the Ith column of @@ -141,7 +141,7 @@ write code for their own fix styles and :doc:`add them to LAMMPS `. See specified with a wildcard asterisk to effectively specify multiple values. -If a value begins with "v_", a variable name must follow which has +If a value begins with "v\_", a variable name must follow which has been previously defined in the input script as an :doc:`atom-style variable ` Variables of style *atom* can reference thermodynamic keywords, or invoke other computes, fixes, or variables when they are evaluated, so this is a very general means of generating diff --git a/doc/src/fix_ave_chunk.rst b/doc/src/fix_ave_chunk.rst index 34116a56a2..b19cce417c 100644 --- a/doc/src/fix_ave_chunk.rst +++ b/doc/src/fix_ave_chunk.rst @@ -265,7 +265,7 @@ of atoms to calculate their temperature. The compute allows the center-of-mass velocity of each chunk to be subtracted before calculating the temperature; this fix does not. -If a value begins with "c_", a compute ID must follow which has been +If a value begins with "c\_", a compute ID must follow which has been previously defined in the input script. If no bracketed integer is appended, the per-atom vector calculated by the compute is used. If a bracketed integer is appended, the Ith column of the per-atom array @@ -274,7 +274,7 @@ their own compute styles and :doc:`add them to LAMMPS `. See the discussion above for how I can be specified with a wildcard asterisk to effectively specify multiple values. -If a value begins with "f_", a fix ID must follow which has been +If a value begins with "f\_", a fix ID must follow which has been previously defined in the input script. If no bracketed integer is appended, the per-atom vector calculated by the fix is used. If a bracketed integer is appended, the Ith column of the per-atom array @@ -285,7 +285,7 @@ own fix styles and :doc:`add them to LAMMPS `. See the discussion above for how I can be specified with a wildcard asterisk to effectively specify multiple values. -If a value begins with "v_", a variable name must follow which has +If a value begins with "v\_", a variable name must follow which has been previously defined in the input script. Variables of style *atom* can reference thermodynamic keywords and various per-atom attributes, or invoke other computes, fixes, or variables when they diff --git a/doc/src/fix_ave_correlate.rst b/doc/src/fix_ave_correlate.rst index c921e8e55b..c42159e89b 100644 --- a/doc/src/fix_ave_correlate.rst +++ b/doc/src/fix_ave_correlate.rst @@ -169,7 +169,7 @@ default, then *Nfreq* >= (\ *Nrepeat*\ -1)\*\ *Nevery* is required. ---------- -If a value begins with "c_", a compute ID must follow which has been +If a value begins with "c\_", a compute ID must follow which has been previously defined in the input script. If no bracketed term is appended, the global scalar calculated by the compute is used. If a bracketed term is appended, the Ith element of the global vector @@ -185,7 +185,7 @@ or :doc:`fix temp/rescale `. See the doc pages for these commands which give the IDs of these computes. Users can also write code for their own compute styles and :doc:`add them to LAMMPS `. -If a value begins with "f_", a fix ID must follow which has been +If a value begins with "f\_", a fix ID must follow which has been previously defined in the input script. If no bracketed term is appended, the global scalar calculated by the fix is used. If a bracketed term is appended, the Ith element of the global vector @@ -197,7 +197,7 @@ Note that some fixes only produce their values on certain timesteps, which must be compatible with *Nevery*\ , else an error will result. Users can also write code for their own fix styles and :doc:`add them to LAMMPS `. -If a value begins with "v_", a variable name must follow which has +If a value begins with "v\_", a variable name must follow which has been previously defined in the input script. Only equal-style or vector-style variables can be referenced; the latter requires a bracketed term to specify the Ith element of the vector calculated by diff --git a/doc/src/fix_ave_histo.rst b/doc/src/fix_ave_histo.rst index b9437834f0..158f259695 100644 --- a/doc/src/fix_ave_histo.rst +++ b/doc/src/fix_ave_histo.rst @@ -176,7 +176,7 @@ self-explanatory. Note that other atom attributes can be used as inputs to this fix by using the :doc:`compute property/atom ` command and then specifying an input value from that compute. -If a value begins with "c_", a compute ID must follow which has been +If a value begins with "c\_", a compute ID must follow which has been previously defined in the input script. If *mode* = scalar, then if no bracketed term is appended, the global scalar calculated by the compute is used. If a bracketed term is appended, the Ith element of @@ -196,7 +196,7 @@ or :doc:`fix temp/rescale `. See the doc pages for these commands which give the IDs of these computes. Users can also write code for their own compute styles and :doc:`add them to LAMMPS `. -If a value begins with "f_", a fix ID must follow which has been +If a value begins with "f\_", a fix ID must follow which has been previously defined in the input script. If *mode* = scalar, then if no bracketed term is appended, the global scalar calculated by the fix is used. If a bracketed term is appended, the Ith element of the @@ -212,7 +212,7 @@ Note that some fixes only produce their values on certain timesteps, which must be compatible with *Nevery*\ , else an error will result. Users can also write code for their own fix styles and :doc:`add them to LAMMPS `. -If a value begins with "v_", a variable name must follow which has +If a value begins with "v\_", a variable name must follow which has been previously defined in the input script. If *mode* = scalar, then only equal-style or vector-style variables can be used, which both produce global values. In this mode, a vector-style variable requires diff --git a/doc/src/fix_ave_time.rst b/doc/src/fix_ave_time.rst index 9d121488cc..efa8095d69 100644 --- a/doc/src/fix_ave_time.rst +++ b/doc/src/fix_ave_time.rst @@ -155,7 +155,7 @@ averaging is done; values are simply generated on timesteps ---------- -If a value begins with "c_", a compute ID must follow which has been +If a value begins with "c\_", a compute ID must follow which has been previously defined in the input script. If *mode* = scalar, then if no bracketed term is appended, the global scalar calculated by the compute is used. If a bracketed term is appended, the Ith element of @@ -173,7 +173,7 @@ not in your input script, but by :doc:`thermodynamic output ` or o the doc pages for these commands which give the IDs of these computes. Users can also write code for their own compute styles and :doc:`add them to LAMMPS `. -If a value begins with "f_", a fix ID must follow which has been +If a value begins with "f\_", a fix ID must follow which has been previously defined in the input script. If *mode* = scalar, then if no bracketed term is appended, the global scalar calculated by the fix is used. If a bracketed term is appended, the Ith element of the @@ -188,7 +188,7 @@ Note that some fixes only produce their values on certain timesteps, which must be compatible with *Nevery*\ , else an error will result. Users can also write code for their own fix styles and :doc:`add them to LAMMPS `. -If a value begins with "v_", a variable name must follow which has +If a value begins with "v\_", a variable name must follow which has been previously defined in the input script. If *mode* = scalar, then only equal-style or vector-style variables can be used, which both produce global values. In this mode, a vector-style variable requires diff --git a/doc/src/fix_controller.rst b/doc/src/fix_controller.rst index 45ff47f868..2fd5f17c95 100644 --- a/doc/src/fix_controller.rst +++ b/doc/src/fix_controller.rst @@ -152,7 +152,7 @@ The process variable *pvar* can be specified as the output of a :doc:`variable `. In each case, the compute, fix, or variable must produce a global quantity, not a per-atom or local quantity. -If *pvar* begins with "c_", a compute ID must follow which has been +If *pvar* begins with "c\_", a compute ID must follow which has been previously defined in the input script and which generates a global scalar or vector. See the individual :doc:`compute ` doc page for details. If no bracketed integer is appended, the scalar @@ -160,7 +160,7 @@ calculated by the compute is used. If a bracketed integer is appended, the Ith value of the vector calculated by the compute is used. Users can also write code for their own compute styles and :doc:`add them to LAMMPS `. -If *pvar* begins with "f_", a fix ID must follow which has been +If *pvar* begins with "f\_", a fix ID must follow which has been previously defined in the input script and which generates a global scalar or vector. See the individual :doc:`fix ` doc page for details. Note that some fixes only produce their values on certain @@ -170,7 +170,7 @@ is appended, the scalar calculated by the fix is used. If a bracketed integer is appended, the Ith value of the vector calculated by the fix is used. Users can also write code for their own fix style and :doc:`add them to LAMMPS `. -If *pvar* begins with "v_", a variable name must follow which has been +If *pvar* begins with "v\_", a variable name must follow which has been previously defined in the input script. Only equal-style variables can be referenced. See the :doc:`variable ` command for details. Note that variables of style *equal* define a formula which @@ -183,7 +183,7 @@ The target value *setpoint* for the process variable must be a numeric value, in whatever units *pvar* is defined for. The control variable *cvar* must be the name of an :doc:`internal-style variable ` previously defined in the input script. Note -that it is not specified with a "v_" prefix, just the name of the +that it is not specified with a "v\_" prefix, just the name of the variable. It must be an internal-style variable, because this fix updates its value directly. Note that other commands can use an equal-style versus internal-style variable interchangeably. diff --git a/doc/src/fix_rx.rst b/doc/src/fix_rx.rst index c79fd2178b..0d8af574c1 100644 --- a/doc/src/fix_rx.rst +++ b/doc/src/fix_rx.rst @@ -189,7 +189,7 @@ Note that the species tags that are defined in the reaction equations are used by the :doc:`fix eos/table/rx ` command to define the thermodynamic properties of each species. Furthermore, the number of species molecules (i.e., concentration) can be specified -either with the :doc:`set ` command using the "d_" prefix or by +either with the :doc:`set ` command using the "d\_" prefix or by reading directly the concentrations from a data file. For the latter case, the :doc:`read_data ` command with the fix keyword should be specified, where the fix-ID will be the "fix rx`ID with a `_ suffix, e.g. diff --git a/doc/src/fix_vector.rst b/doc/src/fix_vector.rst index 8cf6d900f4..81922dea8a 100644 --- a/doc/src/fix_vector.rst +++ b/doc/src/fix_vector.rst @@ -86,7 +86,7 @@ sufficient size. ---------- -If a value begins with "c_", a compute ID must follow which has been +If a value begins with "c\_", a compute ID must follow which has been previously defined in the input script. If no bracketed term is appended, the global scalar calculated by the compute is used. If a bracketed term is appended, the Ith element of the global vector @@ -100,7 +100,7 @@ or :doc:`fix temp/rescale `. See the doc pages for these commands which give the IDs of these computes. Users can also write code for their own compute styles and :doc:`add them to LAMMPS `. -If a value begins with "f_", a fix ID must follow which has been +If a value begins with "f\_", a fix ID must follow which has been previously defined in the input script. If no bracketed term is appended, the global scalar calculated by the fix is used. If a bracketed term is appended, the Ith element of the global vector @@ -110,7 +110,7 @@ Note that some fixes only produce their values on certain timesteps, which must be compatible with *Nevery*\ , else an error will result. Users can also write code for their own fix styles and :doc:`add them to LAMMPS `. -If a value begins with "v_", a variable name must follow which has +If a value begins with "v\_", a variable name must follow which has been previously defined in the input script. An equal-style or vector-style variable can be referenced; the latter requires a bracketed term to specify the Ith element of the vector calculated by diff --git a/doc/src/pair_resquared.rst b/doc/src/pair_resquared.rst index 34a441b608..5bb4de7cb2 100644 --- a/doc/src/pair_resquared.rst +++ b/doc/src/pair_resquared.rst @@ -141,7 +141,7 @@ interactions are computed by another hybrid pair potential), then you still need to insure the epsilon a,b,c coefficients are assigned to that type in a "pair_coeff I J" command. -For large uniform molecules it has been shown that the epsilon_\*_\* +For large uniform molecules it has been shown that the :math:`\epsilon_{*,*}` energy parameters are approximately representable in terms of local contact curvatures :ref:`(Everaers) `: diff --git a/doc/src/variable.rst b/doc/src/variable.rst index b1d86cd873..0e30efc0ab 100644 --- a/doc/src/variable.rst +++ b/doc/src/variable.rst @@ -485,11 +485,11 @@ references, and references to other variables. +--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Atom vectors | id, mass, type, mol, x, y, z, vx, vy, vz, fx, fy, fz, q | +--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Compute references | c_ID, c_ID[i], c_ID[i][j], C_ID, C_ID[i] | +| Compute references | c_ID, c_ID[i], c_ID[i][j], C_ID, C_ID[i] | +--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Fix references | f_ID, f_ID[i], f_ID[i][j], F_ID, F_ID[i] | +| Fix references | f_ID, f_ID[i], f_ID[i][j], F_ID, F_ID[i] | +--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Other variables | v_name, v_name[i] | +| Other variables | v_name, v_name[i] | +--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ Most of the formula elements produce a scalar value. Some produce a @@ -1038,11 +1038,11 @@ reference means, since computes only produce either global or per-atom quantities, never both. +-------------+-------------------------------------------------------------------------------------------------------+ -| c_ID | global scalar, or per-atom vector | +| c_ID | global scalar, or per-atom vector | +-------------+-------------------------------------------------------------------------------------------------------+ -| c_ID[I] | Ith element of global vector, or atom I's value in per-atom vector, or Ith column from per-atom array | +| c_ID[I] | Ith element of global vector, or atom I's value in per-atom vector, or Ith column from per-atom array | +-------------+-------------------------------------------------------------------------------------------------------+ -| c_ID[I][J] | I,J element of global array, or atom I's Jth value in per-atom array | +| c_ID[I][J] | I,J element of global array, or atom I's Jth value in per-atom array | +-------------+-------------------------------------------------------------------------------------------------------+ For I and J indices, integers can be specified or a variable name, @@ -1092,17 +1092,17 @@ column of an per-atom array. See the doc pages for individual fixes to see what kind of values they produce. The different kinds of fix references are exactly the same as the -compute references listed in the above table, where "c_" is replaced -by "f_". Again, there is typically no ambiguity (see exception below) +compute references listed in the above table, where "c\_" is replaced +by "f\_". Again, there is typically no ambiguity (see exception below) as to what a reference means, since fixes only produce either global or per-atom quantities, never both. +-------------+-------------------------------------------------------------------------------------------------------+ -| f_ID | global scalar, or per-atom vector | +| f_ID | global scalar, or per-atom vector | +-------------+-------------------------------------------------------------------------------------------------------+ -| f_ID[I] | Ith element of global vector, or atom I's value in per-atom vector, or Ith column from per-atom array | +| f_ID[I] | Ith element of global vector, or atom I's value in per-atom vector, or Ith column from per-atom array | +-------------+-------------------------------------------------------------------------------------------------------+ -| f_ID[I][J] | I,J element of global array, or atom I's Jth value in per-atom array | +| f_ID[I][J] | I,J element of global array, or atom I's Jth value in per-atom array | +-------------+-------------------------------------------------------------------------------------------------------+ For I and J indices, integers can be specified or a variable name, @@ -1169,15 +1169,15 @@ There is no ambiguity as to what a reference means, since variables produce only a global scalar or global vector or per-atom vector. +------------+----------------------------------------------------------------------+ -| v_name | global scalar from equal-style variable | +| v_name | global scalar from equal-style variable | +------------+----------------------------------------------------------------------+ -| v_name | global vector from vector-style variable | +| v_name | global vector from vector-style variable | +------------+----------------------------------------------------------------------+ -| v_name | per-atom vector from atom-style or atomfile-style variable | +| v_name | per-atom vector from atom-style or atomfile-style variable | +------------+----------------------------------------------------------------------+ -| v_name[I] | Ith element of a global vector from vector-style variable | +| v_name[I] | Ith element of a global vector from vector-style variable | +------------+----------------------------------------------------------------------+ -| v_name[I] | value of atom with ID = I from atom-style or atomfile-style variable | +| v_name[I] | value of atom with ID = I from atom-style or atomfile-style variable | +------------+----------------------------------------------------------------------+ For the I index, an integer can be specified or a variable name, @@ -1199,7 +1199,7 @@ formula immediately without using the variable command to define a named variable. More generally, there is a difference between referencing a variable -with a leading $ sign (e.g. $x or ${abc}) versus with a leading "v_" +with a leading $ sign (e.g. $x or ${abc}) versus with a leading "v\_" (e.g. v_x or v_abc). The former can be used in any input script command, including a variable command. The input script parser evaluates the reference variable immediately and substitutes its value @@ -1208,7 +1208,7 @@ into the command. As explained on the :doc:`Commands parse ` do this $((xlo+xhi)/2+sqrt(v_area)) in an input script command evaluates the string between the parenthesis as an equal-style variable formula. -Referencing a variable with a leading "v_" is an optional or required +Referencing a variable with a leading "v\_" is an optional or required kind of argument for some commands (e.g. the :doc:`fix ave/chunk ` or :doc:`dump custom ` or :doc:`thermo_style ` commands) if you wish it to evaluate a variable periodically during a run. It can also be used in a -- GitLab From cf21affd386d5db9dc9677b04e9d43a188783237 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Fri, 13 Mar 2020 17:28:18 -0400 Subject: [PATCH 267/689] Add special highlights for commands which use IDs --- doc/utils/sphinx-config/LAMMPSLexer.py | 93 +++++++++++++++++++++++--- 1 file changed, 85 insertions(+), 8 deletions(-) diff --git a/doc/utils/sphinx-config/LAMMPSLexer.py b/doc/utils/sphinx-config/LAMMPSLexer.py index 3ff23439de..72536d494f 100644 --- a/doc/utils/sphinx-config/LAMMPSLexer.py +++ b/doc/utils/sphinx-config/LAMMPSLexer.py @@ -1,31 +1,53 @@ -from pygments.lexer import RegexLexer, words +from pygments.lexer import RegexLexer, words, include, default from pygments.token import * LAMMPS_COMMANDS = ("angle_coeff", "angle_style", "atom_modify", "atom_style", "balance", "bond_coeff", "bond_style", "bond_write", "boundary", "box", -"change_box", "clear", "comm_modify", "comm_style", "compute", +"clear", "comm_modify", "comm_style", "compute_modify", "create_atoms", "create_bonds", "create_box", "delete_atoms", "delete_bonds", "dielectric", "dihedral_coeff", "dihedral_style", "dimension", -"displace_atoms", "dump", "dump_modify", "dynamical_matrix", "echo", "fix", -"fix_modify", "group", "group2ndx", "hyper", "if", "improper_coeff", +"displace_atoms", "dump_modify", "dynamical_matrix", "echo", +"fix_modify", "group2ndx", "hyper", "if", "improper_coeff", "improper_style", "include", "info", "jump", "kim_init", "kim_interactions", "kim_param", "kim_query", "kspace_modify", "kspace_style", "label", "lattice", "log", "mass", "message", "minimize", "min_modify", "min_style", "molecule", "ndx2group", "neb", "neb/spin", "neighbor", "neigh_modify", "newton", "next", "package", "pair_coeff", "pair_modify", "pair_style", "pair_write", "partition", "prd", "print", "processors", "python", "quit", "read_data", -"read_dump", "read_restart", "region", "replicate", "rerun", "reset_ids", +"read_dump", "read_restart", "replicate", "rerun", "reset_ids", "reset_timestep", "restart", "run", "run_style", "server", "set", "shell", "special_bonds", "suffix", "tad", "temper", "temper/grem", "temper/npt", "thermo", "thermo_modify", "thermo_style", "then", "third_order", "timer", "timestep", -"uncompute", "undump", "unfix", "units", "variable", "velocity", "write_coeff", -"write_data", "write_dump", "write_restart") +"units", "velocity", "write_coeff", +"write_data", "write_restart") + +#fix ID group-ID style args +#compute ID group-ID style args +#dump ID group-ID style N file args +#region ID style args keyword arg ... +#variable name style args ... +#group ID style args +#uncompute compute-ID +#undump dump-ID +#unfix fix-ID +#write_dump group-ID style file dump-args modify dump_modify-args class LAMMPSLexer(RegexLexer): name = 'LAMMPS' tokens = { 'root': [ - (words(LAMMPS_COMMANDS, suffix=r'\b', prefix=r'^'), Keyword), + (r'fix\s+', Keyword, 'fix'), + (r'compute\s+', Keyword, 'compute'), + (r'dump\s+', Keyword, 'dump'), + (r'region\s+', Keyword, 'region'), + (r'variable\s+', Keyword, 'variable'), + (r'group\s+', Keyword, 'group'), + (r'change_box\s+', Keyword, 'change_box'), + (r'uncompute\s+', Keyword, 'uncompute'), + (r'unfix\s+', Keyword, 'unfix'), + (r'undump\s+', Keyword, 'undump'), + (r'write_dump\s+', Keyword, 'write_dump'), + include('keywords'), (r'#.*?\n', Comment), ('"', String, 'string'), ('\'', String, 'single_quote_string'), @@ -37,6 +59,10 @@ class LAMMPSLexer(RegexLexer): (r'\s+', Whitespace), (r'[\+\-\*\^\|\/\!%&=<>]', Operator), ], + 'keywords' : [ + (words(LAMMPS_COMMANDS, suffix=r'\b', prefix=r'^'), Keyword) + ] + , 'variable' : [ ('[^\}]+', Name.Variable), ('\}', Name.Variable, '#pop'), @@ -53,5 +79,56 @@ class LAMMPSLexer(RegexLexer): ('[^\(\)]+', Name.Variable), ('\(', Name.Variable, 'expression'), ('\)', Name.Variable, '#pop'), + ], + 'fix' : [ + (r'[\w_\-\.\[\]]+', Name.Variable.Identifier), + (r'\s+', Whitespace, 'group_id'), + default('#pop') + ], + 'compute' : [ + (r'[\w_\-\.\[\]]+', Name.Variable.Identifier), + (r'\s+', Whitespace, 'group_id'), + default('#pop') + ], + 'dump' : [ + (r'[\w_\-\.\[\]]+', Name.Variable.Identifier), + (r'\s+', Whitespace, 'group_id'), + default('#pop') + ], + 'region' : [ + (r'[\w_\-\.\[\]]+', Name.Variable.Identifier), + default('#pop') + ], + 'variable' : [ + (r'[\w_\-\.\[\]]+', Name.Variable.Identifier), + default('#pop') + ], + 'group' : [ + (r'[\w_\-\.\[\]]+', Name.Variable.Identifier), + default('#pop') + ], + 'change_box' : [ + (r'[\w_\-\.\[\]]+', Name.Variable.Identifier), + default('#pop') + ], + 'unfix' : [ + (r'[\w_\-\.\[\]]+', Name.Variable.Identifier), + default('#pop') + ], + 'undump' : [ + (r'[\w_\-\.\[\]]+', Name.Variable.Identifier), + default('#pop') + ], + 'uncompute' : [ + (r'[\w_\-\.\[\]]+', Name.Variable.Identifier), + default('#pop') + ], + 'write_dump' : [ + (r'[\w_\-\.\[\]]+', Name.Variable.Identifier), + default('#pop') + ], + 'group_id' : [ + (r'[\w_\-\.\[\]]+', Name.Variable.Identifier), + default('#pop:2') ] } -- GitLab From 80630881493b1d78d29ac00a9de78e4514ccfda6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 13 Mar 2020 18:07:32 -0400 Subject: [PATCH 268/689] fix a couple of settings --- doc/src/Build_basics.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/src/Build_basics.rst b/doc/src/Build_basics.rst index 892bcebaea..a4eb7cf5b0 100644 --- a/doc/src/Build_basics.rst +++ b/doc/src/Build_basics.rst @@ -41,8 +41,8 @@ is below. # no default value The executable created by CMake (after running make) is named *lmp* unless -the LAMMPS_MACHINE option is set. When setting `LAMMPS_MACHINE=name` -the executable will be named *lmp_name*\. Using `BUILD_MPI=no` will +the LAMMPS_MACHINE option is set. When setting :code:`LAMMPS_MACHINE=name` +the executable will be named *lmp_name*\. Using :code:`BUILD_MPI=no` will enforce building a serial executable using the MPI STUBS library. **Traditional make**\ : -- GitLab From f11e4313003c003a1d46e74eea5b204a47fbf7f3 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 13 Mar 2020 14:37:13 -0400 Subject: [PATCH 269/689] some updates to building with cmake --- doc/src/Build_cmake.rst | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/doc/src/Build_cmake.rst b/doc/src/Build_cmake.rst index ea4880aaa3..4332920ee3 100644 --- a/doc/src/Build_cmake.rst +++ b/doc/src/Build_cmake.rst @@ -13,8 +13,8 @@ good place to start. Building LAMMPS with CMake is a two-step process. First you use CMake to create a build environment in a new directory. On Linux systems, -this will be based on makefiles for use with make. Then you use the -make command to build LAMMPS, which uses the created +this will be by default based on Unix-style makefiles for use with make. +Then you use the *make* command to build LAMMPS, which uses the created Makefile(s). Example: .. code-block:: bash @@ -28,8 +28,8 @@ The cmake command will detect available features, enable selected packages and options, and will generate the build environment. By default this build environment will be created for "Unix Makefiles" on most platforms and particularly on Linux. However, alternate build tools -(e.g. Ninja) and support files for Integrated Development Environments -(IDE) like Eclipse, CodeBlocks, or Kate can be generated, too. This is +(e.g. Ninja) and project files for Integrated Development Environments +(IDEs) like Eclipse, CodeBlocks, or Kate can be generated, too. This is selected via the "-G" command line flag. For the rest of the documentation we will assume that the build environment is generated for makefiles and thus the make command will be used to compile and link LAMMPS as @@ -60,11 +60,12 @@ to ${HOME}/.local ---------- -There are 3 variants of CMake: a command-line version (cmake), a text mode -UI version (ccmake), and a graphical GUI version (cmake-GUI). You can use -any of them interchangeably to configure and create the LAMMPS build -environment. On Linux all the versions produce a Makefile as their -output. See more details on each below. +There are 3 variants of the CMake command itself: a command-line version +(*cmake* or *cmake3*), a text mode UI version (*ccmake* or *ccmake3*), +and a graphical GUI version (*cmake-gui*). You can use any of them +interchangeably to configure and create the LAMMPS build environment. +On Linux all the versions produce a Makefile as their output by default. +See more details on each below. You can specify a variety of options with any of the 3 versions, which affect how the build is performed and what is included in the LAMMPS @@ -106,8 +107,9 @@ folder, recreate the directory and start over. .. code-block:: bash - cmake [options ...] /path/to/lammps/cmake # build from any dir - cmake [options ...] ../cmake # build from lammps/build + cmake [options ...] /path/to/lammps/cmake # build from any dir + cmake [options ...] ../cmake # build from lammps/build + cmake3 [options ...] ../cmake # build from lammps/build The cmake command takes one required argument, which is the LAMMPS cmake directory which contains the CMakeLists.txt file. @@ -119,7 +121,8 @@ command-line options. Several useful ones are: -D CMAKE_INSTALL_PREFIX=path # where to install LAMMPS executable/lib if desired -D CMAKE_BUILD_TYPE=type # type = RelWithDebInfo (default), Release, MinSizeRel, or Debug - -G output # style of output CMake generates + -G output # style of output CMake generates (e.g. "Unix Makefiles" or "Ninja") + -D CMAKE_MAKE_PROGRAM=builder # name of the builder executable (e.g. set to "gmake" instead of "make") -DVARIABLE=value # setting for a LAMMPS feature to enable -D VARIABLE=value # ditto, but cannot come after CMakeLists.txt dir -C path/to/preset/file # load some CMake settings before configuring -- GitLab From e4d6214d3bc69e54fdd06b5eba9e18ef60a2b765 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 13 Mar 2020 18:08:47 -0400 Subject: [PATCH 270/689] reformat source --- doc/src/Build_cmake.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/doc/src/Build_cmake.rst b/doc/src/Build_cmake.rst index 4332920ee3..c41136c0a5 100644 --- a/doc/src/Build_cmake.rst +++ b/doc/src/Build_cmake.rst @@ -83,12 +83,13 @@ this directory or sub-directories within it that CMake creates. .. note:: - To perform a CMake build, no packages can be installed or a - build been previously attempted in the LAMMPS src directory by using - "make" commands to :doc:`perform a conventional LAMMPS build `. CMake detects if this is the case and - generates an error, telling you to type "make no-all purge" in the src - directory to un-install all packages. The purge removes all the \*.h - files auto-generated by make. + To perform a CMake build, no packages can be installed or a build + been previously attempted in the LAMMPS src directory by using "make" + commands to :doc:`perform a conventional LAMMPS build `. + CMake detects if this is the case and generates an error, telling you + to type "make no-all purge" in the src directory to un-install all + packages. The purge removes all the \*.h files auto-generated by + make. You must have CMake version 3.10 or later on your system to build LAMMPS. Installation instructions for CMake are below. -- GitLab From cdec46ba6aa4f01aba3bb2161222d93168043acd Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 13 Mar 2020 18:38:47 -0400 Subject: [PATCH 271/689] Some more code-blocks instead of parsed-literal --- doc/src/Build_link.rst | 2 +- doc/src/Build_make.rst | 2 +- doc/src/Examples.rst | 6 +++--- doc/src/Howto_drude2.rst | 2 +- doc/src/Manual_build.rst | 2 +- doc/src/Python_call.rst | 2 +- doc/src/Python_install.rst | 2 +- doc/src/Python_mpi.rst | 10 +++++----- doc/src/Python_shlib.rst | 8 ++++---- doc/src/Python_test.rst | 16 ++++++++-------- doc/src/Run_windows.rst | 8 ++++---- doc/src/Speed_gpu.rst | 4 ++-- doc/src/Speed_intel.rst | 2 +- doc/src/Speed_omp.rst | 4 ++-- doc/src/Speed_opt.rst | 4 ++-- doc/src/Speed_packages.rst | 2 +- doc/src/Tools.rst | 10 +++++----- 17 files changed, 43 insertions(+), 43 deletions(-) diff --git a/doc/src/Build_link.rst b/doc/src/Build_link.rst index 60f7ee9d9c..64c890d8ec 100644 --- a/doc/src/Build_link.rst +++ b/doc/src/Build_link.rst @@ -11,7 +11,7 @@ The :doc:`Build basics ` doc page explains how to build LAMMPS as either a shared or static library. This results in one of these 2 files: -.. parsed-literal:: +.. code-block:: bash liblammps.so # shared library liblammps.a # static library diff --git a/doc/src/Build_make.rst b/doc/src/Build_make.rst index 73e6964608..0379a8379a 100644 --- a/doc/src/Build_make.rst +++ b/doc/src/Build_make.rst @@ -73,7 +73,7 @@ in the LAMMPS distribution. Typing "make machine" uses use Makefile.serial and Makefile.mpi, respectively. Other makefiles are in these directories: -.. parsed-literal:: +.. code-block:: bash OPTIONS # Makefiles which enable specific options MACHINES # Makefiles for specific machines diff --git a/doc/src/Examples.rst b/doc/src/Examples.rst index 21ab13e2d4..b94db208d9 100644 --- a/doc/src/Examples.rst +++ b/doc/src/Examples.rst @@ -155,7 +155,7 @@ Lowercase directories Here is how you can run and visualize one of the sample problems: -.. parsed-literal:: +.. code-block:: bash cd indent cp ../../src/lmp_linux . # copy LAMMPS executable to this dir @@ -177,9 +177,9 @@ like ImageMagick or QuickTime or various Windows-based tools. See the Imagemagick command would create a GIF file suitable for viewing in a browser. -.. parsed-literal:: +.. code-block:: bash - % convert -loop 1 \*.jpg foo.gif + % convert -loop 1 *.jpg foo.gif ---------- diff --git a/doc/src/Howto_drude2.rst b/doc/src/Howto_drude2.rst index 7a8a8b4c2c..cbdbc2d250 100644 --- a/doc/src/Howto_drude2.rst +++ b/doc/src/Howto_drude2.rst @@ -83,7 +83,7 @@ You can use the *polarizer* tool (Python script distributed with the USER-DRUDE package) to convert a non-polarizable data file (here *data.102494.lmp*\ ) to a polarizable data file (\ *data-p.lmp*\ ) -.. parsed-literal:: +.. code-block:: bash polarizer -q -f phenol.dff data.102494.lmp data-p.lmp diff --git a/doc/src/Manual_build.rst b/doc/src/Manual_build.rst index f87ce8bec2..5d5b749678 100644 --- a/doc/src/Manual_build.rst +++ b/doc/src/Manual_build.rst @@ -5,7 +5,7 @@ Depending on how you obtained LAMMPS, the doc directory has up to 6 sub-directories, 2 Nroff files, and optionally 2 PDF files plus 2 e-book format files: -.. parsed-literal:: +.. code-block:: bash src # content files for LAMMPS documentation html # HTML version of the LAMMPS manual (see html/Manual.html) diff --git a/doc/src/Python_call.rst b/doc/src/Python_call.rst index 33f73933df..e0bcf70b9a 100644 --- a/doc/src/Python_call.rst +++ b/doc/src/Python_call.rst @@ -59,7 +59,7 @@ new potential. To use any of these commands, you only need to build LAMMPS with the PYTHON package installed: -.. parsed-literal:: +.. code-block:: bash make yes-python make machine diff --git a/doc/src/Python_install.rst b/doc/src/Python_install.rst index aaeece7752..8b2fe9c367 100644 --- a/doc/src/Python_install.rst +++ b/doc/src/Python_install.rst @@ -31,7 +31,7 @@ If you set the paths to these files as environment variables, you only have to do it once. For the csh or tcsh shells, add something like this to your ~/.cshrc file, one line for each of the two files: -.. parsed-literal:: +.. code-block:: csh setenv PYTHONPATH ${PYTHONPATH}:/home/sjplimp/lammps/python setenv LD_LIBRARY_PATH ${LD_LIBRARY_PATH}:/home/sjplimp/lammps/src diff --git a/doc/src/Python_mpi.rst b/doc/src/Python_mpi.rst index e702172fe9..02a62c89d0 100644 --- a/doc/src/Python_mpi.rst +++ b/doc/src/Python_mpi.rst @@ -18,7 +18,7 @@ LAMMPS instances on subsets of the total MPI ranks. To install mpi4py (version mpi4py-3.0.3 as of Nov 2019), unpack it and from its main directory, type -.. parsed-literal:: +.. code-block:: bash python setup.py build sudo python setup.py install @@ -27,27 +27,27 @@ Again, the "sudo" is only needed if required to copy mpi4py files into your Python distribution's site-packages directory. To install with user privilege into the user local directory type -.. parsed-literal:: +.. code-block:: bash python setup.py install --user If you have successfully installed mpi4py, you should be able to run Python and type -.. parsed-literal:: +.. code-block:: python from mpi4py import MPI without error. You should also be able to run python in parallel on a simple test script -.. parsed-literal:: +.. code-block:: bash % mpirun -np 4 python test.py where test.py contains the lines -.. parsed-literal:: +.. code-block:: python from mpi4py import MPI comm = MPI.COMM_WORLD diff --git a/doc/src/Python_shlib.rst b/doc/src/Python_shlib.rst index aa11d84432..bd1d559359 100644 --- a/doc/src/Python_shlib.rst +++ b/doc/src/Python_shlib.rst @@ -12,7 +12,7 @@ wrap LAMMPS. On Linux this is a library file that ends in ".so", not From the src directory, type -.. parsed-literal:: +.. code-block:: bash make foo mode=shlib @@ -37,7 +37,7 @@ Build LAMMPS as a shared library using CMake When using CMake the following two options are necessary to generate the LAMMPS shared library: -.. parsed-literal:: +.. code-block:: bash -D BUILD_LIB=on # enable building LAMMPS as a library -D BUILD_SHARED_LIBS=on # enable building of LAMMPS shared library (both options are needed!) @@ -50,7 +50,7 @@ library path (e.g. /usr/lib64/) or in the LD_LIBRARY_PATH. If you want to use the shared library with Python the recommended way is to create a virtualenv and use it as CMAKE_INSTALL_PREFIX. -.. parsed-literal:: +.. code-block:: bash # create virtualenv virtualenv --python=$(which python3) myenv3 @@ -69,7 +69,7 @@ This will also install the Python module into your virtualenv. Since virtualenv doesn't change your LD_LIBRARY_PATH, you still need to add its lib64 folder to it, which contains the installed liblammps.so. -.. parsed-literal:: +.. code-block:: bash export LD_LIBRARY_PATH=$VIRTUAL_ENV/lib64:$LD_LIBRARY_PATH diff --git a/doc/src/Python_test.rst b/doc/src/Python_test.rst index 89a4c32504..55a1c0a2d3 100644 --- a/doc/src/Python_test.rst +++ b/doc/src/Python_test.rst @@ -49,7 +49,7 @@ interactively from the bench directory: Or put the same lines in the file test.py and run it as -.. parsed-literal:: +.. code-block:: bash % python test.py @@ -68,7 +68,7 @@ To run LAMMPS in parallel, assuming you have installed the `PyPar `_ package as discussed above, create a test.py file containing these lines: -.. parsed-literal:: +.. code-block:: python import pypar from lammps import lammps @@ -81,7 +81,7 @@ To run LAMMPS in parallel, assuming you have installed the `mpi4py `_ package as discussed above, create a test.py file containing these lines: -.. parsed-literal:: +.. code-block:: python from mpi4py import MPI from lammps import lammps @@ -94,13 +94,13 @@ above, create a test.py file containing these lines: You can either script in parallel as: -.. parsed-literal:: +.. code-block:: bash % mpirun -np 4 python test.py and you should see the same output as if you had typed -.. parsed-literal:: +.. code-block:: bash % mpirun -np 4 lmp_g++ -in in.lj @@ -124,7 +124,7 @@ Running Python scripts: Note that any Python script (not just for LAMMPS) can be invoked in one of several ways: -.. parsed-literal:: +.. code-block:: bash % python foo.script % python -i foo.script @@ -133,7 +133,7 @@ one of several ways: The last command requires that the first line of the script be something like this: -.. parsed-literal:: +.. code-block:: bash #!/usr/local/bin/python #!/usr/local/bin/python -i @@ -141,7 +141,7 @@ something like this: where the path points to where you have Python installed, and that you have made the script file executable: -.. parsed-literal:: +.. code-block:: bash % chmod +x foo.script diff --git a/doc/src/Run_windows.rst b/doc/src/Run_windows.rst index 4a60af331a..0343e123b9 100644 --- a/doc/src/Run_windows.rst +++ b/doc/src/Run_windows.rst @@ -14,7 +14,7 @@ Note that the serial executable includes support for multi-threading parallelization from the styles in the USER-OMP packages. To run with 4 threads, you can type this: -.. parsed-literal:: +.. code-block:: bash lmp_serial -in in.lj -pk omp 4 -sf omp @@ -43,7 +43,7 @@ into the MPICH2 installation directory, then into the sub-directory Then type something like this: -.. parsed-literal:: +.. code-block:: bash mpiexec -localonly 4 lmp_mpi -in in.file mpiexec -np 4 lmp_mpi -in in.file @@ -58,13 +58,13 @@ patient before the output shows up. The parallel executable can also run on a single processor by typing something like this: -.. parsed-literal:: +.. code-block:: bash lmp_mpi -in in.lj Note that the parallel executable also includes OpenMP multi-threading, which can be combined with MPI using something like: -.. parsed-literal:: +.. code-block:: bash mpiexec -localonly 2 lmp_mpi -in in.lj -pk omp 2 -sf omp diff --git a/doc/src/Speed_gpu.rst b/doc/src/Speed_gpu.rst index fd0556f67b..9981b22b03 100644 --- a/doc/src/Speed_gpu.rst +++ b/doc/src/Speed_gpu.rst @@ -76,7 +76,7 @@ automatically append "gpu" to styles that support it. Use the "-pk gpu Ng" :doc:`command-line switch ` to set Ng = # of GPUs/node to use. -.. parsed-literal:: +.. code-block:: bash lmp_machine -sf gpu -pk gpu 1 -in in.script # 1 MPI task uses 1 GPU mpirun -np 12 lmp_machine -sf gpu -pk gpu 2 -in in.script # 12 MPI tasks share 2 GPUs on a single 16-core (or whatever) node @@ -106,7 +106,7 @@ and use of multiple MPI tasks/GPU is the same. Use the :doc:`suffix gpu ` command, or you can explicitly add an "gpu" suffix to individual styles in your input script, e.g. -.. parsed-literal:: +.. code-block:: LAMMPS pair_style lj/cut/gpu 2.5 diff --git a/doc/src/Speed_intel.rst b/doc/src/Speed_intel.rst index a203b4789d..4658fb9584 100644 --- a/doc/src/Speed_intel.rst +++ b/doc/src/Speed_intel.rst @@ -205,7 +205,7 @@ For building with make, several example Makefiles for building with the Intel compiler are included with LAMMPS in the src/MAKE/OPTIONS/ directory: -.. parsed-literal:: +.. code-block:: bash Makefile.intel_cpu_intelmpi # Intel Compiler, Intel MPI, No Offload Makefile.knl # Intel Compiler, Intel MPI, No Offload diff --git a/doc/src/Speed_omp.rst b/doc/src/Speed_omp.rst index 5e034e51ec..04e4366758 100644 --- a/doc/src/Speed_omp.rst +++ b/doc/src/Speed_omp.rst @@ -23,7 +23,7 @@ instructions. These examples assume one or more 16-core nodes. -.. parsed-literal:: +.. code-block:: bash env OMP_NUM_THREADS=16 lmp_omp -sf omp -in in.script # 1 MPI task, 16 threads according to OMP_NUM_THREADS lmp_mpi -sf omp -in in.script # 1 MPI task, no threads, optimized kernels @@ -60,7 +60,7 @@ and threads/MPI task is the same. Use the :doc:`suffix omp ` command, or you can explicitly add an "omp" suffix to individual styles in your input script, e.g. -.. parsed-literal:: +.. code-block:: LAMMPS pair_style lj/cut/omp 2.5 diff --git a/doc/src/Speed_opt.rst b/doc/src/Speed_opt.rst index f1c7868644..297177f8d4 100644 --- a/doc/src/Speed_opt.rst +++ b/doc/src/Speed_opt.rst @@ -17,7 +17,7 @@ See the :ref:`Build extras ` doc page for instructions. **Run with the OPT package from the command line:** -.. parsed-literal:: +.. code-block:: bash lmp_mpi -sf opt -in in.script # run in serial mpirun -np 4 lmp_mpi -sf opt -in in.script # run in parallel @@ -30,7 +30,7 @@ automatically append "opt" to styles that support it. Use the :doc:`suffix opt ` command, or you can explicitly add an "opt" suffix to individual styles in your input script, e.g. -.. parsed-literal:: +.. code-block:: LAMMPS pair_style lj/cut/opt 2.5 diff --git a/doc/src/Speed_packages.rst b/doc/src/Speed_packages.rst index 97eb7a64c2..ab02ba7f48 100644 --- a/doc/src/Speed_packages.rst +++ b/doc/src/Speed_packages.rst @@ -132,7 +132,7 @@ packages. As an example, here is a command that builds with all the GPU related packages installed (GPU, KOKKOS with Cuda), including settings to build the needed auxiliary GPU libraries for Kepler GPUs: -.. parsed-literal:: +.. code-block:: bash Make.py -j 16 -p omp gpu kokkos -cc nvcc wrap=mpi -gpu mode=double arch=35 -kokkos cuda arch=35 lib-all file mpi diff --git a/doc/src/Tools.rst b/doc/src/Tools.rst index 10b1e5033c..6137b1aa6f 100644 --- a/doc/src/Tools.rst +++ b/doc/src/Tools.rst @@ -99,7 +99,7 @@ binary2txt tool The file binary2txt.cpp converts one or more binary LAMMPS dump file into ASCII text files. The syntax for running the tool is -.. parsed-literal:: +.. code-block:: bash binary2txt file1 file2 ... @@ -149,7 +149,7 @@ chains and solvent atoms can strongly overlap, so LAMMPS needs to run the system initially with a "soft" pair potential to un-overlap it. The syntax for running the tool is -.. parsed-literal:: +.. code-block:: bash chain < def.chain > data.file @@ -178,11 +178,11 @@ Version 20110511 .. parsed-literal:: - Syntax: ./abf_integrate < filename > [-n < nsteps >] [-t < temp >] [-m [0\|1] (metadynamics)] [-h < hill_height >] [-f < variable_hill_factor >] + ./abf_integrate < filename > [-n < nsteps >] [-t < temp >] [-m [0\|1] (metadynamics)] [-h < hill_height >] [-f < variable_hill_factor >] The LAMMPS interface to the colvars collective variable library, as well as these tools, were created by Axel Kohlmeyer (akohlmey at -gmail.com) at ICTP, Italy. +gmail.com) while at ICTP, Italy. ---------- @@ -427,7 +427,7 @@ atoms can strongly overlap, so LAMMPS needs to run the system initially with a "soft" pair potential to un-overlap it. The syntax for running the tool is -.. parsed-literal:: +.. code-block:: bash micelle2d < def.micelle2d > data.file -- GitLab From 6d9064f98fcd82003ca3545a6f8946dab74a518f Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 13 Mar 2020 18:41:37 -0400 Subject: [PATCH 272/689] Revert "fix bug in pair styles lubricate and lubricate/poly" This reverts commit e368ae9f227d375ff5e186b840234dca2acd0566. As it contradicts the comments in the code above the segment. --- src/COLLOID/pair_lubricate.cpp | 2 +- src/COLLOID/pair_lubricate_poly.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/COLLOID/pair_lubricate.cpp b/src/COLLOID/pair_lubricate.cpp index 1795edf874..a72eaef679 100644 --- a/src/COLLOID/pair_lubricate.cpp +++ b/src/COLLOID/pair_lubricate.cpp @@ -142,7 +142,7 @@ void PairLubricate::compute(int eflag, int vflag) Ef[2][2] = h_rate[2]/domain->zprd; Ef[0][1] = Ef[1][0] = 0.5 * h_rate[5]/domain->yprd; Ef[0][2] = Ef[2][0] = 0.5 * h_rate[4]/domain->zprd; - Ef[1][2] = Ef[2][1] = 0.5 * h_rate[3]/domain->xprd; + Ef[1][2] = Ef[2][1] = 0.5 * h_rate[3]/domain->zprd; // copy updated velocity/omega/angmom to the ghost particles // no need to do this if not shearing since comm->ghost_velocity is set diff --git a/src/COLLOID/pair_lubricate_poly.cpp b/src/COLLOID/pair_lubricate_poly.cpp index 3be7c2e34e..e347441cf4 100644 --- a/src/COLLOID/pair_lubricate_poly.cpp +++ b/src/COLLOID/pair_lubricate_poly.cpp @@ -124,7 +124,7 @@ void PairLubricatePoly::compute(int eflag, int vflag) Ef[2][2] = h_rate[2]/domain->zprd; Ef[0][1] = Ef[1][0] = 0.5 * h_rate[5]/domain->yprd; Ef[0][2] = Ef[2][0] = 0.5 * h_rate[4]/domain->zprd; - Ef[1][2] = Ef[2][1] = 0.5 * h_rate[3]/domain->xprd; + Ef[1][2] = Ef[2][1] = 0.5 * h_rate[3]/domain->zprd; // copy updated omega to the ghost particles // no need to do this if not shearing since comm->ghost_velocity is set -- GitLab From 68051137804236586ab5d8699995eb65e0b8f300 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 13 Mar 2020 19:41:33 -0400 Subject: [PATCH 273/689] some more typesetting improvements --- doc/src/Build_basics.rst | 101 ++++++++++++------------ doc/src/Build_extras.rst | 149 ++++++++++++++++++------------------ doc/src/Build_package.rst | 20 ++--- doc/src/Build_settings.rst | 37 +++++---- doc/src/Install_git.rst | 2 +- doc/src/Install_tarball.rst | 4 +- doc/src/Install_windows.rst | 4 +- 7 files changed, 161 insertions(+), 156 deletions(-) diff --git a/doc/src/Build_basics.rst b/doc/src/Build_basics.rst index a4eb7cf5b0..51c3fd871d 100644 --- a/doc/src/Build_basics.rst +++ b/doc/src/Build_basics.rst @@ -40,14 +40,14 @@ is below. -D LAMMPS_MACHINE=name # name = mpi, serial, mybox, titan, laptop, etc # no default value -The executable created by CMake (after running make) is named *lmp* unless -the LAMMPS_MACHINE option is set. When setting :code:`LAMMPS_MACHINE=name` -the executable will be named *lmp_name*\. Using :code:`BUILD_MPI=no` will +The executable created by CMake (after running make) is named ``lmp`` unless +the LAMMPS_MACHINE option is set. When setting ``LAMMPS_MACHINE=name`` +the executable will be called ``lmp_name``. Using ``BUILD_MPI=no`` will enforce building a serial executable using the MPI STUBS library. **Traditional make**\ : -The build with traditional makefiles has to be done inside the source folder `src`. +The build with traditional makefiles has to be done inside the source folder ``src``. .. code-block:: bash @@ -57,16 +57,16 @@ The build with traditional makefiles has to be done inside the source folder `sr Any "make machine" command will look up the make settings from a file Makefile.machine, create a folder Obj_machine with all objects and -generated files and an executable called *lmp_machine*\ . The standard -parallel build with `make mpi` assumes a standard MPI installation with +generated files and an executable called ``lmp_machine``\ . The standard +parallel build with ``make mpi`` assumes a standard MPI installation with MPI compiler wrappers where all necessary compiler and linker flags to get access and link with the suitable MPI headers and libraries are set by the wrapper programs. For other cases or the serial build, you have -to adjust the make file variables MPI_INC, MPI_PATH, MPI_LIB as well -as CC and LINK. To enable OpenMP threading usually a compiler specific -flag needs to be added to the compile and link commands. For the GNU -compilers, this is *-fopenmp*\ , which can be added to the CC and LINK -makefile variables. +to adjust the make file variables ``MPI_INC``, ``MPI_PATH``, ``MPI_LIB`` +as well as ``CC`` and ``LINK``\ . To enable OpenMP threading usually +a compiler specific flag needs to be added to the compile and link +commands. For the GNU compilers, this is ``-fopenmp``\ , which can be +added to the ``CC`` and ``LINK`` makefile variables. For the serial build the following make variables are set (see src/MAKE/Makefile.serial): @@ -79,8 +79,8 @@ For the serial build the following make variables are set (see src/MAKE/Makefile MPI_LIB = -lmpi_stubs You also need to build the STUBS library for your platform before making -LAMMPS itself. A "make serial" build does this for you automatically, -otherwise, type "make mpi-stubs" from the src directory, or "make" from +LAMMPS itself. A ``make serial`` build does this for you automatically, +otherwise, type ``make mpi-stubs`` from the src directory, or ``make`` from the src/STUBS dir. If the build fails, you will need to edit the STUBS/Makefile for your platform. The stubs library does not provide MPI/IO functions required by some LAMMPS packages, e.g. MPIIO or USER-LB, @@ -88,7 +88,7 @@ and thus is not compatible with those packages. .. note:: - The file STUBS/mpi.c provides a CPU timer function called + The file ``src/STUBS/mpi.c`` provides a CPU timer function called MPI_Wtime() that calls gettimeofday() . If your operating system does not support gettimeofday() , you will need to insert code to call another timer. Note that the ANSI-standard function clock() @@ -126,28 +126,28 @@ to: e.g. LATTE and USER-COLVARS. See the :doc:`Packages details ` doc page for more info on these packages and the doc pages for their respective commands for OpenMP threading info. -For CMake, if you use BUILD_OMP=yes, you can use these packages and -turn on their native OpenMP support and turn on their native OpenMP -support at run time, by setting the OMP_NUM_THREADS environment +For CMake, if you use ``BUILD_OMP=yes``, you can use these packages +and turn on their native OpenMP support and turn on their native OpenMP +support at run time, by setting the ``OMP_NUM_THREADS`` environment variable before you launch LAMMPS. -For building via conventional make, the CCFLAGS and LINKFLAGS +For building via conventional make, the ``CCFLAGS`` and ``LINKFLAGS`` variables in Makefile.machine need to include the compiler flag that -enables OpenMP. For GNU compilers it is -fopenmp. For (recent) Intel -compilers it is -qopenmp. If you are using a different compiler, +enables OpenMP. For GNU compilers it is ``-fopenmp``\ . For (recent) Intel +compilers it is ``-qopenmp``\ . If you are using a different compiler, please refer to its documentation. .. _default-none-issues: **OpenMP Compiler compatibility info**\ : -Some compilers do not fully support the 'default(none)' directive +Some compilers do not fully support the ``default(none)`` directive and others (e.g. GCC version 9 and beyond) may implement OpenMP 4.0 -semantics, which are incompatible with the OpenMP 3.1 directives used +semantics, which are incompatible with the OpenMP 3.1 semantics used in LAMMPS (for maximal compatibility with compiler versions in use). -In those case, all 'default(none)' directives (which aid in detecting -incorrect and unwanted sharing) can be replaced with 'default(shared)' -while dropping all 'shared()' directives. The script +In those case, all ``default(none)`` directives (which aid in detecting +incorrect and unwanted sharing) can be replaced with ``default(shared)`` +while dropping all ``shared()`` directives. The script 'src/USER-OMP/hack_openmp_for_pgi_gcc9.sh' can be used to automate this conversion. @@ -183,11 +183,11 @@ optimization flags appropriate to that compiler and any build. You can tell CMake to look for a specific compiler with these variable -settings. Likewise you can specify the FLAGS variables if you want to -experiment with alternate optimization flags. You should specify all -3 compilers, so that the small number of LAMMPS source files written -in C or Fortran are built with a compiler consistent with the one used -for all the C++ files: +settings. Likewise you can specify the corresponding ``CMAKE_*_FLAGS`` +variables if you want to experiment with alternate optimization flags. +You should specify all 3 compilers, so that the small number of LAMMPS +source files written in C or Fortran are built with a compiler consistent +with the one used for all the C++ files: .. code-block:: bash @@ -300,19 +300,18 @@ are set, defaults are applied. -D LAMMPS_LIB_SUFFIX=name # name = mpi, serial, mybox, titan, laptop, etc # no default value -Setting BUILD_EXE=no will not produce an executable. Setting -BUILD_LIB=yes will produce a static library named *liblammps.a*\ . -Setting both BUILD_LIB=yes and BUILD_SHARED_LIBS=yes will produce a -shared library named *liblammps.so* instead. If LAMMPS_LIB_SUFFIX is -set to *name* in addition, the name of the generated libraries will be -changed to either *liblammps_name.a* or *liblammps_name.so*\ , -respectively. +Setting ``BUILD_EXE=no`` will not produce an executable. Setting +``BUILD_LIB=yes`` will produce a static library named ``liblammps.a``\ . +Setting both ``BUILD_LIB=yes`` and ``BUILD_SHARED_LIBS=yes`` will produce a +shared library named ``liblammps.so`` instead. If ``LAMMPS_LIB_SUFFIX=name`` +is set in addition, the name of the generated libraries will be changed to +either ``liblammps_name.a`` or ``liblammps_name.so``\ , respectively. **Traditional make**\ : With the traditional makefile based build process, the choice of the generated executable or library depends on the "mode" setting. -Several options are available and "mode=exe" is the default. +Several options are available and ``mode=exe`` is the default. .. code-block:: bash @@ -322,11 +321,11 @@ Several options are available and "mode=exe" is the default. make mode=shlib machine # build LAMMPS shared lib liblammps_machine.so make mode=shexe machine # same as "mode=exe" but uses objects from "mode=shlib" -The two "exe" builds will generate and executable *lmp_machine*\ , -while the two library builds will create a file *liblammps_machine.a* -or *liblammps_machine.so*\ . They will also create generic soft links, -named *liblammps.a* and *liblammps.so*\ , which point to the specific -*liblammps_machine.a/so* files. +The two "exe" builds will generate and executable ``lmp_machine``\ , +while the two library builds will create a file ``liblammps_machine.a`` +or ``liblammps_machine.so``\ . They will also create generic soft links, +named ``liblammps.a`` and ``liblammps.so``\ , which point to the specific +``liblammps_machine.a/so`` files. **CMake and make info**\ : @@ -335,7 +334,7 @@ the auxiliary libraries it depends on must also exist as shared libraries. This will be the case for libraries included with LAMMPS, such as the dummy MPI library in src/STUBS or any package libraries in the lib/packages directory, since they are always built in a shared -library compatible way using the -fPIC switch. However, if a library +library compatible way using the ``-fPIC`` switch. However, if a library like MPI or FFTW does not exist as a shared library, the shared library build may generate an error. This means you will need to install a shared library version of the auxiliary library. The build instructions @@ -353,10 +352,10 @@ in the default /usr/local/lib location: make make install -You may need to use "sudo make install" in place of the last line if you -do not have write privileges for /usr/local/lib. The end result should -be the file /usr/local/lib/libmpich.so. On many Linux installations the -folder "${HOME}/.local" is an alternative to using /usr/local and does +You may need to use ``sudo make install`` in place of the last line if you +do not have write privileges for ``/usr/local/lib``. The end result should +be the file ``/usr/local/lib/libmpich.so``. On many Linux installations the +folder ``${HOME}/.local`` is an alternative to using ``/usr/local`` and does not require superuser or sudo access. In that case the configuration step becomes: @@ -420,7 +419,7 @@ It is also possible to create the HTML version of the manual within the :doc:`CMake build directory `. The reason for this option is to include the installation of the HTML manual pages into the "install" step when installing LAMMPS after the CMake build via -"make install". +``make install``. .. code-block:: bash @@ -479,6 +478,6 @@ you want to copy files to is protected. **Traditional make**\ : -There is no "install" option in the src/Makefile for LAMMPS. If you -wish to do this you will need to first build LAMMPS, then manually +There is no "install" option in the ``src/Makefile`` for LAMMPS. If +you wish to do this you will need to first build LAMMPS, then manually copy the desired LAMMPS files to the appropriate system directories. diff --git a/doc/src/Build_extras.rst b/doc/src/Build_extras.rst index 1e7275b366..4589015e35 100644 --- a/doc/src/Build_extras.rst +++ b/doc/src/Build_extras.rst @@ -128,16 +128,16 @@ for the JIT compiler of the CUDA driver to translate it. **Traditional make**\ : -Before building LAMMPS, you must build the GPU library in lib/gpu. +Before building LAMMPS, you must build the GPU library in ``lib/gpu``\ . You can do this manually if you prefer; follow the instructions in -lib/gpu/README. Note that the GPU library uses MPI calls, so you must +``lib/gpu/README``. Note that the GPU library uses MPI calls, so you must use the same MPI library (or the STUBS library) settings as the main -LAMMPS code. This also applies to the -DLAMMPS_BIGBIG, --DLAMMPS_SMALLBIG, or -DLAMMPS_SMALLSMALL settings in whichever +LAMMPS code. This also applies to the ``-DLAMMPS_BIGBIG``\ , +``-DLAMMPS_SMALLBIG``\ , or ``-DLAMMPS_SMALLSMALL`` settings in whichever Makefile you use. -You can also build the library in one step from the lammps/src dir, -using a command like these, which simply invoke the lib/gpu/Install.py +You can also build the library in one step from the ``lammps/src`` dir, +using a command like these, which simply invoke the ``lib/gpu/Install.py`` script with the specified args: .. code-block:: bash @@ -156,10 +156,10 @@ Makefile.machine you start from via the corresponding -c, -a, -p, -e switches (as in the examples above), and also save a copy of the new Makefile if desired: -* CUDA_HOME = where NVIDIA CUDA software is installed on your system -* CUDA_ARCH = sm_XX, what GPU hardware you have, same as CMake GPU_ARCH above -* CUDA_PRECISION = precision (double, mixed, single) -* EXTRAMAKE = which Makefile.lammps.\* file to copy to Makefile.lammps +* ``CUDA_HOME`` = where NVIDIA CUDA software is installed on your system +* ``CUDA_ARCH`` = sm_XX, what GPU hardware you have, same as CMake GPU_ARCH above +* ``CUDA_PRECISION`` = precision (double, mixed, single) +* ``EXTRAMAKE`` = which Makefile.lammps.\* file to copy to Makefile.lammps The file Makefile.linux_multi is set up to include support for multiple GPU architectures as supported by the CUDA toolkit in use. This is done @@ -167,11 +167,11 @@ through using the "--gencode " flag, which can be used multiple times and thus support all GPU architectures supported by your CUDA compiler. If the library build is successful, 3 files should be created: -lib/gpu/libgpu.a, lib/gpu/nvc_get_devices, and -lib/gpu/Makefile.lammps. The latter has settings that enable LAMMPS -to link with CUDA libraries. If the settings in Makefile.lammps for +``lib/gpu/libgpu.a``\ , ``lib/gpu/nvc_get_devices``\ , and +``lib/gpu/Makefile.lammps``\ . The latter has settings that enable LAMMPS +to link with CUDA libraries. If the settings in ``Makefile.lammps`` for your machine are not correct, the LAMMPS build will fail, and -lib/gpu/Makefile.lammps may need to be edited. +``lib/gpu/Makefile.lammps`` may need to be edited. .. note:: @@ -211,35 +211,36 @@ minutes to hours) to build. Of course you only need to do that once.) -D LMP_DEBUG_CURL=value # set libcurl verbose mode on/off, value = off (default) or on -D LMP_NO_SSL_CHECK=value # tell libcurl to not verify the peer, value = no (default) or yes -If DOWNLOAD_KIM is set, the KIM library will be downloaded and built +If ``DOWNLOAD_KIM`` is set, the KIM library will be downloaded and built inside the CMake build directory. If the KIM library is already on -your system (in a location CMake cannot find it), set the PKG_CONFIG_PATH +your system (in a location CMake cannot find it), set the ``PKG_CONFIG_PATH`` environment variable so that libkim-api can be found. *For using OpenKIM web queries in LAMMPS*\ : -If LMP_DEBUG_CURL is set, the libcurl verbose mode will be on, and any -libcurl calls within the KIM web query display a lot of information about -libcurl operations. You hardly ever want this set in production use, you will -almost always want this when you debug/report problems. +If the ``LMP_DEBUG_CURL`` environment variable is set, the libcurl verbose +mode will be on, and any libcurl calls within the KIM web query display a +lot of information about libcurl operations. You hardly ever want this +set in production use, you will almost always want this when you debug or +report problems. The libcurl performs peer SSL certificate verification by default. This verification is done using a CA certificate store that the SSL library can use to make sure the peer's server certificate is valid. If SSL reports an error ("certificate verify failed") during the handshake and thus refuses -further communication with that server, you can set LMP_NO_SSL_CHECK. -If LMP_NO_SSL_CHECK is set, libcurl does not verify the peer and connection +further communication with that server, you can set ``LMP_NO_SSL_CHECK``\ . +If ``LMP_NO_SSL_CHECK`` is set, libcurl does not verify the peer and connection succeeds regardless of the names in the certificate. This option is insecure. As an alternative, you can specify your own CA cert path by setting the -environment variable CURL_CA_BUNDLE to the path of your choice. A call to the -KIM web query would get this value from the environmental variable. +environment variable ``CURL_CA_BUNDLE`` to the path of your choice. A call +to the KIM web query would get this value from the environmental variable. **Traditional make**\ : You can download and build the KIM library manually if you prefer; -follow the instructions in lib/kim/README. You can also do it in one +follow the instructions in ``lib/kim/README``\ . You can also do it in one step from the lammps/src dir, using a command like these, which simply -invoke the lib/kim/Install.py script with the specified args. +invoke the ``lib/kim/Install.py`` script with the specified args. .. code-block:: bash @@ -252,7 +253,7 @@ invoke the lib/kim/Install.py script with the specified args. $ make lib-kim args="-p /usr/local -a EAM_Dynamo_Ackland_W__MO_141627196590_002" # ditto but add one model or driver Settings for OpenKIM web queries discussed above need to be applied by adding -them to the LMP_INC variable through editing the Makefile.machine you are +them to the ``LMP_INC`` variable through editing the Makefile.machine you are using. For example: .. code-block:: make @@ -271,7 +272,7 @@ build for, either CPUs (multi-threading via OpenMP) or KNLs (OpenMP) or GPUs (NVIDIA Cuda). For a CMake or make build, these are the possible choices for the -KOKKOS_ARCH settings described below. Note that for CMake, these are +``KOKKOS_ARCH`` settings described below. Note that for CMake, these are really Kokkos variables, not LAMMPS variables. Hence you must use case-sensitive values, e.g. BDW, not bdw. @@ -334,7 +335,7 @@ For NVIDIA GPUs using CUDA, set these 4 variables: -D CMAKE_CXX_COMPILER=wrapper # wrapper = full path to Cuda nvcc wrapper The wrapper value is the Cuda nvcc compiler wrapper provided in the -Kokkos library: lib/kokkos/bin/nvcc_wrapper. The setting should +Kokkos library: ``lib/kokkos/bin/nvcc_wrapper``\ . The setting should include the full path name to the wrapper, e.g. .. code-block:: bash @@ -343,9 +344,9 @@ include the full path name to the wrapper, e.g. **Traditional make**\ : -Choose which hardware to support in Makefile.machine via -KOKKOS_DEVICES and KOKKOS_ARCH settings. See the -src/MAKE/OPTIONS/Makefile.kokkos\* files for examples. +Choose which hardware to support in ``Makefile.machine`` via +``KOKKOS_DEVICES`` and ``KOKKOS_ARCH`` settings. See the +``src/MAKE/OPTIONS/Makefile.kokkos\*`` files for examples. For multicore CPUs using OpenMP: @@ -400,18 +401,18 @@ library. -D DOWNLOAD_LATTE=value # download LATTE for build, value = no (default) or yes -D LATTE_LIBRARY=path # LATTE library file (only needed if a custom location) -If DOWNLOAD_LATTE is set, the LATTE library will be downloaded and +If ``DOWNLOAD_LATTE`` is set, the LATTE library will be downloaded and built inside the CMake build directory. If the LATTE library is already on your system (in a location CMake cannot find it), -LATTE_LIBRARY is the filename (plus path) of the LATTE library file, +``LATTE_LIBRARY`` is the filename (plus path) of the LATTE library file, not the directory the library file is in. **Traditional make**\ : You can download and build the LATTE library manually if you prefer; -follow the instructions in lib/latte/README. You can also do it in -one step from the lammps/src dir, using a command like these, which -simply invokes the lib/latte/Install.py script with the specified +follow the instructions in ``lib/latte/README``\ . You can also do it in +one step from the ``lammps/src`` dir, using a command like these, which +simply invokes the ``lib/latte/Install.py`` script with the specified args: .. code-block:: bash @@ -450,10 +451,10 @@ be installed on your system. **Traditional make**\ : Before building LAMMPS, you must build the CSlib library in -lib/message. You can build the CSlib library manually if you prefer; -follow the instructions in lib/message/README. You can also do it in -one step from the lammps/src dir, using a command like these, which -simply invoke the lib/message/Install.py script with the specified args: +``lib/message``\ . You can build the CSlib library manually if you prefer; +follow the instructions in ``lib/message/README``\ . You can also do it in +one step from the ``lammps/src`` dir, using a command like these, which +simply invoke the ``lib/message/Install.py`` script with the specified args: .. code-block:: bash @@ -461,9 +462,9 @@ simply invoke the lib/message/Install.py script with the specified args: $ make lib-message args="-m -z" # build with MPI and socket (ZMQ) support $ make lib-message args="-s" # build as serial lib with no ZMQ support -The build should produce two files: lib/message/cslib/src/libmessage.a -and lib/message/Makefile.lammps. The latter is copied from an -existing Makefile.lammps.\* and has settings to link with the ZeroMQ +The build should produce two files: ``lib/message/cslib/src/libmessage.a`` +and ``lib/message/Makefile.lammps``\ . The latter is copied from an +existing ``Makefile.lammps.\*`` and has settings to link with the ZeroMQ library if requested in the build. ---------- @@ -474,10 +475,10 @@ MSCG package ----------------------- To build with this package, you must download and build the MS-CG -library. Building the MS-CG library and using it from LAMMPS requires -a C++11 compatible compiler and that the GSL (GNU Scientific Library) -headers and libraries are installed on your machine. See the -lib/mscg/README and MSCG/Install files for more details. +library. Building the MS-CG library requires that the GSL +(GNU Scientific Library) headers and libraries are installed on your +machine. See the ``lib/mscg/README`` and ``MSCG/Install`` files for +more details. **CMake build**\ : @@ -487,19 +488,19 @@ lib/mscg/README and MSCG/Install files for more details. -D MSCG_LIBRARY=path # MSCG library file (only needed if a custom location) -D MSCG_INCLUDE_DIR=path # MSCG include directory (only needed if a custom location) -If DOWNLOAD_MSCG is set, the MSCG library will be downloaded and built +If ``DOWNLOAD_MSCG`` is set, the MSCG library will be downloaded and built inside the CMake build directory. If the MSCG library is already on -your system (in a location CMake cannot find it), MSCG_LIBRARY is the +your system (in a location CMake cannot find it), ``MSCG_LIBRARY`` is the filename (plus path) of the MSCG library file, not the directory the -library file is in. MSCG_INCLUDE_DIR is the directory the MSCG +library file is in. ``MSCG_INCLUDE_DIR`` is the directory the MSCG include file is in. **Traditional make**\ : You can download and build the MS-CG library manually if you prefer; -follow the instructions in lib/mscg/README. You can also do it in one -step from the lammps/src dir, using a command like these, which simply -invoke the lib/mscg/Install.py script with the specified args: +follow the instructions in ``lib/mscg/README``\ . You can also do it in one +step from the ``lammps/src`` dir, using a command like these, which simply +invoke the ``lib/mscg/Install.py`` script with the specified args: .. code-block:: bash @@ -511,9 +512,9 @@ invoke the lib/mscg/Install.py script with the specified args: $ make lib-mscg args="-p /usr/local/mscg-release" # use the existing MS-CG installation in /usr/local/mscg-release Note that 2 symbolic (soft) links, "includelink" and "liblink", will -be created in lib/mscg to point to the MS-CG src/installation dir. -When LAMMPS is built in src it will use these links. You should not -need to edit the lib/mscg/Makefile.lammps file. +be created in ``lib/mscg`` to point to the MS-CG ``src/installation`` +dir. When LAMMPS is built in src it will use these links. You should +not need to edit the ``lib/mscg/Makefile.lammps`` file. ---------- @@ -524,7 +525,7 @@ OPT package **CMake build**\ : -No additional settings are needed besides "-D PKG_OPT=yes". +No additional settings are needed besides ``-D PKG_OPT=yes`` **Traditional make**\ : @@ -542,15 +543,15 @@ POEMS package **CMake build**\ : -No additional settings are needed besides "-D PKG_OPT=yes". +No additional settings are needed besides ``-D PKG_OPT=yes`` **Traditional make**\ : -Before building LAMMPS, you must build the POEMS library in lib/poems. +Before building LAMMPS, you must build the POEMS library in ``lib/poems``\ . You can do this manually if you prefer; follow the instructions in -lib/poems/README. You can also do it in one step from the lammps/src +``lib/poems/README``\ . You can also do it in one step from the ``lammps/src`` dir, using a command like these, which simply invoke the -lib/poems/Install.py script with the specified args: +``lib/poems/Install.py`` script with the specified args: .. code-block:: bash @@ -559,13 +560,13 @@ lib/poems/Install.py script with the specified args: $ make lib-poems args="-m mpi" # build with default MPI C++ compiler (settings as with "make mpi") $ make lib-poems args="-m icc" # build with Intel icc compiler -The build should produce two files: lib/poems/libpoems.a and -lib/poems/Makefile.lammps. The latter is copied from an existing -Makefile.lammps.\* and has settings needed to build LAMMPS with the +The build should produce two files: ``lib/poems/libpoems.a`` and +``lib/poems/Makefile.lammps``\ . The latter is copied from an existing +``Makefile.lammps.\*`` and has settings needed to build LAMMPS with the POEMS library (though typically the settings are just blank). If -necessary, you can edit/create a new lib/poems/Makefile.machine file -for your system, which should define an EXTRAMAKE variable to specify -a corresponding Makefile.lammps.machine file. +necessary, you can edit/create a new ``lib/poems/Makefile.machine`` file +for your system, which should define an ``EXTRAMAKE`` variable to specify +a corresponding ``Makefile.lammps.machine`` file. ---------- @@ -575,9 +576,9 @@ PYTHON package --------------------------- Building with the PYTHON package requires you have a Python shared -library available on your system, which needs to be a Python 2 -version, 2.6 or later. Python 3 is not yet supported. See -lib/python/README for more details. +library available on your system, which needs to be a Python 2.7 +version or a Python 3.x version. See ``lib/python/README`` for more +details. **CMake build**\ : @@ -594,10 +595,10 @@ headers installed for this version, e.g. python2-devel. **Traditional make**\ : -The build uses the lib/python/Makefile.lammps file in the compile/link +The build uses the ``lib/python/Makefile.lammps`` file in the compile/link process to find Python. You should only need to create a new -Makefile.lammps.\* file (and copy it to Makefile.lammps) if the LAMMPS -build fails. +``Makefile.lammps.\*`` file (and copy it to ``Makefile.lammps``\ ) if +the LAMMPS build fails. ---------- diff --git a/doc/src/Build_package.rst b/doc/src/Build_package.rst index 23ff460d5c..b3d2d3fc56 100644 --- a/doc/src/Build_package.rst +++ b/doc/src/Build_package.rst @@ -47,13 +47,13 @@ versus make. **CMake build**\ : -.. code-block:: bash +.. code-block:: csh -D PKG_NAME=value # yes or no (default) Examples: -.. code-block:: bash +.. code-block:: csh -D PKG_MANYBODY=yes -D PKG_USER-INTEL=yes @@ -185,7 +185,7 @@ one of them as a starting point and customize it to your needs. The following commands are useful for managing package source files and their installation when building LAMMPS via traditional make. -Just type "make" in lammps/src to see a one-line summary. +Just type ``make`` in lammps/src to see a one-line summary. These commands install/un-install sets of packages: @@ -202,8 +202,8 @@ These commands install/un-install sets of packages: make yes-ext # install packages that require external libraries make no-ext # uninstall packages that require external libraries -which install/un-install various sets of packages. Typing "make -package" will list all the these commands. +which install/un-install various sets of packages. Typing ``make +package`` will list all the these commands. .. note:: @@ -220,23 +220,23 @@ need to use these commands unless you are editing LAMMPS files or are :doc:`installing a patch ` downloaded from the LAMMPS web site. -Type "make package-status" or "make ps" to show which packages are +Type ``make package-status`` or ``make ps`` to show which packages are currently installed. For those that are installed, it will list any files that are different in the src directory and package sub-directory. -Type "make package-installed" or "make pi" to show which packages are +Type ``make package-installed`` or ``make pi`` to show which packages are currently installed, without listing the status of packages that are not installed. -Type "make package-update" or "make pu" to overwrite src files with +Type ``make package-update`` or ``make pu`` to overwrite src files with files from the package sub-directories if the package is installed. It should be used after a :doc:`patch has been applied `, since patches only update the files in the package sub-directory, but not the src files. -Type "make package-overwrite" to overwrite files in the package +Type ``make package-overwrite`` to overwrite files in the package sub-directories with src files. -Type "make package-diff" to list all differences between pairs of +Type ``make package-diff`` to list all differences between pairs of files in both the source directory and the package directory. diff --git a/doc/src/Build_settings.rst b/doc/src/Build_settings.rst index 4c318626e0..01792507e7 100644 --- a/doc/src/Build_settings.rst +++ b/doc/src/Build_settings.rst @@ -100,9 +100,9 @@ to assist: FFT_LIB = -lmkl_gf_lp64 -lmkl_gnu_thread -lmkl_core # MKL with GNU compiler, threaded interface FFT_LIB = -lmkl_rt # MKL with automatic runtime selection of interface libs -As with CMake, you do not need to set paths in FFT_INC or FFT_PATH, if +As with CMake, you do not need to set paths in ``FFT_INC`` or ``FFT_PATH``, if the compiler can find the FFT header and library files in its default search path. -You must specify FFT_LIB with the appropriate FFT libraries to include in the link. +You must specify ``FFT_LIB`` with the appropriate FFT libraries to include in the link. **CMake and make info**\ : @@ -126,14 +126,15 @@ platform and can be faster than the KISS FFT library. You can download it from `www.fftw.org `_. LAMMPS requires version 3.X; the legacy version 2.1.X is no longer supported. -Building FFTW for your box should be as simple as ./configure; make; -make install. The install command typically requires root privileges +Building FFTW for your box should be as simple as ``./configure; make; +make install``\ . The install command typically requires root privileges (e.g. invoke it via sudo), unless you specify a local directory with -the "--prefix" option of configure. Type "./configure --help" to see +the "--prefix" option of configure. Type ``./configure --help`` to see various options. The Intel MKL math library is part of the Intel compiler suite. It -can be used with the Intel or GNU compiler (see FFT_LIB setting above). +can be used with the Intel or GNU compiler (see the ``FFT_LIB`` setting +above). Performing 3d FFTs in parallel can be time consuming due to data access and required communication. This cost can be reduced by @@ -142,15 +143,15 @@ precision means the real and imaginary parts of a complex datum are 4-byte floats. Double precision means they are 8-byte doubles. Note that Fourier transform and related PPPM operations are somewhat less sensitive to floating point truncation errors and thus the resulting -error is less than the difference in precision. Using the -DFFT_SINGLE +error is less than the difference in precision. Using the ``-DFFT_SINGLE`` setting trades off a little accuracy for reduced memory use and parallel communication costs for transposing 3d FFT data. -When using -DFFT_SINGLE with FFTW3 you may need to build the FFTW +When using ``-DFFT_SINGLE`` with FFTW3 you may need to build the FFTW library a second time with support for single-precision. For FFTW3, do the following, which should produce the additional -library libfftw3f.a or libfftw3f.so. +library ``libfftw3f.a`` or ``libfftw3f.so``\ . .. code-block:: bash @@ -187,7 +188,8 @@ adequate. LMP_INC = -DLAMMPS_SMALLBIG # or -DLAMMPS_BIGBIG or -DLAMMPS_SMALLSMALL -# default is LAMMPS_SMALLBIG if not specified +The default setting is ``-DLAMMPS_SMALLBIG`` if nothing is specified + **CMake and make info**\ : The default "smallbig" setting allows for simulations with: @@ -235,7 +237,7 @@ than crashing randomly or corrupting data. Also note that the GPU package requires its lib/gpu library to be compiled with the same size setting, or the link will fail. A CMake build does this automatically. When building with make, the setting -in whichever lib/gpu/Makefile is used must be the same as above. +in whichever ``lib/gpu/Makefile`` is used must be the same as above. ---------- @@ -286,15 +288,16 @@ variables: JPG_PATH = -L/usr/lib # paths to libjpeg.a, libpng.a, libz.a (.so) files if make cannot find them JPG_LIB = -ljpeg -lpng -lz # library names -As with CMake, you do not need to set JPG_INC or JPG_PATH, if make can -find the graphics header and library files. You must specify JPG_LIB +As with CMake, you do not need to set ``JPG_INC`` or ``JPG_PATH``, +if make can find the graphics header and library files. You must +specify ``JPG_LIB`` with a list of graphics libraries to include in the link. You must insure ffmpeg is in a directory where LAMMPS can find it at runtime, that is a directory in your PATH environment variable. **CMake and make info**\ : -Using ffmpeg to output movie files requires that your machine +Using ``ffmpeg`` to output movie files requires that your machine supports the "popen" function in the standard runtime library. .. note:: @@ -366,7 +369,7 @@ aligned on 64-byte boundaries. -D LAMMPS_MEMALIGN=value # 0, 8, 16, 32, 64 (default) -Use a LAMMPS_MEMALIGN value of 0 to disable using posix_memalign() +Use a ``LAMMPS_MEMALIGN`` value of 0 to disable using posix_memalign() and revert to using the malloc() C-library function instead. When compiling LAMMPS for Windows systems, malloc() will always be used and this setting ignored. @@ -377,8 +380,8 @@ and this setting ignored. LMP_INC = -DLAMMPS_MEMALIGN=value # 8, 16, 32, 64 -Do not set -DLAMMPS_MEMALIGN, if you want to have memory allocated -with the malloc() function call instead. -DLAMMPS_MEMALIGN **cannot** +Do not set ``-DLAMMPS_MEMALIGN``, if you want to have memory allocated +with the malloc() function call instead. ``-DLAMMPS_MEMALIGN`` **cannot** be used on Windows, as it does use different function calls for allocating aligned memory, that are not compatible with how LAMMPS manages its dynamical memory. diff --git a/doc/src/Install_git.rst b/doc/src/Install_git.rst index 8185d65e7c..2f6e8096dc 100644 --- a/doc/src/Install_git.rst +++ b/doc/src/Install_git.rst @@ -16,7 +16,7 @@ commands explained below to communicate with the git servers on GitHub. For people still using subversion (svn), GitHub also provides `limited support for subversion clients `_. -.. warning:: +.. note:: As of October 2016, the official home of public LAMMPS development is on GitHub. The previously advertised LAMMPS git repositories on diff --git a/doc/src/Install_tarball.rst b/doc/src/Install_tarball.rst index a3df478311..d80fc14f76 100644 --- a/doc/src/Install_tarball.rst +++ b/doc/src/Install_tarball.rst @@ -26,7 +26,7 @@ command: .. code-block:: bash - $ tar -xzvf lammps\*.tar.gz + $ tar -xzvf lammps*.tar.gz This will create a LAMMPS directory with the version date in its name, e.g. lammps-23Jun18. @@ -40,7 +40,7 @@ a lammps-master dir: .. code-block:: bash - $ unzip lammps\*.zip + $ unzip lammps*.zip This version is the most up-to-date LAMMPS development version. It will have the date of the most recent patch release (see the file diff --git a/doc/src/Install_windows.rst b/doc/src/Install_windows.rst index 9a876eb732..548f67e484 100644 --- a/doc/src/Install_windows.rst +++ b/doc/src/Install_windows.rst @@ -4,7 +4,9 @@ Download an executable for Windows Pre-compiled Windows installers which install LAMMPS executables on a Windows system can be downloaded from this site: -`http://packages.lammps.org/windows.html `_ +.. parsed-literal:: + + `http://packages.lammps.org/windows.html `_ Note that each installer package has a date in its name, which corresponds to the LAMMPS version of the same date. Installers for -- GitLab From 6cc7ac65a51d38dd83269825716055c36b97cb9e Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Fri, 13 Mar 2020 20:46:14 -0600 Subject: [PATCH 274/689] VORONOI.cmake: fix ninja build --- cmake/Modules/Packages/VORONOI.cmake | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cmake/Modules/Packages/VORONOI.cmake b/cmake/Modules/Packages/VORONOI.cmake index 89fa70bf98..5418132034 100644 --- a/cmake/Modules/Packages/VORONOI.cmake +++ b/cmake/Modules/Packages/VORONOI.cmake @@ -7,9 +7,6 @@ if(PKG_VORONOI) endif() option(DOWNLOAD_VORO "Download and compile the Voro++ library instead of using an already installed one" ${DOWNLOAD_VORO_DEFAULT}) if(DOWNLOAD_VORO) - if(CMAKE_GENERATOR STREQUAL "Ninja") - message(FATAL_ERROR "Cannot build downloaded Voro++ library with Ninja build tool") - endif() message(STATUS "Voro++ download requested - we will build our own") include(ExternalProject) @@ -29,6 +26,7 @@ if(PKG_VORONOI) URL https://download.lammps.org/thirdparty/voro++-0.4.6.tar.gz URL_MD5 2338b824c3b7b25590e18e8df5d68af9 CONFIGURE_COMMAND "" BUILD_COMMAND make ${VORO_BUILD_OPTIONS} BUILD_IN_SOURCE 1 INSTALL_COMMAND "" + BUILD_BYPRODUCTS /src/libvoro++.a ) ExternalProject_get_property(voro_build SOURCE_DIR) set(VORO_LIBRARIES ${SOURCE_DIR}/src/libvoro++.a) -- GitLab From 649a8cc01a314947eb262a30ed7a83210eeb7521 Mon Sep 17 00:00:00 2001 From: Eisuke Kawashima Date: Sat, 14 Mar 2020 12:38:28 +0900 Subject: [PATCH 275/689] Fix typo --- cmake/Modules/Packages/USER-NETCDF.cmake | 2 +- cmake/README.md | 4 +- doc/msi2lmp.1 | 2 +- doc/src/2001/README.html | 2 +- doc/src/2001/basics.html | 2 +- doc/src/2001/input_commands.html | 6 +- doc/src/99/README.html | 2 +- doc/src/99/basics.html | 2 +- doc/src/99/input_commands.html | 4 +- doc/src/Errors_messages.rst | 2 +- doc/src/USER/atc/man_boundary.html | 2 +- doc/src/USER/atc/man_hardy_gradients.html | 2 +- doc/src/USER/atc/man_hardy_rates.html | 2 +- .../lammps_nwchem/planewave/nwchem_lammps.out | 2 +- examples/COUPLE/lammps_quest/lmpqst.cpp | 2 +- examples/UNITS/README | 4 +- examples/USER/atc/README | 4 +- examples/USER/atc/fluids/in.bar1d_fluids | 2 +- .../USER/atc/fluids/in.conducting_interface | 2 +- .../USER/atc/fluids/in.dielectric_interface | 2 +- examples/USER/atc/fluids/in.shear_flow | 2 +- examples/USER/atc/fluids/in.shear_no_atoms | 2 +- examples/USER/atc/thermal/bar1d.screen | 2 +- examples/USER/atc/thermal/in.bar1d | 2 +- examples/USER/atc/thermal/in.bar1d_all_atoms | 2 +- examples/USER/atc/thermal/in.bar1d_combined | 2 +- examples/USER/atc/thermal/in.bar1d_flux | 2 +- examples/USER/atc/thermal/in.bar1d_frac_step | 2 +- examples/USER/cgdna/README | 2 +- .../oxDNA2/unique_bp/generate_unique.py | 6 +- examples/USER/cgdna/util/generate.py | 4 +- examples/USER/diffraction/README | 2 +- examples/USER/eff/Li-dendritic/README | 2 +- .../fourspheres/in.fourspheres_default_gamma | 2 +- .../lb/fourspheres/in.fourspheres_set_gamma | 2 +- examples/USER/misc/ees/README | 2 +- examples/USER/misc/hma/README | 2 +- examples/USER/plumed/reference/p.log | 2 +- .../USER/qtb/methane_qbmsst/methane_qtb.mod | 2 +- examples/USER/qtb/methane_qtb/methane_qtb.in | 2 +- examples/USER/quip/in.molecular | 2 +- .../USER/quip/log.24Jul17.molecular.g++.1 | 2 +- .../USER/quip/log.24Jul17.molecular.g++.4 | 2 +- .../aluminum_strip_pull.lmp | 4 +- .../fluid_structure_interaction.lmp | 4 +- examples/USER/smd/funnel_flow/funnel_flow.lmp | 2 +- .../smd/rubber_rings_3d/rubber_rings_3d.lmp | 2 +- .../rubber_strip_pull/rubber_strip_pull.lmp | 2 +- examples/USER/tally/in.pe | 2 +- examples/USER/tally/log.12Jun17.pe.1 | 2 +- examples/USER/tally/log.12Jun17.pe.4 | 2 +- examples/hugoniostat/in.hugoniostat | 6 +- .../hugoniostat/log.27Nov18.hugoniostat.g++.1 | 6 +- .../hugoniostat/log.27Nov18.hugoniostat.g++.4 | 6 +- examples/reax/HNS/README.txt | 2 +- lib/atc/ATC_Coupling.cpp | 2 +- lib/atc/ATC_Coupling.h | 2 +- lib/atc/ATC_CouplingEnergy.cpp | 2 +- lib/atc/ATC_CouplingMass.cpp | 2 +- lib/atc/ATC_CouplingMomentum.cpp | 2 +- lib/atc/ATC_CouplingMomentumEnergy.cpp | 2 +- lib/atc/ATC_Method.cpp | 4 +- lib/atc/ATC_Transfer.cpp | 8 +-- lib/atc/AtomToMoleculeTransfer.h | 2 +- lib/atc/AtomicRegulator.h | 2 +- lib/atc/CbPotential.h | 2 +- lib/atc/ChargeRegulator.cpp | 4 +- lib/atc/ConcentrationRegulator.cpp | 2 +- lib/atc/DiagonalMatrix.h | 2 +- lib/atc/ElasticTimeIntegrator.cpp | 6 +- lib/atc/ElectronHeatFlux.h | 2 +- lib/atc/ExtrinsicModelElectrostatic.cpp | 2 +- lib/atc/ExtrinsicModelElectrostatic.h | 2 +- lib/atc/FE_Element.cpp | 4 +- lib/atc/FE_Engine.cpp | 2 +- lib/atc/FE_Engine.h | 2 +- lib/atc/FE_Interpolate.cpp | 4 +- lib/atc/FieldEulerIntegrator.h | 2 +- lib/atc/FundamentalAtomicQuantity.h | 2 +- lib/atc/GhostManager.cpp | 2 +- lib/atc/InterscaleOperators.cpp | 2 +- lib/atc/InterscaleOperators.h | 12 ++-- lib/atc/KinetoThermostat.h | 2 +- lib/atc/Kinetostat.cpp | 4 +- lib/atc/Kinetostat.h | 2 +- lib/atc/LammpsInterface.cpp | 2 +- lib/atc/Material.h | 2 +- lib/atc/Matrix.cpp | 4 +- lib/atc/Matrix.h | 4 +- lib/atc/PhysicsModel.cpp | 2 +- lib/atc/SparseMatrix.h | 4 +- lib/atc/SparseVector-inl.h | 4 +- lib/atc/SparseVector.h | 8 +-- lib/atc/Stress.cpp | 4 +- lib/atc/ThermalTimeIntegrator.cpp | 6 +- lib/atc/ThermalTimeIntegrator.h | 2 +- lib/atc/Thermostat.cpp | 8 +-- lib/atc/Thermostat.h | 2 +- lib/atc/TimeIntegrator.h | 4 +- lib/atc/TransferOperator.h | 8 +-- lib/awpmd/ivutils/include/logexc.h | 6 +- lib/awpmd/ivutils/include/wavepacket.h | 4 +- lib/awpmd/systems/interact/TCP/wpmd.cpp | 2 +- lib/awpmd/systems/interact/TCP/wpmd.h | 8 +-- lib/awpmd/systems/interact/TCP/wpmd_split.cpp | 2 +- lib/colvars/colvar.cpp | 2 +- lib/colvars/colvarbias_abf.h | 2 +- lib/colvars/colvarcomp.h | 2 +- lib/colvars/colvarcomp_protein.cpp | 6 +- lib/colvars/colvardeps.h | 2 +- lib/colvars/colvarproxy.h | 2 +- lib/gpu/README | 2 +- lib/gpu/cudpp_mini/cudpp.cpp | 2 +- lib/gpu/cudpp_mini/cutil.h | 6 +- lib/gpu/cudpp_mini/kernel/scan_kernel.cu | 2 +- lib/gpu/lal_base_atomic.h | 2 +- lib/gpu/lal_base_charge.h | 2 +- lib/gpu/lal_base_dipole.h | 2 +- lib/gpu/lal_base_dpd.h | 2 +- lib/gpu/lal_base_ellipsoid.h | 2 +- lib/gpu/lal_base_three.h | 2 +- lib/gpu/lal_beck.h | 2 +- lib/gpu/lal_born.h | 2 +- lib/gpu/lal_born_coul_long.h | 2 +- lib/gpu/lal_born_coul_long_cs.h | 2 +- lib/gpu/lal_born_coul_wolf.h | 2 +- lib/gpu/lal_born_coul_wolf_cs.h | 2 +- lib/gpu/lal_buck.h | 2 +- lib/gpu/lal_buck_coul.h | 2 +- lib/gpu/lal_buck_coul_long.h | 2 +- lib/gpu/lal_charmm_long.h | 2 +- lib/gpu/lal_colloid.h | 2 +- lib/gpu/lal_coul.h | 2 +- lib/gpu/lal_coul_debye.h | 2 +- lib/gpu/lal_coul_dsf.h | 2 +- lib/gpu/lal_coul_long.h | 2 +- lib/gpu/lal_coul_long_cs.h | 2 +- lib/gpu/lal_device.h | 8 +-- lib/gpu/lal_dipole_lj.h | 2 +- lib/gpu/lal_dipole_lj_sf.h | 2 +- lib/gpu/lal_dipole_long_lj.h | 2 +- lib/gpu/lal_dpd.h | 2 +- lib/gpu/lal_eam.h | 2 +- lib/gpu/lal_gauss.h | 2 +- lib/gpu/lal_gayberne.h | 2 +- lib/gpu/lal_lj.h | 2 +- lib/gpu/lal_lj96.h | 2 +- lib/gpu/lal_lj_class2_long.h | 2 +- lib/gpu/lal_lj_coul.h | 2 +- lib/gpu/lal_lj_coul_debye.h | 2 +- lib/gpu/lal_lj_coul_long.h | 2 +- lib/gpu/lal_lj_coul_msm.h | 2 +- lib/gpu/lal_lj_cubic.h | 2 +- lib/gpu/lal_lj_dsf.h | 2 +- lib/gpu/lal_lj_expand.h | 2 +- lib/gpu/lal_lj_expand_coul_long.h | 2 +- lib/gpu/lal_lj_gromacs.h | 2 +- lib/gpu/lal_lj_sdk.h | 2 +- lib/gpu/lal_lj_sdk_long.h | 2 +- lib/gpu/lal_lj_tip4p_long.h | 2 +- lib/gpu/lal_mie.h | 2 +- lib/gpu/lal_morse.h | 2 +- lib/gpu/lal_pppm.h | 2 +- lib/gpu/lal_re_squared.h | 2 +- lib/gpu/lal_soft.h | 2 +- lib/gpu/lal_sw.h | 2 +- lib/gpu/lal_table.h | 2 +- lib/gpu/lal_tersoff.h | 2 +- lib/gpu/lal_tersoff_mod.h | 2 +- lib/gpu/lal_tersoff_zbl.h | 2 +- lib/gpu/lal_ufm.h | 2 +- lib/gpu/lal_vashishta.h | 2 +- lib/gpu/lal_yukawa.h | 2 +- lib/gpu/lal_yukawa_colloid.h | 2 +- lib/gpu/lal_zbl.h | 2 +- lib/h5md/README | 2 +- lib/kokkos/algorithms/src/Kokkos_Random.hpp | 4 +- .../policy_performance/script_sample_usage.sh | 2 +- lib/kokkos/bin/hpcbind | 2 +- .../containers/src/Kokkos_UnorderedMap.hpp | 2 +- lib/kokkos/containers/src/Kokkos_Vector.hpp | 4 +- .../containers/unit_tests/TestBitset.hpp | 2 +- .../TestViewCtorPropEmbeddedDim.hpp | 2 +- .../core/src/Cuda/Kokkos_Cuda_Locks.hpp | 8 +-- .../core/src/Cuda/Kokkos_Cuda_Parallel.hpp | 12 ++-- lib/kokkos/core/src/Kokkos_Concepts.hpp | 2 +- lib/kokkos/core/src/Kokkos_CopyViews.hpp | 2 +- lib/kokkos/core/src/Kokkos_CudaSpace.hpp | 2 +- lib/kokkos/core/src/Kokkos_HBWSpace.hpp | 8 +-- lib/kokkos/core/src/Kokkos_HostSpace.hpp | 8 +-- .../core/src/Kokkos_OpenMPTargetSpace.hpp | 8 +-- .../core/src/Kokkos_Parallel_Reduce.hpp | 2 +- lib/kokkos/core/src/Kokkos_ROCmSpace.hpp | 2 +- .../src/OpenMP/Kokkos_OpenMP_Parallel.hpp | 4 +- .../Kokkos_Qthreads_TaskPolicy.hpp.old | 2 +- .../Kokkos_Qthreads_TaskQueue_impl.hpp | 2 +- .../core/src/Threads/Kokkos_ThreadsExec.cpp | 4 +- .../src/Threads/Kokkos_ThreadsExec_base.cpp | 4 +- lib/kokkos/core/src/impl/Kokkos_Error.cpp | 2 +- .../core/src/impl/Kokkos_HostBarrier.hpp | 2 +- .../core/src/impl/Kokkos_HostThreadTeam.cpp | 2 +- .../core/src/impl/Kokkos_SharedAlloc.hpp | 2 +- lib/kokkos/core/src/impl/Kokkos_TaskNode.hpp | 4 +- .../core/src/impl/Kokkos_TaskQueue_impl.hpp | 2 +- lib/kokkos/core/src/impl/Kokkos_Traits.hpp | 2 +- lib/kokkos/core/unit_test/TestTeam.hpp | 4 +- lib/kokkos/core/unit_test/TestTeamVector.hpp | 2 +- .../unit_test/TestViewCtorPropEmbeddedDim.hpp | 2 +- lib/kokkos/core/unit_test/TestWorkGraph.hpp | 2 +- lib/kokkos/example/fenl/fenl_functors.hpp | 2 +- .../example/multi_fem/BoxMeshPartition.hpp | 2 +- lib/kokkos/example/multi_fem/Implicit.hpp | 2 +- lib/kokkos/example/multi_fem/Nonlinear.hpp | 2 +- .../example/tutorial/03_simple_view/Makefile | 2 +- .../01_random_numbers/random_numbers.cpp | 6 +- lib/linalg/dlaed8.f | 2 +- lib/linalg/dlalsa.f | 2 +- lib/linalg/dlasd7.f | 2 +- lib/linalg/iparam2stage.F | 4 +- lib/message/README | 2 +- lib/molfile/molfile_plugin.h | 2 +- lib/plumed/README | 2 +- lib/poems/SystemProcessor.h | 4 +- lib/poems/fastmatrixops.h | 2 +- lib/poems/joint.cpp | 4 +- lib/poems/matrixfun.cpp | 6 +- lib/poems/poemstree.h | 4 +- lib/qmmm/README | 2 +- lib/scafacos/README | 8 +-- potentials/BNCH-old.ILP | 2 +- potentials/BNCH.ILP | 2 +- potentials/BNC_MBD_bulk.ILP | 2 +- potentials/BNC_TS_bulk.ILP | 2 +- python/examples/pylammps/montecarlo/mc.ipynb | 2 +- python/lammps.py | 2 +- src/COLLOID/pair_lubricateU.cpp | 6 +- src/COLLOID/pair_lubricateU_poly.cpp | 4 +- src/CORESHELL/pair_born_coul_wolf_cs.cpp | 2 +- src/CORESHELL/pair_coul_wolf_cs.cpp | 2 +- src/GPU/pair_born_coul_wolf_cs_gpu.cpp | 2 +- src/KIM/README | 2 +- src/KIM/kim_units.cpp | 2 +- src/KOKKOS/atom_vec_bond_kokkos.cpp | 2 +- src/KOKKOS/comm_kokkos.cpp | 2 +- src/KOKKOS/comm_tiled_kokkos.cpp | 2 +- src/KOKKOS/fix_eos_table_rx_kokkos.h | 2 +- src/KOKKOS/npair_ssa_kokkos.cpp | 2 +- src/KOKKOS/pair_exp6_rx_kokkos.cpp | 4 +- src/KOKKOS/pppm_kokkos.cpp | 2 +- src/KOKKOS/sna_kokkos.h | 2 +- src/KOKKOS/sna_kokkos_impl.h | 2 +- src/KSPACE/ewald_dipole.cpp | 2 +- src/KSPACE/ewald_dipole_spin.cpp | 2 +- src/KSPACE/msm_cg.cpp | 2 +- src/KSPACE/pppm.cpp | 4 +- src/KSPACE/pppm_cg.cpp | 2 +- src/KSPACE/pppm_dipole.cpp | 2 +- src/KSPACE/pppm_disp.cpp | 14 ++-- src/KSPACE/pppm_disp_tip4p.cpp | 2 +- src/KSPACE/pppm_stagger.cpp | 2 +- src/KSPACE/pppm_tip4p.cpp | 2 +- src/MAKE/MACHINES/Makefile.redsky | 2 +- src/MANYBODY/pair_airebo.cpp | 4 +- src/MANYBODY/pair_bop.h | 4 +- src/MANYBODY/pair_lcbop.cpp | 2 +- src/MISC/dump_xtc.cpp | 6 +- src/MISC/fix_deposit.cpp | 2 +- src/MPIIO/restart_mpiio.cpp | 2 +- src/MSCG/README | 2 +- src/PERI/fix_peri_neigh.h | 4 +- src/PERI/pair_peri_ves.cpp | 4 +- src/PYTHON/fix_python_move.h | 2 +- src/PYTHON/pair_python.h | 2 +- src/REPLICA/fix_event_hyper.h | 2 +- src/REPLICA/fix_event_prd.h | 2 +- src/REPLICA/fix_hyper_global.cpp | 2 +- src/REPLICA/fix_hyper_local.cpp | 6 +- src/REPLICA/prd.cpp | 2 +- src/RIGID/fix_rigid.cpp | 4 +- src/RIGID/fix_rigid_nh.h | 2 +- src/RIGID/fix_rigid_nh_small.h | 2 +- src/RIGID/fix_rigid_small.cpp | 6 +- src/RIGID/fix_shake.cpp | 2 +- src/SPIN/README | 2 +- src/SPIN/min_spin.cpp | 2 +- src/SPIN/min_spin_cg.cpp | 2 +- src/SPIN/min_spin_lbfgs.cpp | 2 +- src/SRD/fix_srd.cpp | 6 +- src/USER-ATC/fix_atc.cpp | 2 +- src/USER-DIFFRACTION/README | 2 +- src/USER-DIFFRACTION/compute_saed.cpp | 8 +-- src/USER-DIFFRACTION/fix_saed_vtk.cpp | 2 +- src/USER-DPD/fix_rx.h | 2 +- src/USER-DPD/npair_half_bin_newton_ssa.cpp | 2 +- src/USER-DRUDE/pair_lj_cut_thole_long.cpp | 2 +- src/USER-DRUDE/pair_thole.cpp | 2 +- src/USER-INTEL/README | 2 +- src/USER-INTEL/pair_airebo_intel.cpp | 2 +- .../pair_lj_charmm_coul_charmm_intel.cpp | 2 +- .../pair_lj_charmm_coul_charmm_intel.h | 2 +- .../pair_lj_charmm_coul_long_intel.cpp | 2 +- .../pair_lj_charmm_coul_long_intel.h | 2 +- src/USER-INTEL/pppm_disp_intel.cpp | 2 +- src/USER-MANIFOLD/fix_nve_manifold_rattle.cpp | 2 +- src/USER-MANIFOLD/manifold_thylakoid.cpp | 2 +- src/USER-MEAMC/README | 2 +- src/USER-MEAMC/meam_funcs.cpp | 2 +- src/USER-MEAMC/meam_setup_done.cpp | 2 +- src/USER-MGPT/pair_mgpt.cpp | 2 +- src/USER-MISC/compute_cnp_atom.cpp | 2 +- src/USER-MISC/compute_stress_mop.cpp | 2 +- src/USER-MISC/compute_stress_mop_profile.cpp | 4 +- src/USER-MISC/dihedral_table.cpp | 2 +- src/USER-MISC/dihedral_table_cut.cpp | 2 +- src/USER-MISC/fix_flow_gauss.cpp | 2 +- src/USER-MISC/fix_ipi.cpp | 2 +- src/USER-MISC/fix_pimd.cpp | 4 +- src/USER-MISC/fix_pimd.h | 2 +- src/USER-MISC/fix_wall_reflect_stochastic.cpp | 4 +- src/USER-MISC/pair_cosine_squared.cpp | 2 +- src/USER-MISC/pair_coul_shield.cpp | 2 +- src/USER-MISC/pair_drip.cpp | 2 +- src/USER-MISC/pair_e3b.cpp | 2 +- src/USER-MISC/pair_extep.cpp | 2 +- src/USER-MISC/pair_ilp_graphene_hbn.cpp | 6 +- src/USER-MISC/pair_kolmogorov_crespi_full.cpp | 4 +- src/USER-MISC/pair_mesocnt.cpp | 4 +- src/USER-OMP/msm_cg_omp.cpp | 2 +- src/USER-OMP/pair_airebo_omp.cpp | 4 +- src/USER-OMP/pair_lj_long_tip4p_long_omp.cpp | 6 +- src/USER-OMP/pppm_cg_omp.cpp | 4 +- src/USER-OMP/pppm_disp_tip4p_omp.cpp | 2 +- src/USER-OMP/pppm_omp.cpp | 4 +- src/USER-OMP/pppm_tip4p_omp.cpp | 4 +- src/USER-OMP/thr_data.h | 2 +- src/USER-PHONON/fix_phonon.h | 2 +- src/USER-REACTION/fix_bond_react.cpp | 8 +-- src/USER-SMD/atom_vec_smd.cpp | 2 +- src/USER-SMD/pair_smd_tlsph.cpp | 2 +- src/USER-SMD/pair_smd_tlsph.h | 2 +- .../pair_smd_triangulated_surface.cpp | 2 +- src/USER-SMD/smd_material_models.cpp | 14 ++-- src/USER-SMTBQ/pair_smtbq.h | 4 +- src/USER-UEF/fix_nh_uef.cpp | 2 +- src/USER-VTK/dump_vtk.h | 2 +- .../pair_lj_switch3_coulgauss_long.cpp | 2 +- src/VORONOI/README | 2 +- src/comm.cpp | 6 +- src/comm_brick.cpp | 2 +- src/comm_tiled.cpp | 2 +- src/compute_cna_atom.cpp | 2 +- src/compute_orientorder_atom.cpp | 2 +- src/dump_image.cpp | 2 +- src/fix_balance.cpp | 2 +- src/fix_deform.cpp | 2 +- src/fix_tmd.cpp | 2 +- src/hashlittle.cpp | 2 +- src/input.cpp | 2 +- src/kspace.h | 2 +- src/lammps.cpp | 2 +- src/my_pool_chunk.h | 2 +- src/neigh_request.cpp | 2 +- src/pair_zero.h | 2 +- src/reset_ids.cpp | 2 +- src/write_restart.cpp | 2 +- tools/amber2lmp/amber2lammps.py | 2 +- tools/ch2lmp/charmm2lammps.pl | 6 +- tools/ch2lmp/example/par_all27_na.prm | 36 +++++----- tools/colvars/abf_data.cpp | 8 +-- tools/doxygen/README | 2 +- tools/eff/lmp2radii.c | 2 +- tools/i-pi/drivers/LJ.f90 | 2 +- tools/i-pi/drivers/SG.f90 | 2 +- tools/i-pi/ipi/engine/ensembles.py | 6 +- tools/i-pi/ipi/engine/outputs.py | 4 +- tools/i-pi/ipi/engine/properties.py | 2 +- tools/i-pi/ipi/engine/simulation.py | 2 +- tools/i-pi/ipi/engine/thermostats.py | 10 +-- tools/i-pi/ipi/tests/README | 2 +- tools/i-pi/ipi/utils/depend.py | 2 +- tools/i-pi/ipi/utils/inputvalue.py | 2 +- tools/i-pi/ipi/utils/io/io_xml.py | 4 +- tools/ipp/ipp | 2 +- tools/lmp2cfg/lmp2cfg.f | 2 +- tools/matlab/readdump_one.m | 2 +- tools/matlab/readlog.m | 2 +- tools/matlab/readrdf.m | 2 +- tools/moltemplate/README.txt | 4 +- tools/msi2lmp/frc_files/cvff.frc | 4 +- tools/msi2lmp/frc_files/cvff_aug.frc | 4 +- tools/msi2lmp/frc_files/oplsaa.frc | 2 +- tools/msi2lmp/src/ReadCarFile.c | 2 +- tools/phonon/dynmat.cpp | 2 +- tools/phonon/green.cpp | 4 +- tools/polybond/lmpsdata.py | 66 +++++++++---------- tools/pymol_asphere/src/cartesian.cpp | 4 +- tools/pymol_asphere/src/error.h | 2 +- tools/reax/reaxc_bond.pl | 2 +- tools/replica/reorder_remd_traj.py | 2 +- tools/spin/interpolate_gneb/README | 2 +- tools/xmgrace/lammpsplot.cpp | 2 +- 401 files changed, 617 insertions(+), 617 deletions(-) diff --git a/cmake/Modules/Packages/USER-NETCDF.cmake b/cmake/Modules/Packages/USER-NETCDF.cmake index f60c046ab9..921156f1e0 100644 --- a/cmake/Modules/Packages/USER-NETCDF.cmake +++ b/cmake/Modules/Packages/USER-NETCDF.cmake @@ -1,6 +1,6 @@ if(PKG_USER-NETCDF) # USER-NETCDF can use NetCDF, Parallel NetCDF (PNetCDF), or both. At least one necessary. - # NetCDF library enables dump sytle "netcdf", while PNetCDF enables dump style "netcdf/mpiio" + # NetCDF library enables dump style "netcdf", while PNetCDF enables dump style "netcdf/mpiio" find_package(NetCDF) if(NETCDF_FOUND) find_package(PNetCDF) diff --git a/cmake/README.md b/cmake/README.md index 9fb5dc3c16..b9dd6d4373 100644 --- a/cmake/README.md +++ b/cmake/README.md @@ -217,7 +217,7 @@ cmake -C ../cmake/presets/all_on.cmake -C ../cmake/presets/nolib.cmake -D PKG_GP CMAKE_VERBOSE_MAKEFILE - Enable verbose output from Makefile builds (useful for debugging), the same can be achived by adding `VERBOSE=1` to the `make` call. + Enable verbose output from Makefile builds (useful for debugging), the same can be achieved by adding `VERBOSE=1` to the `make` call.
    off (default)
    @@ -576,7 +576,7 @@ cmake -C ../cmake/presets/all_on.cmake -C ../cmake/presets/nolib.cmake -D PKG_GP Several fixes and a pair style that have Monte Carlo (MC) or MC-like attributes. These include fixes for creating, breaking, and swapping bonds, for performing atomic swaps, and performing grand-canonical MC (GCMC) in - conjuction with dynamics. + conjunction with dynamics.
    diff --git a/doc/msi2lmp.1 b/doc/msi2lmp.1 index 08a442e1de..e1a8c8a2f3 100644 --- a/doc/msi2lmp.1 +++ b/doc/msi2lmp.1 @@ -31,7 +31,7 @@ of benzene, you have to provide the files 'benzene.car' and 'benzene.mdf' in the current working directory. .B msi2lmp will then read and process those files according to its remaining settings. -All other settins are optional and have defaults as listed. +All other settings are optional and have defaults as listed. .TP \fB\-c \fR, \fB\-class \fR The \-c or \-class option selects the force field class, i.e which pair diff --git a/doc/src/2001/README.html b/doc/src/2001/README.html index d36aa917aa..d57897cd27 100644 --- a/doc/src/2001/README.html +++ b/doc/src/2001/README.html @@ -10,7 +10,7 @@ LAMMPS LAMMPS = Large-scale Atomic/Molecular Massively Parallel Simulator

    This is the documentation for the LAMMPS 2001 version, written in F90, -which has been superceded by more current versions. See the LAMMPS WWW Site for more information.

    diff --git a/doc/src/2001/basics.html b/doc/src/2001/basics.html index 24ac6de4ca..343fd8d129 100644 --- a/doc/src/2001/basics.html +++ b/doc/src/2001/basics.html @@ -47,7 +47,7 @@ directories:

    The src directory contains the F90 and C source files for LAMMPS as well as several sample Makefiles for different machines. To make LAMMPS -for a specfic machine, you simply type

    +for a specific machine, you simply type

    make machine

    diff --git a/doc/src/2001/input_commands.html b/doc/src/2001/input_commands.html index 797d6bec4e..62ef5a5120 100644 --- a/doc/src/2001/input_commands.html +++ b/doc/src/2001/input_commands.html @@ -1079,7 +1079,7 @@ for style aveforce, average force on the group of fixed atoms is computed, to new total value -> has effect of applying same force to entire group of atoms thermostatting constraints (rescale, hoover/drag, langevin) cannot be used in - conjuction with global "temp control", since they conflict and will + conjunction with global "temp control", since they conflict and will cause atom velocities to be reset twice thermostatting constraints (rescale, hoover/drag, langevin) cannot be used when performing a minimization @@ -1089,7 +1089,7 @@ meaning of rescale and Langevin thermostatting coefficients is same as in "temp control" command for rescale style, it can be used as a coarse temperature rescaler, for example "rescale 200.0 300.0 100 10.0 1.0" will ramp the temperature - up during the simulation, resetting it to the target temperatue as needed + up during the simulation, resetting it to the target temperature as needed for rescale style, it can be used to create an instantaneous drag force that slowly rescales the temperature without oscillation, for example "rescale 300.0 300.0 1 0.0 0.0001" will force (or keep) @@ -1952,7 +1952,7 @@ for rescale style, the amount of rescaling is contfolled by the fractional to halfway between the current and target temperature for rescale style, it can be used as a coarse temperature rescaler, for example "rescale 200.0 300.0 100 10.0 1.0" will ramp the temperature - up during the simulation, resetting it to the target temperatue as needed + up during the simulation, resetting it to the target temperature as needed for rescale style, it can be used to create an instantaneous drag force that slowly rescales the temperature without oscillation, for example "rescale 300.0 300.0 1 0.0 0.0001" will force (or keep) diff --git a/doc/src/99/README.html b/doc/src/99/README.html index 528c1e161d..d85f23970f 100644 --- a/doc/src/99/README.html +++ b/doc/src/99/README.html @@ -10,7 +10,7 @@ LAMMPS LAMMPS = Large-scale Atomic/Molecular Massively Parallel Simulator

    This is the documentation for the LAMMPS 99 version, written in F77, -which has been superceded by more current versions. See the LAMMPS WWW Site for more information.

    diff --git a/doc/src/99/basics.html b/doc/src/99/basics.html index b6236f4bf9..ef85d35b14 100644 --- a/doc/src/99/basics.html +++ b/doc/src/99/basics.html @@ -45,7 +45,7 @@ directories:

    The src directory contains the F77 and C source files for LAMMPS as well as several sample Makefiles for different machines. To make LAMMPS -for a specfic machine, you simply type

    +for a specific machine, you simply type

    make machine

    diff --git a/doc/src/99/input_commands.html b/doc/src/99/input_commands.html index baea02b5c2..5ece32d52b 100644 --- a/doc/src/99/input_commands.html +++ b/doc/src/99/input_commands.html @@ -430,7 +430,7 @@ accuracy criterion effectively determines how many k-space vectors are used for PPPM, accuracy criterion determines mesh spacing (see "particle mesh" command) for PPPM, must be running on power-of-2 number of processors for FFTs -must use periodic boundary conditions in conjuction with Ewald and PPPM +must use periodic boundary conditions in conjunction with Ewald and PPPM cannot use any styles other than none with nonbond style = lj/shift or nonbond style = soft Coulomb style = smooth should be used with nonbond style = lj/switch, @@ -772,7 +772,7 @@ for style aveforce, average force on the group of fixed atoms is computed, to new total value -> has effect of applying same force to entire group of atoms thermostatting constraints (rescale, langevin, nose/hoover) cannot be used in - conjuction with global "temp control", since they conflict and will + conjunction with global "temp control", since they conflict and will cause atom velocities to be reset twice if multiple Langevin constraints are specified the Marsaglia RNG will only use the last RNG seed specified for initialization diff --git a/doc/src/Errors_messages.rst b/doc/src/Errors_messages.rst index da36f18d82..1fafa82a8c 100644 --- a/doc/src/Errors_messages.rst +++ b/doc/src/Errors_messages.rst @@ -7666,7 +7666,7 @@ keyword to allow for additional bonds to be formed Keywords that refer to time (such as cpu, elapsed) do not make sense in between runs. -*Threshhold for an atom property that isn't allocated* +*Threshold for an atom property that isn't allocated* A dump threshold has been requested on a quantity that is not defined by the atom style used in this simulation. diff --git a/doc/src/USER/atc/man_boundary.html b/doc/src/USER/atc/man_boundary.html index f3b20fc78b..c4448bc191 100644 --- a/doc/src/USER/atc/man_boundary.html +++ b/doc/src/USER/atc/man_boundary.html @@ -32,7 +32,7 @@ examples

    fix_modify AtC boundary type ghost_atoms

    description

    -

    Command to define the atoms that represent the ficticious boundary internal to the FE mesh. For fully overlapped MD/FE domains with periodic boundary conditions no boundary atoms should be defined.

    +

    Command to define the atoms that represent the fictitious boundary internal to the FE mesh. For fully overlapped MD/FE domains with periodic boundary conditions no boundary atoms should be defined.

    restrictions

    diff --git a/doc/src/USER/atc/man_hardy_gradients.html b/doc/src/USER/atc/man_hardy_gradients.html index 1874ad152e..1ecfade0ea 100644 --- a/doc/src/USER/atc/man_hardy_gradients.html +++ b/doc/src/USER/atc/man_hardy_gradients.html @@ -38,7 +38,7 @@ examples

    description

    -

    Requests calculation and ouput of gradients of the fields from the transfer class. These gradients will be with regard to spatial or material coordinate for eulerian or lagrangian analysis, respectively, as specified by atom_element_map (see fix_modify AtC atom_element_map )

    +

    Requests calculation and output of gradients of the fields from the transfer class. These gradients will be with regard to spatial or material coordinate for eulerian or lagrangian analysis, respectively, as specified by atom_element_map (see fix_modify AtC atom_element_map )

    restrictions

    Must be used with the hardy/field type of AtC fix ( see fix atc command )

    diff --git a/doc/src/USER/atc/man_hardy_rates.html b/doc/src/USER/atc/man_hardy_rates.html index 337a92517e..8066543485 100644 --- a/doc/src/USER/atc/man_hardy_rates.html +++ b/doc/src/USER/atc/man_hardy_rates.html @@ -38,7 +38,7 @@ examples

    description

    -

    Requests calculation and ouput of rates (time derivatives) of the fields from the transfer class. For eulerian analysis (see fix_modify AtC atom_element_map ), these rates are the partial time derivatives of the nodal fields, not the full (material) time derivatives.
    +

    Requests calculation and output of rates (time derivatives) of the fields from the transfer class. For eulerian analysis (see fix_modify AtC atom_element_map ), these rates are the partial time derivatives of the nodal fields, not the full (material) time derivatives.

    restrictions

    diff --git a/examples/COUPLE/lammps_nwchem/planewave/nwchem_lammps.out b/examples/COUPLE/lammps_nwchem/planewave/nwchem_lammps.out index 27185413eb..92f2ff0037 100644 --- a/examples/COUPLE/lammps_nwchem/planewave/nwchem_lammps.out +++ b/examples/COUPLE/lammps_nwchem/planewave/nwchem_lammps.out @@ -1845,7 +1845,7 @@ Translation force removed: ( -0.00000 -0.00000 -0.00000) - Outputing formatted_stress_filename: ./W.vpp2 + Outputting formatted_stress_filename: ./W.vpp2 ====================== diff --git a/examples/COUPLE/lammps_quest/lmpqst.cpp b/examples/COUPLE/lammps_quest/lmpqst.cpp index 76a89f1d06..6d31a9251b 100644 --- a/examples/COUPLE/lammps_quest/lmpqst.cpp +++ b/examples/COUPLE/lammps_quest/lmpqst.cpp @@ -84,7 +84,7 @@ int main(int narg, char **arg) lmp->input->file(lammps_input); - // make info avaiable to callback function + // make info available to callback function Info info; info.me = me; diff --git a/examples/UNITS/README b/examples/UNITS/README index 3980b38688..7271e5d62b 100644 --- a/examples/UNITS/README +++ b/examples/UNITS/README @@ -27,7 +27,7 @@ The real and metal scripts each have a set of variables at the top which define scale factors for converting quantities like distance, energy, pressure from reduced LJ units to real or metal units. Once these are defined the rest of the input script is very similar to the -LJ script. The approprate scale factor is applied to every input. +LJ script. The appropriate scale factor is applied to every input. Output quantities are printed in both the native real/metal units and unscaled back to LJ units. So that you can see the outputs are the same if you examine the log files. Comments about this comparison @@ -49,6 +49,6 @@ identical input script in an alternate set of units. Where "identical" means it runs the same simulation in a statistical sense. You can find the full set of scale factors LAMMPS uses internally for -different unit systems it supports, at the top of the src/udpate.cpp +different unit systems it supports, at the top of the src/update.cpp file. A couple of those values are used in the real and metal scripts. diff --git a/examples/USER/atc/README b/examples/USER/atc/README index aa874f3300..73996edb9a 100644 --- a/examples/USER/atc/README +++ b/examples/USER/atc/README @@ -68,7 +68,7 @@ elastic: in.cnt_electrostatic2 - Mechanical response of CNT with self-consistent charge density and electric field in.cnt_fixed_charge - Mechancial response of CNT with fixed atomic charges in an electric field in.eam_energy - Quasi-static/quasi-1D coupling and transfer extraction of energy density for EAM gold - in.electron_density - Mechanical response of differnt CNT models with a self-consistent electron density and electric field + in.electron_density - Mechanical response of different CNT models with a self-consistent electron density and electric field in.electrostatic_bending_dos - Quasi-static bending of a CNT using a quantum density of states model for electron density in.no_atoms - FE solution of a box subject to an initial displacement condition in.no_atoms_cb - FE solution of a box subject to an initial displacement condition with a Cauchy-Born material model @@ -149,7 +149,7 @@ elastic: in.cnt_electrostatic2 - Mechanical response of CNT with self-consistent charge density and electric field in.cnt_fixed_charge - Mechancial response of CNT with fixed atomic charges in an electric field in.eam_energy - Quasi-static/quasi-1D coupling and transfer extraction of energy density for EAM gold - in.electron_density - Mechanical response of differnt CNT models with a self-consistent electron density and electric field + in.electron_density - Mechanical response of different CNT models with a self-consistent electron density and electric field in.electrostatic_bending_dos - Quasi-static bending of a CNT using a quantum density of states model for electron density in.no_atoms - FE solution of a box subject to an initial displacement condition in.no_atoms_cb - FE solution of a box subject to an initial displacement condition with a Cauchy-Born material model diff --git a/examples/USER/atc/fluids/in.bar1d_fluids b/examples/USER/atc/fluids/in.bar1d_fluids index af152bfbab..79a6c8a4c2 100644 --- a/examples/USER/atc/fluids/in.bar1d_fluids +++ b/examples/USER/atc/fluids/in.bar1d_fluids @@ -85,7 +85,7 @@ fix_modify AtC control localized_lambda on fix_modify AtC filter type exponential fix_modify AtC filter scale 1000.0 fix_modify AtC filter on -# ouput commands +# output commands fix_modify AtC output bar1d_fluidsFE 100 text #undump D1 #dump D2 all atom 200 dump.bar1d diff --git a/examples/USER/atc/fluids/in.conducting_interface b/examples/USER/atc/fluids/in.conducting_interface index 7ee906e45a..c534231fca 100644 --- a/examples/USER/atc/fluids/in.conducting_interface +++ b/examples/USER/atc/fluids/in.conducting_interface @@ -1,6 +1,6 @@ # simulation of negatively charge liquid argon-positively charged solid/frozen argon # MAKE this conducting_interface then interface (major difference: non-uniform grid) -# START with extrinsic charges on both and then use an instrinsic charge density for frozen +# START with extrinsic charges on both and then use an intrinsic charge density for frozen echo both units real atom_style full diff --git a/examples/USER/atc/fluids/in.dielectric_interface b/examples/USER/atc/fluids/in.dielectric_interface index e9cbe7882a..dd6034a0cc 100644 --- a/examples/USER/atc/fluids/in.dielectric_interface +++ b/examples/USER/atc/fluids/in.dielectric_interface @@ -1,6 +1,6 @@ # simulation of negatively charge liquid argon-positively charged solid/frozen argon # MAKE this dielectric_interface then interface (major difference: non-uniform grid) -# START with extrinsic charges on both and then use an instrinsic charge density for frozen +# START with extrinsic charges on both and then use an intrinsic charge density for frozen echo both units real atom_style full diff --git a/examples/USER/atc/fluids/in.shear_flow b/examples/USER/atc/fluids/in.shear_flow index c5a53b1273..3c06676c64 100644 --- a/examples/USER/atc/fluids/in.shear_flow +++ b/examples/USER/atc/fluids/in.shear_flow @@ -75,7 +75,7 @@ fix_modify AtC control localized_lambda on #fix_modify AtC filter scale 1000.0 #fix_modify AtC filter on -# ouput commands +# output commands fix_modify AtC output shear_flowFE 100 text #binary #undump D1 #dump D1 all custom 100 shear_flow.dmp id type xs ys zs vx vy vz diff --git a/examples/USER/atc/fluids/in.shear_no_atoms b/examples/USER/atc/fluids/in.shear_no_atoms index 8bd350f06c..6c778578c9 100644 --- a/examples/USER/atc/fluids/in.shear_no_atoms +++ b/examples/USER/atc/fluids/in.shear_no_atoms @@ -25,7 +25,7 @@ fix_modify AtC reset_time fix_modify AtC fix velocity y rbc 0.1 fix_modify AtC fix velocity y lbc 0. -# ouput commands +# output commands fix_modify AtC output shear_no_atomsFE 200 text binary # set-up non-equilibrium IC thermo 100 diff --git a/examples/USER/atc/thermal/bar1d.screen b/examples/USER/atc/thermal/bar1d.screen index 33f6590e4d..3c7f8db212 100644 --- a/examples/USER/atc/thermal/bar1d.screen +++ b/examples/USER/atc/thermal/bar1d.screen @@ -239,7 +239,7 @@ fix_modify AtC output bar1dFE 100 text binary ATC: Warning : text output can create _LARGE_ files ATC: output custom names: -# ouput command +# output command #dump D1 all atom 1000 dump.bar1d # run with FE reset_timestep 0 diff --git a/examples/USER/atc/thermal/in.bar1d b/examples/USER/atc/thermal/in.bar1d index 5591f7177d..3f70577ec3 100644 --- a/examples/USER/atc/thermal/in.bar1d +++ b/examples/USER/atc/thermal/in.bar1d @@ -71,7 +71,7 @@ thermo 1 run 100 # set up output, should be before a "run" fix_modify AtC output bar1dFE 100 text binary -# ouput command +# output command #dump D1 all atom 1000 dump.bar1d # run with FE reset_timestep 0 diff --git a/examples/USER/atc/thermal/in.bar1d_all_atoms b/examples/USER/atc/thermal/in.bar1d_all_atoms index 2c8851137f..2219b803ec 100644 --- a/examples/USER/atc/thermal/in.bar1d_all_atoms +++ b/examples/USER/atc/thermal/in.bar1d_all_atoms @@ -93,7 +93,7 @@ fix_modify AtC fix_flux temperature lbndy 0.0000000001 fix_modify AtC fix_flux temperature rbndy -0.0000000001 # set up output, should be before a "run" fix_modify AtC output bar1d_all_atomsFE 200 text binary -# ouput command +# output command #dump D1 all atom 1000 dump.bar1d # run with FE reset_timestep 0 diff --git a/examples/USER/atc/thermal/in.bar1d_combined b/examples/USER/atc/thermal/in.bar1d_combined index 767544d2d4..70dafe72be 100644 --- a/examples/USER/atc/thermal/in.bar1d_combined +++ b/examples/USER/atc/thermal/in.bar1d_combined @@ -79,7 +79,7 @@ thermo 100 # set up output, should be before a "run" fix_modify AtC output bar1d_combinedFE 100 text -# ouput command +# output command #dump D1 all atom 100 dump.bar1d_combined # run with FE reset_timestep 0 diff --git a/examples/USER/atc/thermal/in.bar1d_flux b/examples/USER/atc/thermal/in.bar1d_flux index eae32ec5b2..2b79aa6339 100644 --- a/examples/USER/atc/thermal/in.bar1d_flux +++ b/examples/USER/atc/thermal/in.bar1d_flux @@ -71,7 +71,7 @@ fix_modify AtC fix temperature rbc 20. run 100 # set up output, should be before a "run" fix_modify AtC output bar1d_fluxFE 100 text binary -# ouput command +# output command #dump D1 all atom 1000 dump.bar1d # run with FE reset_timestep 0 diff --git a/examples/USER/atc/thermal/in.bar1d_frac_step b/examples/USER/atc/thermal/in.bar1d_frac_step index eddec44b52..e8540d9151 100644 --- a/examples/USER/atc/thermal/in.bar1d_frac_step +++ b/examples/USER/atc/thermal/in.bar1d_frac_step @@ -72,7 +72,7 @@ fix_modify AtC filter scale 1000.0 fix_modify AtC filter on # set up output, should be before a "run" fix_modify AtC output bar1d_frac_stepFE 200 text -# ouput command +# output command #dump D1 all atom 1000 dump.bar1d # run with FE reset_timestep 0 diff --git a/examples/USER/cgdna/README b/examples/USER/cgdna/README index 49b7cd1f84..a403ce0321 100644 --- a/examples/USER/cgdna/README +++ b/examples/USER/cgdna/README @@ -46,7 +46,7 @@ moment of inertia set to the value used in the standalone implementation of oxDNA (M = I = 1). The masses can be set directly in the input and data file, whereas the moment of inertia is set via the diameter of the ellipsoid in the data file and has a value of 3.16227766. -The change of mass and moment of inertia allows direct comparision of +The change of mass and moment of inertia allows direct comparison of trajectory data or time-dependent observables on a per-timestep basis. As mentioned above, the stacking and hydrogen-bonding interactions diff --git a/examples/USER/cgdna/examples/oxDNA2/unique_bp/generate_unique.py b/examples/USER/cgdna/examples/oxDNA2/unique_bp/generate_unique.py index e5141bc47a..0760d24a0b 100644 --- a/examples/USER/cgdna/examples/oxDNA2/unique_bp/generate_unique.py +++ b/examples/USER/cgdna/examples/oxDNA2/unique_bp/generate_unique.py @@ -105,7 +105,7 @@ EXCL_RC2 = 0.335388426126 EXCL_RC3 = 0.52329943261 """ -Define auxillary variables for the construction of a helix +Define auxiliary variables for the construction of a helix """ # center of the double strand COM_CENTRE_DS = POS_BASE + 0.2 @@ -127,7 +127,7 @@ number_to_base = {1 : 'A', 2 : 'C', 3 : 'G', 4 : 'T'} base_to_number = {'A' : 1, 'a' : 1, 'C' : 2, 'c' : 2, 'G' : 3, 'g' : 3, 'T' : 4, 't' : 4} -# auxillary arrays +# auxiliary arrays positions = [] a1s = [] a3s = [] @@ -551,7 +551,7 @@ def read_strands(filename): smallest_n_bases = n_g if smallest_n_bases < N_BASE_TYPES: - print('## Not enough occurances of base types in the sequence for ' + str(N_BASE_TYPES)) + print('## Not enough occurrences of base types in the sequence for ' + str(N_BASE_TYPES)) print('## unique base types, switching to ' + str(smallest_n_bases) + ' unique types') else: smallest_n_bases = N_BASE_TYPES diff --git a/examples/USER/cgdna/util/generate.py b/examples/USER/cgdna/util/generate.py index eb97f482cc..e175455970 100644 --- a/examples/USER/cgdna/util/generate.py +++ b/examples/USER/cgdna/util/generate.py @@ -81,7 +81,7 @@ EXCL_RC2 = 0.335388426126 EXCL_RC3 = 0.52329943261 """ -Define auxillary variables for the construction of a helix +Define auxiliary variables for the construction of a helix """ # center of the double strand CM_CENTER_DS = POS_BASE + 0.2 @@ -103,7 +103,7 @@ number_to_base = {1 : 'A', 2 : 'C', 3 : 'G', 4 : 'T'} base_to_number = {'A' : 1, 'a' : 1, 'C' : 2, 'c' : 2, 'G' : 3, 'g' : 3, 'T' : 4, 't' : 4} -# auxillary arrays +# auxiliary arrays positions = [] a1s = [] a3s = [] diff --git a/examples/USER/diffraction/README b/examples/USER/diffraction/README index 265201beb1..e36062923b 100644 --- a/examples/USER/diffraction/README +++ b/examples/USER/diffraction/README @@ -1,4 +1,4 @@ -This is a simple example of showing the computation of virutal x-ray +This is a simple example of showing the computation of virtual x-ray and electron diffraction patterns for Ni. In addition to the LAMMPS output, a simple visualizaiton of the electron diff --git a/examples/USER/eff/Li-dendritic/README b/examples/USER/eff/Li-dendritic/README index 24eed28f85..4fdaed1efb 100644 --- a/examples/USER/eff/Li-dendritic/README +++ b/examples/USER/eff/Li-dendritic/README @@ -1,2 +1,2 @@ -Shows the formation of lithium dendrites during the minimization of a volume expanded lithium cell with particle positions remaped to fit the cell. +Shows the formation of lithium dendrites during the minimization of a volume expanded lithium cell with particle positions remapped to fit the cell. This depicts the process of electrode replating in lithium batteries, which leads to failure (short-circuit). diff --git a/examples/USER/lb/fourspheres/in.fourspheres_default_gamma b/examples/USER/lb/fourspheres/in.fourspheres_default_gamma index 2fa161aefa..bce9aec0e9 100755 --- a/examples/USER/lb/fourspheres/in.fourspheres_default_gamma +++ b/examples/USER/lb/fourspheres/in.fourspheres_default_gamma @@ -1,5 +1,5 @@ #===========================================================================# -# Sytem of 2 pairs of rigid particles moving towards one another. # +# System of 2 pairs of rigid particles moving towards one another. # # At each timestep, the hydrodynamic force acting on one of these four # # rigid particles is printed to the screen. # # # diff --git a/examples/USER/lb/fourspheres/in.fourspheres_set_gamma b/examples/USER/lb/fourspheres/in.fourspheres_set_gamma index 452d90ba00..8c32051536 100755 --- a/examples/USER/lb/fourspheres/in.fourspheres_set_gamma +++ b/examples/USER/lb/fourspheres/in.fourspheres_set_gamma @@ -1,5 +1,5 @@ #===========================================================================# -# Sytem of 2 pairs of rigid particles moving towards one another. # +# System of 2 pairs of rigid particles moving towards one another. # # At each timestep, the hydrodynamic force acting on one of these four # # rigid particles is printed to the screen. # # # diff --git a/examples/USER/misc/ees/README b/examples/USER/misc/ees/README index 9f4cb4f159..bfc55e4375 100644 --- a/examples/USER/misc/ees/README +++ b/examples/USER/misc/ees/README @@ -5,7 +5,7 @@ Here one may find simple examples showing how "fix wall/ess" and "fix wall/regio This input uses "Data_region" to setup a system of three particles colliding with a cubic region which its walls interact with particle with EES potential. To find out details - of how to set parameters of "fix wall/region/ees" see documentaion. + of how to set parameters of "fix wall/region/ees" see documentation. --in.fix_wall diff --git a/examples/USER/misc/hma/README b/examples/USER/misc/hma/README index 5af6ec15fa..75c24705d3 100644 --- a/examples/USER/misc/hma/README +++ b/examples/USER/misc/hma/README @@ -15,7 +15,7 @@ Averages of the potential energy (#3 and #4) agree although #4 (HMA) is more pre Averages of the pressure (#5 and #6) agree once the ideal gas contribution is included; #6 (HMA) is more precise. -The heat capacity can be computed from colume #3 (convential) as +The heat capacity can be computed from colume #3 (conventional) as Cv = Var(#3)/(k T^2) With HMA, the heat capacity can be computed from column #4 and #7 as diff --git a/examples/USER/plumed/reference/p.log b/examples/USER/plumed/reference/p.log index 29d99077e4..13a63bdbf1 100644 --- a/examples/USER/plumed/reference/p.log +++ b/examples/USER/plumed/reference/p.log @@ -48,7 +48,7 @@ PLUMED: [1] The PLUMED consortium, Nat. Methods 16, 670 (2019) PLUMED: [2] Tribello, Bonomi, Branduardi, Camilloni, and Bussi, Comput. Phys. Commun. 185, 604 (2014) PLUMED: Please read and cite where appropriate! PLUMED: Finished setup -PLUMED: Cycles Total Average Minumum Maximum +PLUMED: Cycles Total Average Minimum Maximum PLUMED: 1 0.010018 0.010018 0.010018 0.010018 PLUMED: 1 Prepare dependencies 102 0.000241 0.000002 0.000001 0.000003 PLUMED: 2 Sharing data 102 0.002132 0.000021 0.000006 0.000151 diff --git a/examples/USER/qtb/methane_qbmsst/methane_qtb.mod b/examples/USER/qtb/methane_qbmsst/methane_qtb.mod index 181fb99d00..65bfc5d7f7 100644 --- a/examples/USER/qtb/methane_qbmsst/methane_qtb.mod +++ b/examples/USER/qtb/methane_qbmsst/methane_qtb.mod @@ -48,7 +48,7 @@ neigh_modify every 10 delay 0 check no ## This part equilibrates liquid methane to a temperature of ${temperature}(unit temperatureture) with quantum nuclear effects -#Initilization +#Initialization velocity all create ${temperature} 93 dist gaussian sum no mom yes rot yes loop all #Setup output diff --git a/examples/USER/qtb/methane_qtb/methane_qtb.in b/examples/USER/qtb/methane_qtb/methane_qtb.in index f0ea94a221..e31f0695b9 100644 --- a/examples/USER/qtb/methane_qtb/methane_qtb.in +++ b/examples/USER/qtb/methane_qtb/methane_qtb.in @@ -54,7 +54,7 @@ neigh_modify every 10 delay 0 check no ## This part equilibrates liquid methane to a temperature of ${temperature}(unit temperatureture) with quantum nuclear effects -#Initilization +#Initialization velocity all create ${temperature} 93 dist gaussian sum no mom yes rot yes loop all #Setup output diff --git a/examples/USER/quip/in.molecular b/examples/USER/quip/in.molecular index 4253399d7c..08921ef865 100644 --- a/examples/USER/quip/in.molecular +++ b/examples/USER/quip/in.molecular @@ -17,7 +17,7 @@ pair_style hybrid/overlay lj/cut 8.0 quip special_bonds lj/coul 0.999999999 0.999999999 0.999999999 # Intermolecular: OPLS (JACS 118 (45), p. 11225 (1996)) -# Coulomb interactions ommitted for simplicity +# Coulomb interactions omitted for simplicity pair_coeff 1 1 lj/cut 0.0028619844 3.5 # CT pair_coeff 2 2 lj/cut 0.0013009018 2.5 # HC pair_coeff 1 2 lj/cut 0.0019295487 2.95 diff --git a/examples/USER/quip/log.24Jul17.molecular.g++.1 b/examples/USER/quip/log.24Jul17.molecular.g++.1 index 28fc63579b..ca1b83c268 100644 --- a/examples/USER/quip/log.24Jul17.molecular.g++.1 +++ b/examples/USER/quip/log.24Jul17.molecular.g++.1 @@ -39,7 +39,7 @@ special_bonds lj/coul 0.999999999 0.999999999 0.999999999 4 = max # of special neighbors # Intermolecular: OPLS (JACS 118 (45), p. 11225 (1996)) -# Coulomb interactions ommitted for simplicity +# Coulomb interactions omitted for simplicity pair_coeff 1 1 lj/cut 0.0028619844 3.5 # CT pair_coeff 2 2 lj/cut 0.0013009018 2.5 # HC pair_coeff 1 2 lj/cut 0.0019295487 2.95 diff --git a/examples/USER/quip/log.24Jul17.molecular.g++.4 b/examples/USER/quip/log.24Jul17.molecular.g++.4 index a8be8e77bb..2226e45bfb 100644 --- a/examples/USER/quip/log.24Jul17.molecular.g++.4 +++ b/examples/USER/quip/log.24Jul17.molecular.g++.4 @@ -39,7 +39,7 @@ special_bonds lj/coul 0.999999999 0.999999999 0.999999999 4 = max # of special neighbors # Intermolecular: OPLS (JACS 118 (45), p. 11225 (1996)) -# Coulomb interactions ommitted for simplicity +# Coulomb interactions omitted for simplicity pair_coeff 1 1 lj/cut 0.0028619844 3.5 # CT pair_coeff 2 2 lj/cut 0.0013009018 2.5 # HC pair_coeff 1 2 lj/cut 0.0019295487 2.95 diff --git a/examples/USER/smd/aluminum_strip_pull/aluminum_strip_pull.lmp b/examples/USER/smd/aluminum_strip_pull/aluminum_strip_pull.lmp index b75bab10e9..50b20a0787 100644 --- a/examples/USER/smd/aluminum_strip_pull/aluminum_strip_pull.lmp +++ b/examples/USER/smd/aluminum_strip_pull/aluminum_strip_pull.lmp @@ -2,7 +2,7 @@ # # TLSPH example: elongate a 2d strip of aluminum py pulling its ends apart # -# unit sytem: GPa / mm / ms +# unit system: GPa / mm / ms # #################################################################################################### @@ -18,7 +18,7 @@ variable q2 equal 0.0 # standard artificial viscosity quadratic coeffici variable hg equal 10.0 # hourglass control coefficient variable cp equal 1.0 # heat capacity of material -- not used here -variable JC_A equal 0.3241 # Johnson Cook arameters +variable JC_A equal 0.3241 # Johnson Cook parameters variable JC_B equal 0.1138 variable JC_N equal 0.42 variable JC_C equal 0 #0.002 diff --git a/examples/USER/smd/fluid_structure_interaction/fluid_structure_interaction.lmp b/examples/USER/smd/fluid_structure_interaction/fluid_structure_interaction.lmp index 0f7d726e21..e4f3ea603a 100644 --- a/examples/USER/smd/fluid_structure_interaction/fluid_structure_interaction.lmp +++ b/examples/USER/smd/fluid_structure_interaction/fluid_structure_interaction.lmp @@ -4,7 +4,7 @@ # # A column of water is placed in a container and allowed to collapse unter the # influence of gravity. Several solid objects are also placed in the container. -# The water flow pushes the solid objects around until the sytem comes to halt due to +# The water flow pushes the solid objects around until the system comes to halt due to # viscous damping. The solid objects have a lower mass density than water and finally float on # the water surface. # @@ -12,7 +12,7 @@ # Total Lagrangian formalism. Contact forces between container, solid bodies, and water prevent # mutual penetration of these physical entities. # -# unit sytem: GPa / mm / ms +# unit system: GPa / mm / ms # #################################################################################################### diff --git a/examples/USER/smd/funnel_flow/funnel_flow.lmp b/examples/USER/smd/funnel_flow/funnel_flow.lmp index 7cc1e13f4f..b1fde2c2db 100644 --- a/examples/USER/smd/funnel_flow/funnel_flow.lmp +++ b/examples/USER/smd/funnel_flow/funnel_flow.lmp @@ -5,7 +5,7 @@ # The boundary dump file (see below) can be converted into VTK format using the conversion # tool dump2vtk_tris from the tools/smd directory. # -# unit sytem: GPa / mm / ms +# unit system: GPa / mm / ms # #################################################################################################### diff --git a/examples/USER/smd/rubber_rings_3d/rubber_rings_3d.lmp b/examples/USER/smd/rubber_rings_3d/rubber_rings_3d.lmp index 956abd6c4a..11b988e818 100644 --- a/examples/USER/smd/rubber_rings_3d/rubber_rings_3d.lmp +++ b/examples/USER/smd/rubber_rings_3d/rubber_rings_3d.lmp @@ -3,7 +3,7 @@ # # TLSPH example: Two rubber rings impact each other. # -# unit sytem: GPa / mm / ms +# unit system: GPa / mm / ms # #################################################################################################### diff --git a/examples/USER/smd/rubber_strip_pull/rubber_strip_pull.lmp b/examples/USER/smd/rubber_strip_pull/rubber_strip_pull.lmp index 4e53daf993..0e8be3b9da 100644 --- a/examples/USER/smd/rubber_strip_pull/rubber_strip_pull.lmp +++ b/examples/USER/smd/rubber_strip_pull/rubber_strip_pull.lmp @@ -2,7 +2,7 @@ # # TLSPH example: elongate a 2d strip of a linear elastic material py pulling its ends apart # -# unit sytem: GPa / mm / ms +# unit system: GPa / mm / ms # #################################################################################################### diff --git a/examples/USER/tally/in.pe b/examples/USER/tally/in.pe index c6228cebd0..a7a3360c44 100644 --- a/examples/USER/tally/in.pe +++ b/examples/USER/tally/in.pe @@ -37,7 +37,7 @@ group hyd type 2 compute epa oxy group/group hyd pair yes kspace no boundary no # tally pairwise energy between all oygen and all hydrogen compute c1 oxy pe/tally hyd -# tally pairwise energy beween all atoms to compare with globals +# tally pairwise energy between all atoms to compare with globals compute c2 all pe/tally all # collect per atom energies compute c3 all pe/atom pair diff --git a/examples/USER/tally/log.12Jun17.pe.1 b/examples/USER/tally/log.12Jun17.pe.1 index 8b0f753414..ecdaee86d5 100644 --- a/examples/USER/tally/log.12Jun17.pe.1 +++ b/examples/USER/tally/log.12Jun17.pe.1 @@ -89,7 +89,7 @@ group hyd type 2 compute epa oxy group/group hyd pair yes kspace no boundary no # tally pairwise energy between all oygen and all hydrogen compute c1 oxy pe/tally hyd -# tally pairwise energy beween all atoms to compare with globals +# tally pairwise energy between all atoms to compare with globals compute c2 all pe/tally all # collect per atom energies compute c3 all pe/atom pair diff --git a/examples/USER/tally/log.12Jun17.pe.4 b/examples/USER/tally/log.12Jun17.pe.4 index f684fabe01..242cad77f3 100644 --- a/examples/USER/tally/log.12Jun17.pe.4 +++ b/examples/USER/tally/log.12Jun17.pe.4 @@ -89,7 +89,7 @@ group hyd type 2 compute epa oxy group/group hyd pair yes kspace no boundary no # tally pairwise energy between all oygen and all hydrogen compute c1 oxy pe/tally hyd -# tally pairwise energy beween all atoms to compare with globals +# tally pairwise energy between all atoms to compare with globals compute c2 all pe/tally all # collect per atom energies compute c3 all pe/atom pair diff --git a/examples/hugoniostat/in.hugoniostat b/examples/hugoniostat/in.hugoniostat index 01c2a246fc..571f92b59e 100644 --- a/examples/hugoniostat/in.hugoniostat +++ b/examples/hugoniostat/in.hugoniostat @@ -67,7 +67,7 @@ fix myhug all nphug temp 1.0 1.0 10.0 z 40.0 40.0 70.0 drag 0.0 tchain 1 pchain fix_modify myhug e0 -6334.0 p0 0.0 v0 680.73519 -# Add fix energy to ouput etotal +# Add fix energy to output etotal fix_modify myhug energy yes @@ -115,7 +115,7 @@ fix myhug all nphug temp 1.0 1.0 1.0 z 40.0 40.0 70.0 drag 200.0 tchain 1 pchain fix_modify myhug e0 -6334.0 p0 0.0 v0 680.73519 -# Add fix energy to ouput etotal +# Add fix energy to output etotal fix_modify myhug energy yes @@ -153,7 +153,7 @@ fix myhug all nphug temp 1.0 1.0 1.0 z 40.0 40.0 70.0 fix_modify myhug e0 -6334.0 p0 0.0 v0 680.73519 -# Add fix energy to ouput etotal +# Add fix energy to output etotal fix_modify myhug energy yes diff --git a/examples/hugoniostat/log.27Nov18.hugoniostat.g++.1 b/examples/hugoniostat/log.27Nov18.hugoniostat.g++.1 index 2473641dea..c1381629eb 100644 --- a/examples/hugoniostat/log.27Nov18.hugoniostat.g++.1 +++ b/examples/hugoniostat/log.27Nov18.hugoniostat.g++.1 @@ -129,7 +129,7 @@ fix myhug all nphug temp 1.0 1.0 10.0 z 40.0 40.0 70.0 drag 0.0 tchain 1 pchain fix_modify myhug e0 -6334.0 p0 0.0 v0 680.73519 -# Add fix energy to ouput etotal +# Add fix energy to output etotal fix_modify myhug energy yes @@ -232,7 +232,7 @@ fix myhug all nphug temp 1.0 1.0 1.0 z 40.0 40.0 70.0 drag 200.0 tchain 1 pchain fix_modify myhug e0 -6334.0 p0 0.0 v0 680.73519 -# Add fix energy to ouput etotal +# Add fix energy to output etotal fix_modify myhug energy yes @@ -327,7 +327,7 @@ fix myhug all nphug temp 1.0 1.0 1.0 z 40.0 40.0 70.0 fix_modify myhug e0 -6334.0 p0 0.0 v0 680.73519 -# Add fix energy to ouput etotal +# Add fix energy to output etotal fix_modify myhug energy yes diff --git a/examples/hugoniostat/log.27Nov18.hugoniostat.g++.4 b/examples/hugoniostat/log.27Nov18.hugoniostat.g++.4 index 30f1335ea9..dd0766e81a 100644 --- a/examples/hugoniostat/log.27Nov18.hugoniostat.g++.4 +++ b/examples/hugoniostat/log.27Nov18.hugoniostat.g++.4 @@ -129,7 +129,7 @@ fix myhug all nphug temp 1.0 1.0 10.0 z 40.0 40.0 70.0 drag 0.0 tchain 1 pchain fix_modify myhug e0 -6334.0 p0 0.0 v0 680.73519 -# Add fix energy to ouput etotal +# Add fix energy to output etotal fix_modify myhug energy yes @@ -232,7 +232,7 @@ fix myhug all nphug temp 1.0 1.0 1.0 z 40.0 40.0 70.0 drag 200.0 tchain 1 pchain fix_modify myhug e0 -6334.0 p0 0.0 v0 680.73519 -# Add fix energy to ouput etotal +# Add fix energy to output etotal fix_modify myhug energy yes @@ -327,7 +327,7 @@ fix myhug all nphug temp 1.0 1.0 1.0 z 40.0 40.0 70.0 fix_modify myhug e0 -6334.0 p0 0.0 v0 680.73519 -# Add fix energy to ouput etotal +# Add fix energy to output etotal fix_modify myhug energy yes diff --git a/examples/reax/HNS/README.txt b/examples/reax/HNS/README.txt index 465d64d171..95ffbb0ebb 100644 --- a/examples/reax/HNS/README.txt +++ b/examples/reax/HNS/README.txt @@ -17,7 +17,7 @@ Questions: Mitchell Wood, mitwood@sandia.gov The type of simulation is set by the 'fix' commands, dynamic charges are controlled with 'fix qeq' and the integration style is given as 'fix nve' here. More information about each of the individual commands can be found online at lammps.sandia.gov in the user manual section. - *There are four free varaibles in this file, three of which control the size of the simulation and the last will dictate how many MD time steps are taken. + *There are four free variables in this file, three of which control the size of the simulation and the last will dictate how many MD time steps are taken. *The size of the system is controlled by the 'replicate' command given the values of $x, $y and $z. *The number of timesteps taken is controlled by the 'run' command given the value of $t diff --git a/lib/atc/ATC_Coupling.cpp b/lib/atc/ATC_Coupling.cpp index 9468064f8d..db72b0cb0c 100644 --- a/lib/atc/ATC_Coupling.cpp +++ b/lib/atc/ATC_Coupling.cpp @@ -625,7 +625,7 @@ namespace ATC { /*! \page man_consistent_fe_initialization fix_modify AtC consistent_fe_initialization \section syntax fix_modify AtC consistent_fe_initialization - - = switch to activiate/deactiviate the intial setting of FE intrinsic field to match the projected MD field + - = switch to activiate/deactiviate the initial setting of FE intrinsic field to match the projected MD field \section examples fix_modify atc consistent_fe_initialization on \section description diff --git a/lib/atc/ATC_Coupling.h b/lib/atc/ATC_Coupling.h index 3816a82798..9f406febbe 100644 --- a/lib/atc/ATC_Coupling.h +++ b/lib/atc/ATC_Coupling.h @@ -227,7 +227,7 @@ namespace ATC { void set_mass_mat_time_filter(FieldName thisField,TimeFilterManager::FilterIntegrationType filterIntegrationType); - /** return referece to ExtrinsicModelManager */ + /** return reference to ExtrinsicModelManager */ ExtrinsicModelManager & extrinsic_model_manager() { return extrinsicModelManager_; } /** access to time integrator */ diff --git a/lib/atc/ATC_CouplingEnergy.cpp b/lib/atc/ATC_CouplingEnergy.cpp index 0338054902..c3b07c242d 100644 --- a/lib/atc/ATC_CouplingEnergy.cpp +++ b/lib/atc/ATC_CouplingEnergy.cpp @@ -364,7 +364,7 @@ namespace ATC { (_tiIt_->second)->post_process(); } - // auxilliary data + // auxiliary data for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) { (_tiIt_->second)->output(outputData); } diff --git a/lib/atc/ATC_CouplingMass.cpp b/lib/atc/ATC_CouplingMass.cpp index 801752d569..d36643e590 100644 --- a/lib/atc/ATC_CouplingMass.cpp +++ b/lib/atc/ATC_CouplingMass.cpp @@ -221,7 +221,7 @@ namespace ATC { (_tiIt_->second)->post_process(); } - // auxilliary data + // auxiliary data for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) { (_tiIt_->second)->output(outputData); } diff --git a/lib/atc/ATC_CouplingMomentum.cpp b/lib/atc/ATC_CouplingMomentum.cpp index f59aa525cb..6757245119 100644 --- a/lib/atc/ATC_CouplingMomentum.cpp +++ b/lib/atc/ATC_CouplingMomentum.cpp @@ -325,7 +325,7 @@ namespace ATC { (_tiIt_->second)->post_process(); } - // auxilliary data + // auxiliary data for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) { (_tiIt_->second)->output(outputData); } diff --git a/lib/atc/ATC_CouplingMomentumEnergy.cpp b/lib/atc/ATC_CouplingMomentumEnergy.cpp index bf0edc71fb..1fc2931977 100644 --- a/lib/atc/ATC_CouplingMomentumEnergy.cpp +++ b/lib/atc/ATC_CouplingMomentumEnergy.cpp @@ -446,7 +446,7 @@ namespace ATC { (_tiIt_->second)->post_process(); } - // auxilliary data + // auxiliary data for (_tiIt_ = timeIntegrators_.begin(); _tiIt_ != timeIntegrators_.end(); ++_tiIt_) { (_tiIt_->second)->output(outputData); diff --git a/lib/atc/ATC_Method.cpp b/lib/atc/ATC_Method.cpp index 5d61a7bed8..f2173e9575 100644 --- a/lib/atc/ATC_Method.cpp +++ b/lib/atc/ATC_Method.cpp @@ -693,12 +693,12 @@ pecified /*! \page man_boundary fix_modify AtC boundary \section syntax fix_modify AtC boundary type - - = type id for atoms that represent a ficticious + - = type id for atoms that represent a fictitious boundary internal to the FE mesh \section examples fix_modify AtC boundary type ghost_atoms \section description - Command to define the atoms that represent the ficticious + Command to define the atoms that represent the fictitious boundary internal to the FE mesh. For fully overlapped MD/FE domains with periodic boundary conditions no boundary atoms should be defined. diff --git a/lib/atc/ATC_Transfer.cpp b/lib/atc/ATC_Transfer.cpp index c876f46634..833e1d1f27 100644 --- a/lib/atc/ATC_Transfer.cpp +++ b/lib/atc/ATC_Transfer.cpp @@ -148,7 +148,7 @@ namespace ATC { } if (!initialized_ || ATC::LammpsInterface::instance()->atoms_sorted() || resetKernelFunction_) { - // initialize kernel funciton matrix N_Ia + // initialize kernel function matrix N_Ia if (! kernelOnTheFly_) { try{ if (!moleculeIds_.empty()) compute_kernel_matrix_molecule(); //KKM add @@ -654,7 +654,7 @@ namespace ATC { fix_modify AtC gradients add temperature velocity stress \n fix_modify AtC gradients delete velocity \n \section description - Requests calculation and ouput of gradients of the fields from the + Requests calculation and output of gradients of the fields from the transfer class. These gradients will be with regard to spatial or material coordinate for eulerian or lagrangian analysis, respectively, as specified by atom_element_map (see \ref man_atom_element_map ) @@ -698,7 +698,7 @@ namespace ATC { fix_modify AtC rates add temperature velocity stress \n fix_modify AtC rates delete stress \n \section description - Requests calculation and ouput of rates (time derivatives) of the fields from the + Requests calculation and output of rates (time derivatives) of the fields from the transfer class. For eulerian analysis (see \ref man_atom_element_map ), these rates are the partial time derivatives of the nodal fields, not the full (material) time derivatives. \n @@ -865,7 +865,7 @@ namespace ATC { } //------------------------------------------------------------------- - // called at the begining of second half timestep + // called at the beginning of second half timestep // REFACTOR move this to post_neighbor void ATC_Transfer::pre_final_integrate() { diff --git a/lib/atc/AtomToMoleculeTransfer.h b/lib/atc/AtomToMoleculeTransfer.h index c6523137a7..c628ee356f 100644 --- a/lib/atc/AtomToMoleculeTransfer.h +++ b/lib/atc/AtomToMoleculeTransfer.h @@ -217,7 +217,7 @@ namespace ATC { /** reference to shape function matrix */ SPAR_MAN * shapeFunction_; - /** persistant workspace */ + /** persistent workspace */ mutable DENS_MAT _workspace_; diff --git a/lib/atc/AtomicRegulator.h b/lib/atc/AtomicRegulator.h index 8fb7de1006..b9fccb902c 100644 --- a/lib/atc/AtomicRegulator.h +++ b/lib/atc/AtomicRegulator.h @@ -585,7 +585,7 @@ namespace ATC { protected: - /** lumped version of the matrix governing lamda */ + /** lumped version of the matrix governing lambda */ DIAG_MAT lumpedMatrix_; /** set of regulated nodes */ diff --git a/lib/atc/CbPotential.h b/lib/atc/CbPotential.h index e218ae2254..1d5386fcd5 100644 --- a/lib/atc/CbPotential.h +++ b/lib/atc/CbPotential.h @@ -7,7 +7,7 @@ namespace ATC enum Interaction{PAIRWISE=1, EAM=2, THREE_BDY=4, ANGLE_BND=8}; //! Booleans that enable types of terms the potential uses. struct Interactions { - //! Enables up to 3 interaction types. (order independant) + //! Enables up to 3 interaction types. (order independent) Interactions(int a=0, int b=0, int c=0); bool pairwise; //!< Pairwise interaction terms exist. bool embedding; //!< Embedding interaction terms (EAM) exist. diff --git a/lib/atc/ChargeRegulator.cpp b/lib/atc/ChargeRegulator.cpp index cbfda69480..bae78a7613 100644 --- a/lib/atc/ChargeRegulator.cpp +++ b/lib/atc/ChargeRegulator.cpp @@ -214,7 +214,7 @@ namespace ATC { qV2e_ = lammpsInterface_->qv2e(); qqrd2e_ = lammpsInterface_->qqrd2e(); - // note derived method set intialized to true + // note derived method set initialized to true } @@ -327,7 +327,7 @@ namespace ATC { // - if (nInfluenceNodes_ < nControlNodes_) throw ATC_Error(" least square not implmented "); + if (nInfluenceNodes_ < nControlNodes_) throw ATC_Error(" least square not implemented "); if (nInfluenceNodes_ > nControlNodes_) throw ATC_Error(" solve not possible "); DENS_MAT G(nInfluenceNodes_,nControlNodes_); DENS_VEC G_I; diff --git a/lib/atc/ConcentrationRegulator.cpp b/lib/atc/ConcentrationRegulator.cpp index 8055433f5d..4255b919b9 100644 --- a/lib/atc/ConcentrationRegulator.cpp +++ b/lib/atc/ConcentrationRegulator.cpp @@ -263,7 +263,7 @@ const double kMinScale_ = 10000.; volumes_(i) += volumes_(i-1); } - // record orginal energetic properties + // record original energetic properties int ntypes = lammpsInterface_->ntypes(); epsilon0_.reset(ntypes); p_ = lammpsInterface_->potential(); diff --git a/lib/atc/DiagonalMatrix.h b/lib/atc/DiagonalMatrix.h index 6c2fe23144..ca3001f225 100644 --- a/lib/atc/DiagonalMatrix.h +++ b/lib/atc/DiagonalMatrix.h @@ -472,7 +472,7 @@ inline DiagonalMatrix inv(const DiagonalMatrix& A) return A.inv(); } //----------------------------------------------------------------------------- -// general diagonalmatrix assigment +// general diagonalmatrix assignment //----------------------------------------------------------------------------- template void DiagonalMatrix::_set_equal(const Matrix &r) diff --git a/lib/atc/ElasticTimeIntegrator.cpp b/lib/atc/ElasticTimeIntegrator.cpp index 9793f6a58e..5e11f1584c 100644 --- a/lib/atc/ElasticTimeIntegrator.cpp +++ b/lib/atc/ElasticTimeIntegrator.cpp @@ -91,7 +91,7 @@ namespace ATC { atc_->set_mass_mat_time_filter(MOMENTUM,TimeFilterManager::EXPLICIT_IMPLICIT); break; default: - throw ATC_Error("Uknown time integration type in ThermalTimeIntegrator::Initialize()"); + throw ATC_Error("Unknown time integration type in ThermalTimeIntegrator::Initialize()"); } } @@ -102,7 +102,7 @@ namespace ATC { break; } default: - throw ATC_Error("Uknown time integration type in MomentumTimeIntegrator::Initialize()"); + throw ATC_Error("Unknown time integration type in MomentumTimeIntegrator::Initialize()"); } } else { @@ -120,7 +120,7 @@ namespace ATC { break; } default: - throw ATC_Error("Uknown time integration type in MomentumTimeIntegrator::Initialize()"); + throw ATC_Error("Unknown time integration type in MomentumTimeIntegrator::Initialize()"); } } } diff --git a/lib/atc/ElectronHeatFlux.h b/lib/atc/ElectronHeatFlux.h index 41c89d6c6d..d0bc2a44f2 100644 --- a/lib/atc/ElectronHeatFlux.h +++ b/lib/atc/ElectronHeatFlux.h @@ -126,7 +126,7 @@ namespace ATC { /** * @class ElectronHeatFluxThermopower * @brief Class for an electron heat flux proportional to the temperature gradient but with a condu -ctivity proportional to the ratio of the electron and phonon temperatures with the thermopower from teh electric current included +ctivity proportional to the ratio of the electron and phonon temperatures with the thermopower from the electric current included */ class ElectronHeatFluxThermopower : public ElectronHeatFlux diff --git a/lib/atc/ExtrinsicModelElectrostatic.cpp b/lib/atc/ExtrinsicModelElectrostatic.cpp index b10e77a306..ef3aa52dee 100644 --- a/lib/atc/ExtrinsicModelElectrostatic.cpp +++ b/lib/atc/ExtrinsicModelElectrostatic.cpp @@ -144,7 +144,7 @@ namespace ATC { } } - /** switch to account for short range interaces */ + /** switch to account for short range interfaces */ else if (strcmp(arg[argIndx],"short_range")==0) { argIndx++; if (strcmp(arg[argIndx],"on")==0) { diff --git a/lib/atc/ExtrinsicModelElectrostatic.h b/lib/atc/ExtrinsicModelElectrostatic.h index c4a0af464d..86cba31471 100644 --- a/lib/atc/ExtrinsicModelElectrostatic.h +++ b/lib/atc/ExtrinsicModelElectrostatic.h @@ -92,7 +92,7 @@ namespace ATC { /** rhs mask for Poisson solver */ Array2D rhsMask_; - /** estimate instrinsic charge density */ + /** estimate intrinsic charge density */ void add_electrostatic_forces(MATRIX & nodalPotential); /** correct short range FE electric field */ diff --git a/lib/atc/FE_Element.cpp b/lib/atc/FE_Element.cpp index 9eec08c483..0d2fc036c7 100644 --- a/lib/atc/FE_Element.cpp +++ b/lib/atc/FE_Element.cpp @@ -408,7 +408,7 @@ static const double localCoordinatesTolerance = 1.e-09; throw ATC_Error("Unrecognized interpolation order specified " "for element class: \n" " element only knows how to construct lin " - "and quad elments."); + "and quad elements."); } localCoords_.resize(nSD_,numNodes_); @@ -637,7 +637,7 @@ static const double localCoordinatesTolerance = 1.e-09; throw ATC_Error("Unrecognized interpolation order specified " "for element class: \n" " element only knows how to construct lin " - "and quad elments."); + "and quad elements."); } localCoords_.resize(nSD_+1, numNodes_); diff --git a/lib/atc/FE_Engine.cpp b/lib/atc/FE_Engine.cpp index bef135a5f2..5e01709b19 100644 --- a/lib/atc/FE_Engine.cpp +++ b/lib/atc/FE_Engine.cpp @@ -349,7 +349,7 @@ namespace ATC{ else throw ATC_Error("not enough element partitions"); } } - // each segment of the piecewise funcion is length-normalized separately + // each segment of the piecewise function is length-normalized separately else if (strcmp(arg[argIdx],"position-number-density")==0) { argIdx++; double *y = new double[nx]; diff --git a/lib/atc/FE_Engine.h b/lib/atc/FE_Engine.h index 18dae0e6b4..eb59f04eef 100644 --- a/lib/atc/FE_Engine.h +++ b/lib/atc/FE_Engine.h @@ -510,7 +510,7 @@ namespace ATC { /** finite element mesh */ FE_Mesh *feMesh_; - /** auxillary kernel function */ + /** auxiliary kernel function */ KernelFunction *kernelFunction_; /** initialized flag */ diff --git a/lib/atc/FE_Interpolate.cpp b/lib/atc/FE_Interpolate.cpp index 19753a8007..5e5bd5ecf1 100644 --- a/lib/atc/FE_Interpolate.cpp +++ b/lib/atc/FE_Interpolate.cpp @@ -564,7 +564,7 @@ namespace ATC { N = 1.0; dNdr = 1.0; - // mapping returns the 1d nodes in each dimension that sould be multiplied + // mapping returns the 1d nodes in each dimension that should be multiplied // to achieve the shape functions in 3d vector mapping(nSD_); for (int inode=0; inodeneedReset_ = true;}; /** specialized reset to account for forcing lammps to perform the compute */ diff --git a/lib/atc/GhostManager.cpp b/lib/atc/GhostManager.cpp index 3c9e54b4f5..77594ec406 100644 --- a/lib/atc/GhostManager.cpp +++ b/lib/atc/GhostManager.cpp @@ -523,7 +523,7 @@ namespace ATC { { compute_distances(); int nlayers = find_layers(); - if (nlayers > ((int)gamma_.size())) throw ATC_Error("GhostModifierDampedHarmonicLayers::initialize not enough damping factors specfied " + to_string(gamma_.size())); + if (nlayers > ((int)gamma_.size())) throw ATC_Error("GhostModifierDampedHarmonicLayers::initialize not enough damping factors specified " + to_string(gamma_.size())); } //-------------------------------------------------------- diff --git a/lib/atc/InterscaleOperators.cpp b/lib/atc/InterscaleOperators.cpp index 0e218bdef4..f1e5607b6e 100644 --- a/lib/atc/InterscaleOperators.cpp +++ b/lib/atc/InterscaleOperators.cpp @@ -157,7 +157,7 @@ namespace ATC{ bool isTemporary = (quantity->memory_type()==TEMPORARY); for (it = (quantity->dependentQuantities_).begin(); it != (quantity->dependentQuantities_).end(); it++) { - // make sure that if quantity isn't persistent, none of it's depedencies are + // make sure that if quantity isn't persistent, none of it's dependencies are if ((*it)->memory_type()==PERSISTENT && isTemporary) { throw ATC_Error("InterscaleManager::dfs_visit - a persistent quantity has a temporary dependency"); } diff --git a/lib/atc/InterscaleOperators.h b/lib/atc/InterscaleOperators.h index 0ddca1dc67..3a4d81212e 100644 --- a/lib/atc/InterscaleOperators.h +++ b/lib/atc/InterscaleOperators.h @@ -245,19 +245,19 @@ namespace ATC { /** container for molecule sets */ std::map smallMoleculeSets_; - /** container for atomic quantities which must be transfered when atoms cross processors */ + /** container for atomic quantities which must be transferred when atoms cross processors */ std::set *> exchangeList_; - /** container for atomic quantities which must be transfered to ghost atoms on other processors */ + /** container for atomic quantities which must be transferred to ghost atoms on other processors */ std::vector *> commList_; - /** container for integer atomic quantities which must be transfered to ghost atoms on other processors */ + /** container for integer atomic quantities which must be transferred to ghost atoms on other processors */ std::vector *> commIntList_; - /** container for atomic diagonal matrices which must be transfered to ghost atoms on other processors */ + /** container for atomic diagonal matrices which must be transferred to ghost atoms on other processors */ std::vector *> commDmList_; - /** container for atomic sparse matrices which must be transfered to ghost atoms on other processors */ + /** container for atomic sparse matrices which must be transferred to ghost atoms on other processors */ std::vector *> commSmList_; /** prefix for labeling associated lammps arrays */ @@ -329,7 +329,7 @@ namespace ATC { (it->second)->set_memory_type(TEMPORARY); } - /** helper function to perform intialization for dfs of a list */ + /** helper function to perform initialization for dfs of a list */ template void dfs_prepare_loop(std::map & list) { diff --git a/lib/atc/KinetoThermostat.h b/lib/atc/KinetoThermostat.h index 6f7d113734..bc40f19ed1 100644 --- a/lib/atc/KinetoThermostat.h +++ b/lib/atc/KinetoThermostat.h @@ -607,7 +607,7 @@ namespace ATC { /* /\** change in restricted atomic FE energy over a timestep *\/ */ /* DENS_MAT deltaNodalAtomicEnergy_; */ -/* /\** intial restricted atomic FE energy used to compute change *\/ */ +/* /\** initial restricted atomic FE energy used to compute change *\/ */ /* DENS_MAT initialNodalAtomicEnergy_; */ /* /\** filtered nodal atomic energy *\/ */ diff --git a/lib/atc/Kinetostat.cpp b/lib/atc/Kinetostat.cpp index 8093d5925a..7f95398dcb 100644 --- a/lib/atc/Kinetostat.cpp +++ b/lib/atc/Kinetostat.cpp @@ -2233,7 +2233,7 @@ namespace ATC { // initialize_delta_nodal_atomic_momentum: // initializes storage for the variable tracking // the change in the nodal atomic momentum - // that has occured over the past timestep + // that has occurred over the past timestep //-------------------------------------------------------- void KinetostatFixed::initialize_delta_nodal_atomic_momentum(double dt) { @@ -2248,7 +2248,7 @@ namespace ATC { //-------------------------------------------------------- // compute_delta_nodal_atomic_momentum: // computes the change in the nodal atomic momentum - // that has occured over the past timestep + // that has occurred over the past timestep //-------------------------------------------------------- void KinetostatFixed::compute_delta_nodal_atomic_momentum(double dt) { diff --git a/lib/atc/Kinetostat.h b/lib/atc/Kinetostat.h index 691b929e9f..e3e1c17e52 100644 --- a/lib/atc/Kinetostat.h +++ b/lib/atc/Kinetostat.h @@ -806,7 +806,7 @@ namespace ATC { /** change in restricted atomic FE momentum over a timestep */ DENS_MAT deltaNodalAtomicMomentum_; - /** intial restricted atomic FE momentum used to compute change */ + /** initial restricted atomic FE momentum used to compute change */ DENS_MAT initialNodalAtomicMomentum_; /** filtered nodal atomic momentum */ diff --git a/lib/atc/LammpsInterface.cpp b/lib/atc/LammpsInterface.cpp index 9c2223f555..9964a1c4bb 100644 --- a/lib/atc/LammpsInterface.cpp +++ b/lib/atc/LammpsInterface.cpp @@ -631,7 +631,7 @@ LammpsInterface::LatticeType LammpsInterface::lattice_style() const throw ATC_Error("Lattice has not been defined"); } -//* retuns the number of basis vectors +//* returns the number of basis vectors int LammpsInterface::n_basis() const { return lammps_->domain->lattice->nbasis; diff --git a/lib/atc/Material.h b/lib/atc/Material.h index 18cccd8792..5a835d446b 100644 --- a/lib/atc/Material.h +++ b/lib/atc/Material.h @@ -83,7 +83,7 @@ namespace ATC /** each of these is a field function computed at a set of points */ /** if there is only one function it is in the base class - ** otherwise, a subsidary class is setup */ + ** otherwise, a subsidiary class is setup */ /* -----------------------------------------------------------------*/ /** densities */ /* -----------------------------------------------------------------*/ diff --git a/lib/atc/Matrix.cpp b/lib/atc/Matrix.cpp index 0741099872..1b77796b8b 100644 --- a/lib/atc/Matrix.cpp +++ b/lib/atc/Matrix.cpp @@ -81,7 +81,7 @@ DenseMatrix inv(const MATRIX& A) GCK(A,A,info<0,"DenseMatrix::inv() dgetri error: Argument had bad value."); GCHK(info>0,"DenseMatrix::inv() dgetri error: Matrix not invertible."); - // Work size query succeded + // Work size query succeeded lwork = (int)work_dummy[0]; double *work = new double[lwork]; // Allocate vector of appropriate size @@ -287,7 +287,7 @@ double det(const MATRIX& A) double max_eigenvalue(const Matrix& A) { - GCK(A,A,!A.is_size(3,3), "max_eigenvalue only implimented for 3x3"); + GCK(A,A,!A.is_size(3,3), "max_eigenvalue only implemented for 3x3"); const double c0 = det(A); const double c1 = A(1,0)*A(0,1) + A(2,0)*A(0,2) + A(1,2)*A(2,1) - A(0,0)*A(1,1) - A(0,0)*A(2,2) - A(1,1)*A(2,2); diff --git a/lib/atc/Matrix.h b/lib/atc/Matrix.h index 6745ea96db..c93576518c 100644 --- a/lib/atc/Matrix.h +++ b/lib/atc/Matrix.h @@ -150,7 +150,7 @@ protected: //* Matrix operations //@{ -//* Sets C as b*C + a*A[tranpose?]*B[transpose?] +//* Sets C as b*C + a*A[transpose?]*B[transpose?] template void MultAB(const Matrix &A, const Matrix &B, DenseMatrix &C, bool At=0, bool Bt=0, T a=1, T b=0); @@ -622,7 +622,7 @@ Matrix& Matrix::operator+=(const T v) return *this; } //----------------------------------------------------------------------------- -// substracts a constant to this matrix +// subtracts a constant to this matrix //----------------------------------------------------------------------------- template Matrix& Matrix::operator-=(const T v) diff --git a/lib/atc/PhysicsModel.cpp b/lib/atc/PhysicsModel.cpp index 77cc41e972..f5c342c5a0 100644 --- a/lib/atc/PhysicsModel.cpp +++ b/lib/atc/PhysicsModel.cpp @@ -95,7 +95,7 @@ void PhysicsModel::parse_material_file(string fileName) } } else { - throw ATC_Error("units need to be specfied in material file"); + throw ATC_Error("units need to be specified in material file"); } } } diff --git a/lib/atc/SparseMatrix.h b/lib/atc/SparseMatrix.h index 35393187cd..700d2f3af6 100644 --- a/lib/atc/SparseMatrix.h +++ b/lib/atc/SparseMatrix.h @@ -38,9 +38,9 @@ class SparseMatrix : public Matrix friend SparseMatrix operator*(const SparseMatrix &A, const DiagonalMatrix& D); //* SparseMatrix-SparseMatrix multiplication (S * S) friend SparseMatrix operator*(const SparseMatrix &A, const SparseMatrix &B); - //* computes the product of a SparseMatrix tranpose with a SparseVector (M'*v). + //* computes the product of a SparseMatrix transpose with a SparseVector (M'*v). friend SparseVector operator*(const SparseMatrix &M, const SparseVector &v); - //* computes the product of a SparseMatrix tranpose with a SparseVector (M'*v). + //* computes the product of a SparseMatrix transpose with a SparseVector (M'*v). friend SparseVector operator*(const SparseVector &v, const SparseMatrix &M); template diff --git a/lib/atc/SparseVector-inl.h b/lib/atc/SparseVector-inl.h index 760eb66f58..7f2c844bd6 100644 --- a/lib/atc/SparseVector-inl.h +++ b/lib/atc/SparseVector-inl.h @@ -55,7 +55,7 @@ T dot(const SparseVector &a, const SparseVector &b) } return v; } -// Computes the product of a SparseMatrix tranpose with a SparseVector (M'*v). +// Computes the product of a SparseMatrix transpose with a SparseVector (M'*v). template SparseVector operator*(const SparseMatrix &M, const SparseVector &v) { @@ -73,7 +73,7 @@ SparseVector operator*(const SparseMatrix &M, const SparseVector &v) return y; } -// computes the product of a SparseMatrix tranpose with a SparseVector (M'*v). +// computes the product of a SparseMatrix transpose with a SparseVector (M'*v). template SparseVector operator*(const SparseVector &v, const SparseMatrix &M) { diff --git a/lib/atc/SparseVector.h b/lib/atc/SparseVector.h index 4219bb2627..5cb16af527 100644 --- a/lib/atc/SparseVector.h +++ b/lib/atc/SparseVector.h @@ -30,9 +30,9 @@ class SparseVector : public Vector { // for use with gcc friend T dot(const SparseVector &a, const SparseVector &b); #endif - //* computes the product of a SparseMatrix tranpose with a SparseVector (M'*v). + //* computes the product of a SparseMatrix transpose with a SparseVector (M'*v). friend SparseVector operator*(const SparseMatrix &M, const SparseVector &v); - //* computes the product of a SparseMatrix tranpose with a SparseVector (M'*v). + //* computes the product of a SparseMatrix transpose with a SparseVector (M'*v). friend SparseVector operator*(const SparseVector &v, const SparseMatrix &M); public: //* Constructor - sets length of vector (NOT # of nonzeros). @@ -71,9 +71,9 @@ public: void reset (INDEX nRows, INDEX nCols=1, bool zero=0); //* zeros out all elements while preserving sparcity pattern void zero(); - //* TODO impliment copy (or maybe not necessary) + //* TODO implement copy (or maybe not necessary) void copy(const T* ptr, INDEX nRows, INDEX nCols=1); - //* Writes a restart file (TODO impliment this if needed/wanted). + //* Writes a restart file (TODO implement this if needed/wanted). void write_restart(FILE *F) const; //* Adds SparseVector x, scaled by s to this one. Can be different sparcity. void add_scaled(SparseVector& x, const T& s); diff --git a/lib/atc/Stress.cpp b/lib/atc/Stress.cpp index 906b15986e..72656c21ed 100644 --- a/lib/atc/Stress.cpp +++ b/lib/atc/Stress.cpp @@ -328,7 +328,7 @@ StressCauchyBorn::StressCauchyBorn(fstream &fileId, CbData &cb) if (line.size() && line[0]=="pair_coeff") break; } if (line[0] != "pair_coeff" || line.size() != 3) { - throw(ATC_Error("lj/cut needs 2 coefficents")); + throw(ATC_Error("lj/cut needs 2 coefficients")); } delete potential_; potential_ = new CbLjCut(str2dbl(line[1]), str2dbl(line[2]), rc); @@ -341,7 +341,7 @@ StressCauchyBorn::StressCauchyBorn(fstream &fileId, CbData &cb) if (line.size() && line[0]=="pair_coeff") break; } if (line[0] != "pair_coeff" || line.size() != 3) { - throw(ATC_Error("lj/smooth/linear needs 2 coefficents")); + throw(ATC_Error("lj/smooth/linear needs 2 coefficients")); } delete potential_; potential_ = new CbLjSmoothLinear(str2dbl(line[1]), str2dbl(line[2]), rc); diff --git a/lib/atc/ThermalTimeIntegrator.cpp b/lib/atc/ThermalTimeIntegrator.cpp index f68f46b01f..e74d46a20c 100644 --- a/lib/atc/ThermalTimeIntegrator.cpp +++ b/lib/atc/ThermalTimeIntegrator.cpp @@ -87,7 +87,7 @@ namespace ATC { break; } default: - throw ATC_Error("Uknown time integration type in ThermalTimeIntegrator::Initialize()"); + throw ATC_Error("Unknown time integration type in ThermalTimeIntegrator::Initialize()"); } } @@ -102,7 +102,7 @@ namespace ATC { break; } default: - throw ATC_Error("Uknown time integration type in ThermalTimeIntegrator::Initialize()"); + throw ATC_Error("Unknown time integration type in ThermalTimeIntegrator::Initialize()"); } } else { @@ -116,7 +116,7 @@ namespace ATC { break; } default: - throw ATC_Error("Uknown time integration type in ThermalTimeIntegrator::Initialize()"); + throw ATC_Error("Unknown time integration type in ThermalTimeIntegrator::Initialize()"); } } } diff --git a/lib/atc/ThermalTimeIntegrator.h b/lib/atc/ThermalTimeIntegrator.h index f0ce73b9b4..8f5175d8a2 100644 --- a/lib/atc/ThermalTimeIntegrator.h +++ b/lib/atc/ThermalTimeIntegrator.h @@ -273,7 +273,7 @@ namespace ATC { /** change in FE temperature due to atomic motions */ DENS_MAN atomicTemperatureDelta_; - /** fractional step auxilliary storage for restricted atomic energy */ + /** fractional step auxiliary storage for restricted atomic energy */ DENS_MAN * nodalAtomicEnergy_; /** power associated with thermostat for post-processing */ diff --git a/lib/atc/Thermostat.cpp b/lib/atc/Thermostat.cpp index 0ede724371..a602105854 100644 --- a/lib/atc/Thermostat.cpp +++ b/lib/atc/Thermostat.cpp @@ -1460,7 +1460,7 @@ namespace ATC { // initialize_delta_nodal_atomic_energy: // initializes storage for the variable tracking // the change in the nodal atomic energy - // that has occured over the past timestep + // that has occurred over the past timestep //-------------------------------------------------------- void ThermostatIntegratorFixed::initialize_delta_nodal_atomic_energy(double dt) { @@ -1475,7 +1475,7 @@ namespace ATC { //-------------------------------------------------------- // compute_delta_nodal_atomic_energy: // computes the change in the nodal atomic energy - // that has occured over the past timestep + // that has occurred over the past timestep //-------------------------------------------------------- void ThermostatIntegratorFixed::compute_delta_nodal_atomic_energy(double dt) { @@ -1778,7 +1778,7 @@ namespace ATC { // initialize_delta_nodal_atomic_energy: // initializes storage for the variable tracking // the change in the nodal atomic energy - // that has occured over the past timestep + // that has occurred over the past timestep //-------------------------------------------------------- @@ -1795,7 +1795,7 @@ namespace ATC { //-------------------------------------------------------- // compute_delta_nodal_atomic_energy: // computes the change in the nodal atomic energy - // that has occured over the past timestep + // that has occurred over the past timestep //-------------------------------------------------------- void ThermostatIntegratorFixedFiltered::compute_delta_nodal_atomic_energy(double dt) { diff --git a/lib/atc/Thermostat.h b/lib/atc/Thermostat.h index 95d2d1162d..3764d0b835 100644 --- a/lib/atc/Thermostat.h +++ b/lib/atc/Thermostat.h @@ -581,7 +581,7 @@ namespace ATC { /** change in restricted atomic FE energy over a timestep */ DENS_MAT deltaNodalAtomicEnergy_; - /** intial restricted atomic FE energy used to compute change */ + /** initial restricted atomic FE energy used to compute change */ DENS_MAT initialNodalAtomicEnergy_; /** filtered nodal atomic energy */ diff --git a/lib/atc/TimeIntegrator.h b/lib/atc/TimeIntegrator.h index ceeb7610fb..ccb9b9f426 100644 --- a/lib/atc/TimeIntegrator.h +++ b/lib/atc/TimeIntegrator.h @@ -362,7 +362,7 @@ namespace ATC { inline void explicit_1(MATRIX & f, const MATRIX & dot_f, double dt) - // 1rst order explict ODE update + // 1rst order explicit ODE update { f = f + dt*dot_f; }; @@ -371,7 +371,7 @@ namespace ATC { const MATRIX & dot_f, const MATRIX & ddot_f, double dt) - // 2nd order explict ODE update + // 2nd order explicit ODE update { f = f + dt*dot_f + .5*dt*dt*ddot_f; }; diff --git a/lib/atc/TransferOperator.h b/lib/atc/TransferOperator.h index 0ab92805be..5f776d04ca 100644 --- a/lib/atc/TransferOperator.h +++ b/lib/atc/TransferOperator.h @@ -466,7 +466,7 @@ namespace ATC { /** reference to shape function matrix */ SPAR_MAN * shapeFunction_; - /** persistant workspace */ + /** persistent workspace */ mutable DENS_MAT _workspace_; @@ -510,7 +510,7 @@ namespace ATC { /** reference to shape function matrix */ SPAR_MAN * shapeFunction_; - /** persistant workspace */ + /** persistent workspace */ mutable DENS_MAT _workspace_; @@ -560,7 +560,7 @@ namespace ATC { DIAG_MAN * weights_; DENS_MAT * reference_; - /** persistant workspace */ + /** persistent workspace */ mutable DENS_MAT _workspace_; @@ -887,7 +887,7 @@ namespace ATC { /** pointer to the mesh being used */ const FE_Mesh * feMesh_; - /** persistant workspace */ + /** persistent workspace */ mutable DENS_MAT _workspace_; diff --git a/lib/awpmd/ivutils/include/logexc.h b/lib/awpmd/ivutils/include/logexc.h index 4c8364671a..80942f60bf 100644 --- a/lib/awpmd/ivutils/include/logexc.h +++ b/lib/awpmd/ivutils/include/logexc.h @@ -42,7 +42,7 @@ enum vbLEVELS{ /// by default all exceptions have vblFATAL level template struct log_exception_traits{ - /// exeption level according to the vbLEVELS + /// exception level according to the vbLEVELS static int level(const exc_t & /* signal */){ return vblFATAL; } /// the string name of exception category static string name(const exc_t & /* signal */){ return typeid(exc_t).name();} @@ -59,7 +59,7 @@ struct log_exception_traits{ /// integer exceptions have the level equal to their value template<> struct log_exception_traits{ - /// exeption level according to the vbLEVELS + /// exception level according to the vbLEVELS static int level(const int &signal){ return signal; } /// the string name of exception category static string name(const int &signal){ @@ -294,7 +294,7 @@ const char *fmt(const char *format,...); /// this may be used to inherit exceptions /// where level and name are defined whithin a class struct log_exception { - /// exeption level according to the vbLEVELS + /// exception level according to the vbLEVELS static int level(const log_exception &signal){ return vblFATAL; } /// the string name of exception category static string name(const log_exception &signal){ return "undefined exception";} diff --git a/lib/awpmd/ivutils/include/wavepacket.h b/lib/awpmd/ivutils/include/wavepacket.h index c4f3837022..337a056e79 100644 --- a/lib/awpmd/ivutils/include/wavepacket.h +++ b/lib/awpmd/ivutils/include/wavepacket.h @@ -168,13 +168,13 @@ public: return imag(b) - real(b)*(imag(a)/real(a)); } - ///\en Transforms derivatives of a function whith respect to WP parameters + ///\en Transforms derivatives of a function with respect to WP parameters /// from internal into physical representation, i. e.:\n /// from df/d{are,aim,b0re,b0im,b1re,b1im,b2re,b2im} (8 values accessed by input iterator d_it in the given order)\n /// to df/d{x0,x1,x2}, df/d{p0,p1,p2}, df/dw, df/dpw /// The supplied inputs (val) are modified by op: val=op(val,phys_der). /// Use operation=eq_second for the supplied inputs to be replaced by new physical derivative values. - /// The inpput and output locations may coinside, an internal buffer is used for transformation. + /// The input and output locations may coinside, an internal buffer is used for transformation. template class operation, class d_it, class dfdx_it, class dfdp_it, class dfdw_it, class dfdpw_it> void int2phys_der(d_it dfdi_,dfdx_it dfdx, dfdp_it dfdp, dfdw_it dfdw, dfdpw_it dfdpw, double h_p=h_plank) const { operation op; diff --git a/lib/awpmd/systems/interact/TCP/wpmd.cpp b/lib/awpmd/systems/interact/TCP/wpmd.cpp index ad5d8e26bc..1e53f3141c 100644 --- a/lib/awpmd/systems/interact/TCP/wpmd.cpp +++ b/lib/awpmd/systems/interact/TCP/wpmd.cpp @@ -217,7 +217,7 @@ int AWPMD::interaction_hartree(int flag, Vector_3P fi, Vector_3P fe_x, // 0. resizing the arrays if needed enum APPROX tmp=HARTREE; - swap(tmp,approx); // do not neeed large matrices + swap(tmp,approx); // do not need large matrices resize(flag); swap(tmp,approx); //1. clearing forces diff --git a/lib/awpmd/systems/interact/TCP/wpmd.h b/lib/awpmd/systems/interact/TCP/wpmd.h index bcb99e2092..e5a7c27697 100644 --- a/lib/awpmd/systems/interact/TCP/wpmd.h +++ b/lib/awpmd/systems/interact/TCP/wpmd.h @@ -201,7 +201,7 @@ inline pair operator*(const pair &right, double le return make_pair(right.first*left,right.second*left); } -// Auxilary class to handle the normalizing term derivatives +// Auxiliary class to handle the normalizing term derivatives class NormDeriv { public: @@ -235,7 +235,7 @@ inline NormDeriv conj(const NormDeriv& src){ return dst; } -///\en Auxilary class to handle derivatives of overlaps +///\en Auxiliary class to handle derivatives of overlaps class OverlapDeriv{ public: WavePacket w1, w2, w12; @@ -496,7 +496,7 @@ public: } protected: - //e translates wp2 to the nearest image postion relative to wp1 + //e translates wp2 to the nearest image position relative to wp1 //e gets the translation vector Vector_3 move_to_image(const WavePacket &wp1, WavePacket &wp2) const { Vector_3 r1=wp1.get_r(); @@ -646,7 +646,7 @@ public: Vector_3P fe_p, double *fe_w, double *fe_pw, Vector_2P fe_c=NULL); - ///\en Creates wave packet acording to the given physical parameters. + ///\en Creates wave packet according to the given physical parameters. /// The function may change its arguments by applying existing constraints! /// Default mass (-1) is the electron mass AWPMD::me. WavePacket create_wp(Vector_3 &x, Vector_3 &v, double &w, double &pw, double mass=-1); diff --git a/lib/awpmd/systems/interact/TCP/wpmd_split.cpp b/lib/awpmd/systems/interact/TCP/wpmd_split.cpp index 691dbac91b..732707d717 100644 --- a/lib/awpmd/systems/interact/TCP/wpmd_split.cpp +++ b/lib/awpmd/systems/interact/TCP/wpmd_split.cpp @@ -351,7 +351,7 @@ int AWPMD_split::interaction_hartree(int flag, Vector_3P fi, Vector_3P fe_x, // resize arrays if needed enum APPROX tmp=HARTREE; - swap(tmp,approx); // do not neeed large matrices + swap(tmp,approx); // do not need large matrices resize(flag); swap(tmp,approx); diff --git a/lib/colvars/colvar.cpp b/lib/colvars/colvar.cpp index fb95bda5ec..1002dc35d8 100644 --- a/lib/colvars/colvar.cpp +++ b/lib/colvars/colvar.cpp @@ -252,7 +252,7 @@ int colvar::init(std::string const &conf) // components may have different types only for scripted functions if (!(is_enabled(f_cv_scripted) || is_enabled(f_cv_custom_function)) && (colvarvalue::check_types(cvcs[i]->value(), cvcs[0]->value())) ) { - cvm::error("ERROR: you are definining this collective variable " + cvm::error("ERROR: you are defining this collective variable " "by using components of different types. " "You must use the same type in order to " "sum them together.\n", INPUT_ERROR); diff --git a/lib/colvars/colvarbias_abf.h b/lib/colvars/colvarbias_abf.h index 5a1a1c8128..1939b61a8b 100644 --- a/lib/colvars/colvarbias_abf.h +++ b/lib/colvars/colvarbias_abf.h @@ -109,7 +109,7 @@ private: colvar_grid_gradient *z_gradients; /// n-dim grid of number of samples on "real" coordinate for eABF z-based estimator colvar_grid_count *z_samples; - /// n-dim grid contining CZAR estimator of "real" free energy gradients + /// n-dim grid containing CZAR estimator of "real" free energy gradients colvar_grid_gradient *czar_gradients; /// n-dim grid of CZAR pmf (dimension 1 to 3) integrate_potential *czar_pmf; diff --git a/lib/colvars/colvarcomp.h b/lib/colvars/colvarcomp.h index b01c7e48e1..1ab7d17031 100644 --- a/lib/colvars/colvarcomp.h +++ b/lib/colvars/colvarcomp.h @@ -1512,7 +1512,7 @@ protected: std::map> string_cv_map; /// Sub-colvar components std::vector cv; - /// Refernce colvar values from path + /// Reference colvar values from path std::vector> ref_cv; /// If all sub-cvs use explicit gradients then we also use it bool use_explicit_gradients; diff --git a/lib/colvars/colvarcomp_protein.cpp b/lib/colvars/colvarcomp_protein.cpp index e0779b602e..3add471c04 100644 --- a/lib/colvars/colvarcomp_protein.cpp +++ b/lib/colvars/colvarcomp_protein.cpp @@ -210,7 +210,7 @@ void colvar::alpha_angles::collect_gradients(std::vector const &atom_ids, s 1.0/(1.0 - (t*t*t*t)) * ( (-2.0 * t) + (-1.0*f)*(-4.0 * (t*t*t)) ); - // Coeficient of this CVC's gradient in the colvar gradient, times coefficient of this + // Coefficient of this CVC's gradient in the colvar gradient, times coefficient of this // angle's gradient in the CVC's gradient cvm::real const coeff = cvc_coeff * theta_norm * dfdt * (1.0/theta_tol); @@ -230,7 +230,7 @@ void colvar::alpha_angles::collect_gradients(std::vector const &atom_ids, s cvm::real const hb_norm = hb_coeff / cvm::real(hb.size()); for (size_t i = 0; i < hb.size(); i++) { - // Coeficient of this CVC's gradient in the colvar gradient, times coefficient of this + // Coefficient of this CVC's gradient in the colvar gradient, times coefficient of this // hbond's gradient in the CVC's gradient cvm::real const coeff = cvc_coeff * 0.5 * hb_norm; @@ -473,7 +473,7 @@ void colvar::dihedPC::collect_gradients(std::vector const &atom_ids, std::v cvm::real const t = (PI / 180.) * theta[i]->value().real_value; cvm::real const dcosdt = - (PI / 180.) * cvm::sin(t); cvm::real const dsindt = (PI / 180.) * cvm::cos(t); - // Coeficient of this dihedPC's gradient in the colvar gradient, times coefficient of this + // Coefficient of this dihedPC's gradient in the colvar gradient, times coefficient of this // dihedral's gradient in the dihedPC's gradient cvm::real const coeff = cvc_coeff * (coeffs[2*i] * dcosdt + coeffs[2*i+1] * dsindt); diff --git a/lib/colvars/colvardeps.h b/lib/colvars/colvardeps.h index 058ac3c78c..63669536fe 100644 --- a/lib/colvars/colvardeps.h +++ b/lib/colvars/colvardeps.h @@ -21,7 +21,7 @@ /// system. They may be enabled or disabled depending on dependencies. /// 2. User features may be enabled based on user input (they may trigger a failure upon dependency resolution, though) /// 3. Static features are static properties of the object, determined -/// programatically at initialization time. +/// programmatically at initialization time. /// /// The following diagram summarizes the dependency tree at the bias, colvar, and colvarcomp levels. /// Isolated and atom group features are not shown to save space. diff --git a/lib/colvars/colvarproxy.h b/lib/colvars/colvarproxy.h index 7a43946c52..ba91afb40e 100644 --- a/lib/colvars/colvarproxy.h +++ b/lib/colvars/colvarproxy.h @@ -334,7 +334,7 @@ class colvarproxy_atom_groups { public: - /// Contructor + /// Constructor colvarproxy_atom_groups(); /// Destructor diff --git a/lib/gpu/README b/lib/gpu/README index 2d98749a40..2ef8ce9556 100644 --- a/lib/gpu/README +++ b/lib/gpu/README @@ -52,7 +52,7 @@ user-gpu_SYSLIB = CUDA libraries needed by this package user-gpu_SYSPATH = path(s) to where those libraries are Because you have the CUDA compilers on your system, you should have -the needed libraries. If the CUDA developement tools were installed +the needed libraries. If the CUDA development tools were installed in the standard manner, the settings in the Makefile.lammps.standard file should work. diff --git a/lib/gpu/cudpp_mini/cudpp.cpp b/lib/gpu/cudpp_mini/cudpp.cpp index da5975406d..e2cd4621a4 100644 --- a/lib/gpu/cudpp_mini/cudpp.cpp +++ b/lib/gpu/cudpp_mini/cudpp.cpp @@ -27,7 +27,7 @@ * defined in cudpp.h. Public interface functions call functions in the * \link cudpp_app Application-Level\endlink interface. The public * interface functions include Plan Interface functions and Algorithm - * Interface functions. Plan Inteface functions are used for creating + * Interface functions. Plan Interface functions are used for creating * CUDPP Plan objects which contain configuration details, intermediate * storage space, and in the case of cudppSparseMatrix(), data. The * Algorithm Interface is the set of functions that do the real work diff --git a/lib/gpu/cudpp_mini/cutil.h b/lib/gpu/cudpp_mini/cutil.h index 3df93fb886..fbf139cda3 100644 --- a/lib/gpu/cudpp_mini/cutil.h +++ b/lib/gpu/cudpp_mini/cutil.h @@ -367,7 +367,7 @@ extern "C" { //! @param w width of the image //! @param h height of the image //! @note If a NULL pointer is passed to this function and it is - //! initialized withing Cutil then cutFree() has to be used to + //! initialized within Cutil then cutFree() has to be used to //! deallocate the memory //////////////////////////////////////////////////////////////////////////// DLL_MAPPING @@ -382,7 +382,7 @@ extern "C" { //! @param w width of the image //! @param h height of the image //! @note If a NULL pointer is passed to this function and it is - //! initialized withing Cutil then cutFree() has to be used to + //! initialized within Cutil then cutFree() has to be used to //! deallocate the memory //////////////////////////////////////////////////////////////////////////// DLL_MAPPING @@ -466,7 +466,7 @@ extern "C" { //////////////////////////////////////////////////////////////////////////// // Command line arguments: General notes // * All command line arguments begin with '--' followed by the token; - // token and value are seperated by '='; example --samples=50 + // token and value are separated by '='; example --samples=50 // * Arrays have the form --model=[one.obj,two.obj,three.obj] // (without whitespaces) //////////////////////////////////////////////////////////////////////////// diff --git a/lib/gpu/cudpp_mini/kernel/scan_kernel.cu b/lib/gpu/cudpp_mini/kernel/scan_kernel.cu index 966634c89b..d8eb477952 100644 --- a/lib/gpu/cudpp_mini/kernel/scan_kernel.cu +++ b/lib/gpu/cudpp_mini/kernel/scan_kernel.cu @@ -46,7 +46,7 @@ * the rows of \a d_blockSums (in elements) in \a blockSumRowPitch, and invoke * with a thread block grid with height greater than 1. * - * This function peforms one level of a recursive, multiblock scan. At the + * This function performs one level of a recursive, multiblock scan. At the * app level, this function is called by cudppScan and cudppMultiScan and used * in combination with vectorAddUniform4() to produce a complete scan. * diff --git a/lib/gpu/lal_base_atomic.h b/lib/gpu/lal_base_atomic.h index e3e9829abc..da17bd928d 100644 --- a/lib/gpu/lal_base_atomic.h +++ b/lib/gpu/lal_base_atomic.h @@ -43,7 +43,7 @@ class BaseAtomic { * \param k_name name for the kernel for force calculation * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_base_charge.h b/lib/gpu/lal_base_charge.h index 64c19554b9..29554ebfd5 100644 --- a/lib/gpu/lal_base_charge.h +++ b/lib/gpu/lal_base_charge.h @@ -44,7 +44,7 @@ class BaseCharge { * \param k_name name for the kernel for force calculation * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_base_dipole.h b/lib/gpu/lal_base_dipole.h index b51c4303cf..eecdcd3aab 100644 --- a/lib/gpu/lal_base_dipole.h +++ b/lib/gpu/lal_base_dipole.h @@ -42,7 +42,7 @@ class BaseDipole { * \param k_name name for the kernel for force calculation * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_base_dpd.h b/lib/gpu/lal_base_dpd.h index 7a75282d0a..b46de2197d 100644 --- a/lib/gpu/lal_base_dpd.h +++ b/lib/gpu/lal_base_dpd.h @@ -42,7 +42,7 @@ class BaseDPD { * \param k_name name for the kernel for force calculation * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_base_ellipsoid.h b/lib/gpu/lal_base_ellipsoid.h index 7deeccbf44..d4bdd9e969 100644 --- a/lib/gpu/lal_base_ellipsoid.h +++ b/lib/gpu/lal_base_ellipsoid.h @@ -44,7 +44,7 @@ class BaseEllipsoid { * \param k_name name for the kernel for force calculation * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_base_three.h b/lib/gpu/lal_base_three.h index f5f36863c4..96ca928edc 100644 --- a/lib/gpu/lal_base_three.h +++ b/lib/gpu/lal_base_three.h @@ -46,7 +46,7 @@ class BaseThree { * \param k_three name for the kernel for 3-body force calculation * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_beck.h b/lib/gpu/lal_beck.h index db26bebeb0..638f1bf626 100644 --- a/lib/gpu/lal_beck.h +++ b/lib/gpu/lal_beck.h @@ -32,7 +32,7 @@ class Beck : public BaseAtomic { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_born.h b/lib/gpu/lal_born.h index 685f4d87a9..2a7f355d69 100644 --- a/lib/gpu/lal_born.h +++ b/lib/gpu/lal_born.h @@ -32,7 +32,7 @@ class Born : public BaseAtomic { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_born_coul_long.h b/lib/gpu/lal_born_coul_long.h index d236b7b57f..e383d18e0c 100644 --- a/lib/gpu/lal_born_coul_long.h +++ b/lib/gpu/lal_born_coul_long.h @@ -32,7 +32,7 @@ class BornCoulLong : public BaseCharge { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_born_coul_long_cs.h b/lib/gpu/lal_born_coul_long_cs.h index df0fa0fcd4..6c4032b3be 100644 --- a/lib/gpu/lal_born_coul_long_cs.h +++ b/lib/gpu/lal_born_coul_long_cs.h @@ -32,7 +32,7 @@ class BornCoulLongCS : public BornCoulLong { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_born_coul_wolf.h b/lib/gpu/lal_born_coul_wolf.h index 4b817ee0ce..fa53f48939 100644 --- a/lib/gpu/lal_born_coul_wolf.h +++ b/lib/gpu/lal_born_coul_wolf.h @@ -32,7 +32,7 @@ class BornCoulWolf : public BaseCharge { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_born_coul_wolf_cs.h b/lib/gpu/lal_born_coul_wolf_cs.h index 1d9de0a457..e5bff1b4cc 100644 --- a/lib/gpu/lal_born_coul_wolf_cs.h +++ b/lib/gpu/lal_born_coul_wolf_cs.h @@ -32,7 +32,7 @@ class BornCoulWolfCS : public BornCoulWolf { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_buck.h b/lib/gpu/lal_buck.h index 3b84066355..7a09fae5dd 100644 --- a/lib/gpu/lal_buck.h +++ b/lib/gpu/lal_buck.h @@ -32,7 +32,7 @@ class Buck : public BaseAtomic { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_buck_coul.h b/lib/gpu/lal_buck_coul.h index 3f8428bfe1..eebba78eb0 100644 --- a/lib/gpu/lal_buck_coul.h +++ b/lib/gpu/lal_buck_coul.h @@ -32,7 +32,7 @@ class BuckCoul : public BaseCharge { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_buck_coul_long.h b/lib/gpu/lal_buck_coul_long.h index 4a70a3a097..e2d69475cf 100644 --- a/lib/gpu/lal_buck_coul_long.h +++ b/lib/gpu/lal_buck_coul_long.h @@ -32,7 +32,7 @@ class BuckCoulLong : public BaseCharge { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_charmm_long.h b/lib/gpu/lal_charmm_long.h index 011083db13..5d9d9ea50b 100644 --- a/lib/gpu/lal_charmm_long.h +++ b/lib/gpu/lal_charmm_long.h @@ -32,7 +32,7 @@ class CHARMMLong : public BaseCharge { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_colloid.h b/lib/gpu/lal_colloid.h index dfbd4dbadd..35426007d8 100644 --- a/lib/gpu/lal_colloid.h +++ b/lib/gpu/lal_colloid.h @@ -32,7 +32,7 @@ class Colloid : public BaseAtomic { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_coul.h b/lib/gpu/lal_coul.h index 6d9b6b1b2b..38472375fb 100644 --- a/lib/gpu/lal_coul.h +++ b/lib/gpu/lal_coul.h @@ -32,7 +32,7 @@ class Coul : public BaseCharge { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_coul_debye.h b/lib/gpu/lal_coul_debye.h index 328c3dd64e..13e4c5b0c6 100644 --- a/lib/gpu/lal_coul_debye.h +++ b/lib/gpu/lal_coul_debye.h @@ -32,7 +32,7 @@ class CoulDebye : public BaseCharge { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_coul_dsf.h b/lib/gpu/lal_coul_dsf.h index e52a51d583..3d57898f81 100644 --- a/lib/gpu/lal_coul_dsf.h +++ b/lib/gpu/lal_coul_dsf.h @@ -32,7 +32,7 @@ class CoulDSF : public BaseCharge { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_coul_long.h b/lib/gpu/lal_coul_long.h index ae25b91dc7..0668e0fd02 100644 --- a/lib/gpu/lal_coul_long.h +++ b/lib/gpu/lal_coul_long.h @@ -32,7 +32,7 @@ class CoulLong : public BaseCharge { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_coul_long_cs.h b/lib/gpu/lal_coul_long_cs.h index 3cfcb80fc8..fc3667d6a0 100644 --- a/lib/gpu/lal_coul_long_cs.h +++ b/lib/gpu/lal_coul_long_cs.h @@ -32,7 +32,7 @@ class CoulLongCS : public CoulLong { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_device.h b/lib/gpu/lal_device.h index 0c4d5f8c43..21bd039c42 100644 --- a/lib/gpu/lal_device.h +++ b/lib/gpu/lal_device.h @@ -41,7 +41,7 @@ class Device { /** Sets up a per-device MPI communicator for load balancing and initializes * the device (>=first_gpu and <=last_gpu) that this proc will be using * Returns: - * - 0 if successfull + * - 0 if successful * - -2 if GPU not found * - -4 if GPU library not compiled for GPU * - -6 if GPU could not be initialized for use @@ -62,7 +62,7 @@ class Device { * \param vel True if velocities need to be stored * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU @@ -76,7 +76,7 @@ class Device { * \param nall Total number of local+ghost particles * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU @@ -100,7 +100,7 @@ class Device { * \param threads_per_atom value to be used by the neighbor list only * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_dipole_lj.h b/lib/gpu/lal_dipole_lj.h index 615784ee8b..bd312324c6 100644 --- a/lib/gpu/lal_dipole_lj.h +++ b/lib/gpu/lal_dipole_lj.h @@ -32,7 +32,7 @@ class DipoleLJ : public BaseDipole { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_dipole_lj_sf.h b/lib/gpu/lal_dipole_lj_sf.h index 20357385a2..ae73508065 100644 --- a/lib/gpu/lal_dipole_lj_sf.h +++ b/lib/gpu/lal_dipole_lj_sf.h @@ -32,7 +32,7 @@ class DipoleLJSF : public BaseDipole { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_dipole_long_lj.h b/lib/gpu/lal_dipole_long_lj.h index 1381e24326..77e22a10a7 100644 --- a/lib/gpu/lal_dipole_long_lj.h +++ b/lib/gpu/lal_dipole_long_lj.h @@ -32,7 +32,7 @@ class DipoleLongLJ : public BaseDipole { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_dpd.h b/lib/gpu/lal_dpd.h index 42ef854522..3c36c39e05 100644 --- a/lib/gpu/lal_dpd.h +++ b/lib/gpu/lal_dpd.h @@ -32,7 +32,7 @@ class DPD : public BaseDPD { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_eam.h b/lib/gpu/lal_eam.h index ce26edc1f4..fa05075883 100644 --- a/lib/gpu/lal_eam.h +++ b/lib/gpu/lal_eam.h @@ -33,7 +33,7 @@ class EAM : public BaseAtomic { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_gauss.h b/lib/gpu/lal_gauss.h index d023310c6d..1399b82d03 100644 --- a/lib/gpu/lal_gauss.h +++ b/lib/gpu/lal_gauss.h @@ -32,7 +32,7 @@ class Gauss : public BaseAtomic { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_gayberne.h b/lib/gpu/lal_gayberne.h index 8792f1f1db..750c739cec 100644 --- a/lib/gpu/lal_gayberne.h +++ b/lib/gpu/lal_gayberne.h @@ -34,7 +34,7 @@ class GayBerne : public BaseEllipsoid { * \return false if there is not sufficient memory or device init prob * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_lj.h b/lib/gpu/lal_lj.h index 01ce85c8ea..c6fec0d159 100644 --- a/lib/gpu/lal_lj.h +++ b/lib/gpu/lal_lj.h @@ -32,7 +32,7 @@ class LJ : public BaseAtomic { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_lj96.h b/lib/gpu/lal_lj96.h index 3fdea5265e..eef6863f37 100644 --- a/lib/gpu/lal_lj96.h +++ b/lib/gpu/lal_lj96.h @@ -32,7 +32,7 @@ class LJ96 : public BaseAtomic { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_lj_class2_long.h b/lib/gpu/lal_lj_class2_long.h index d07b974a90..eac6451b2e 100644 --- a/lib/gpu/lal_lj_class2_long.h +++ b/lib/gpu/lal_lj_class2_long.h @@ -32,7 +32,7 @@ class LJClass2Long : public BaseCharge { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_lj_coul.h b/lib/gpu/lal_lj_coul.h index a262c0837f..0e11162aa5 100644 --- a/lib/gpu/lal_lj_coul.h +++ b/lib/gpu/lal_lj_coul.h @@ -32,7 +32,7 @@ class LJCoul : public BaseCharge { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_lj_coul_debye.h b/lib/gpu/lal_lj_coul_debye.h index 1d3d0ba375..22fcf7234b 100644 --- a/lib/gpu/lal_lj_coul_debye.h +++ b/lib/gpu/lal_lj_coul_debye.h @@ -32,7 +32,7 @@ class LJCoulDebye : public BaseCharge { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_lj_coul_long.h b/lib/gpu/lal_lj_coul_long.h index 7b2d79c2a6..8f77671dc0 100644 --- a/lib/gpu/lal_lj_coul_long.h +++ b/lib/gpu/lal_lj_coul_long.h @@ -32,7 +32,7 @@ class LJCoulLong : public BaseCharge { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_lj_coul_msm.h b/lib/gpu/lal_lj_coul_msm.h index 48d49a8742..6369ce8cb5 100644 --- a/lib/gpu/lal_lj_coul_msm.h +++ b/lib/gpu/lal_lj_coul_msm.h @@ -32,7 +32,7 @@ class LJCoulMSM : public BaseCharge { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_lj_cubic.h b/lib/gpu/lal_lj_cubic.h index 818fb3581b..9578ca27e4 100644 --- a/lib/gpu/lal_lj_cubic.h +++ b/lib/gpu/lal_lj_cubic.h @@ -32,7 +32,7 @@ class LJCubic : public BaseAtomic { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_lj_dsf.h b/lib/gpu/lal_lj_dsf.h index 0195898ca4..b176e087db 100644 --- a/lib/gpu/lal_lj_dsf.h +++ b/lib/gpu/lal_lj_dsf.h @@ -32,7 +32,7 @@ class LJDSF : public BaseCharge { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_lj_expand.h b/lib/gpu/lal_lj_expand.h index a732a3a686..2560d166c7 100644 --- a/lib/gpu/lal_lj_expand.h +++ b/lib/gpu/lal_lj_expand.h @@ -32,7 +32,7 @@ class LJExpand : public BaseAtomic { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_lj_expand_coul_long.h b/lib/gpu/lal_lj_expand_coul_long.h index 64fd9df1ab..404a36e5bc 100644 --- a/lib/gpu/lal_lj_expand_coul_long.h +++ b/lib/gpu/lal_lj_expand_coul_long.h @@ -32,7 +32,7 @@ class LJExpandCoulLong : public BaseCharge { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_lj_gromacs.h b/lib/gpu/lal_lj_gromacs.h index 1e0f72dafc..3dec13c6d7 100644 --- a/lib/gpu/lal_lj_gromacs.h +++ b/lib/gpu/lal_lj_gromacs.h @@ -32,7 +32,7 @@ class LJGROMACS : public BaseAtomic { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_lj_sdk.h b/lib/gpu/lal_lj_sdk.h index ac2b9aafe3..fc50756a3f 100644 --- a/lib/gpu/lal_lj_sdk.h +++ b/lib/gpu/lal_lj_sdk.h @@ -32,7 +32,7 @@ class CGCMM : public BaseAtomic { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_lj_sdk_long.h b/lib/gpu/lal_lj_sdk_long.h index f56687cd7d..608488bd30 100644 --- a/lib/gpu/lal_lj_sdk_long.h +++ b/lib/gpu/lal_lj_sdk_long.h @@ -32,7 +32,7 @@ class CGCMMLong : public BaseCharge { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_lj_tip4p_long.h b/lib/gpu/lal_lj_tip4p_long.h index ab32d1e9f3..90c342e246 100644 --- a/lib/gpu/lal_lj_tip4p_long.h +++ b/lib/gpu/lal_lj_tip4p_long.h @@ -32,7 +32,7 @@ public: * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_mie.h b/lib/gpu/lal_mie.h index 8752fe1748..dfc2ee6e53 100644 --- a/lib/gpu/lal_mie.h +++ b/lib/gpu/lal_mie.h @@ -32,7 +32,7 @@ class Mie : public BaseAtomic { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_morse.h b/lib/gpu/lal_morse.h index ef80fb4235..bf5f1c0f8f 100644 --- a/lib/gpu/lal_morse.h +++ b/lib/gpu/lal_morse.h @@ -32,7 +32,7 @@ class Morse : public BaseAtomic { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_pppm.h b/lib/gpu/lal_pppm.h index 045423e079..65af157513 100644 --- a/lib/gpu/lal_pppm.h +++ b/lib/gpu/lal_pppm.h @@ -39,7 +39,7 @@ class PPPM { /// Clear any previous data and set up for a new LAMMPS run /** Success will be: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -2 if GPU could not be found * - -3 if there is an out of memory error diff --git a/lib/gpu/lal_re_squared.h b/lib/gpu/lal_re_squared.h index 8dc137d829..9e4f4af67a 100644 --- a/lib/gpu/lal_re_squared.h +++ b/lib/gpu/lal_re_squared.h @@ -34,7 +34,7 @@ class RESquared : public BaseEllipsoid { * \return false if there is not sufficient memory or device init prob * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_soft.h b/lib/gpu/lal_soft.h index e72673248c..ff4524b30a 100644 --- a/lib/gpu/lal_soft.h +++ b/lib/gpu/lal_soft.h @@ -32,7 +32,7 @@ class Soft : public BaseAtomic { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_sw.h b/lib/gpu/lal_sw.h index 3546f02eb7..1a2e025ae0 100644 --- a/lib/gpu/lal_sw.h +++ b/lib/gpu/lal_sw.h @@ -32,7 +32,7 @@ class SW : public BaseThree { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_table.h b/lib/gpu/lal_table.h index f667336679..38ae012bee 100644 --- a/lib/gpu/lal_table.h +++ b/lib/gpu/lal_table.h @@ -32,7 +32,7 @@ class Table : public BaseAtomic { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_tersoff.h b/lib/gpu/lal_tersoff.h index fd01af031a..51e64c987b 100644 --- a/lib/gpu/lal_tersoff.h +++ b/lib/gpu/lal_tersoff.h @@ -32,7 +32,7 @@ class Tersoff : public BaseThree { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_tersoff_mod.h b/lib/gpu/lal_tersoff_mod.h index ab1560d951..29a561c71d 100644 --- a/lib/gpu/lal_tersoff_mod.h +++ b/lib/gpu/lal_tersoff_mod.h @@ -32,7 +32,7 @@ class TersoffMod : public BaseThree { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_tersoff_zbl.h b/lib/gpu/lal_tersoff_zbl.h index 0e6cac9587..eb03e9fb02 100644 --- a/lib/gpu/lal_tersoff_zbl.h +++ b/lib/gpu/lal_tersoff_zbl.h @@ -32,7 +32,7 @@ class TersoffZBL : public BaseThree { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_ufm.h b/lib/gpu/lal_ufm.h index aeeaacbe99..65ee15d5b5 100644 --- a/lib/gpu/lal_ufm.h +++ b/lib/gpu/lal_ufm.h @@ -34,7 +34,7 @@ class UFM : public BaseAtomic { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_vashishta.h b/lib/gpu/lal_vashishta.h index c5c96a5b80..2da7a11e1e 100644 --- a/lib/gpu/lal_vashishta.h +++ b/lib/gpu/lal_vashishta.h @@ -32,7 +32,7 @@ class Vashishta : public BaseThree { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_yukawa.h b/lib/gpu/lal_yukawa.h index 4cc23c03e9..7d638d760e 100644 --- a/lib/gpu/lal_yukawa.h +++ b/lib/gpu/lal_yukawa.h @@ -32,7 +32,7 @@ class Yukawa : public BaseAtomic { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_yukawa_colloid.h b/lib/gpu/lal_yukawa_colloid.h index ba69bc4bae..607bc42321 100644 --- a/lib/gpu/lal_yukawa_colloid.h +++ b/lib/gpu/lal_yukawa_colloid.h @@ -32,7 +32,7 @@ class YukawaColloid : public BaseAtomic { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/gpu/lal_zbl.h b/lib/gpu/lal_zbl.h index 9885fcedf2..e205d326c6 100644 --- a/lib/gpu/lal_zbl.h +++ b/lib/gpu/lal_zbl.h @@ -32,7 +32,7 @@ class ZBL : public BaseAtomic { * \param gpu_split fraction of particles handled by device * * Returns: - * - 0 if successfull + * - 0 if successful * - -1 if fix gpu not found * - -3 if there is an out of memory error * - -4 if the GPU library was not compiled for GPU diff --git a/lib/h5md/README b/lib/h5md/README index fb7d82bfcc..4768b50697 100644 --- a/lib/h5md/README +++ b/lib/h5md/README @@ -19,7 +19,7 @@ ch5md is a set of C routines to manipulate H5MD files. H5MD is a file format specification based on [HDF5](http://www.hdfgroup.org/HDF5/) for storing molecular data, whose development is found at . -ch5md is developped by Pierre de Buyl and is released under the 3-clause BSD +ch5md is developed by Pierre de Buyl and is released under the 3-clause BSD license that can be found in the file LICENSE. To use the h5md dump style in lammps, execute diff --git a/lib/kokkos/algorithms/src/Kokkos_Random.hpp b/lib/kokkos/algorithms/src/Kokkos_Random.hpp index e14471a48a..da781de4fe 100644 --- a/lib/kokkos/algorithms/src/Kokkos_Random.hpp +++ b/lib/kokkos/algorithms/src/Kokkos_Random.hpp @@ -102,9 +102,9 @@ namespace Kokkos { //Initializing constructor: calls init(seed,Device_Specific_Number); Pool(unsigned int seed); - //Intialize Pool with seed as a starting seed with a pool_size of num_states + //Initialize Pool with seed as a starting seed with a pool_size of num_states //The Random_XorShift64 generator is used in serial to initialize all states, - //thus the intialization process is platform independent and deterministic. + //thus the initialization process is platform independent and deterministic. void init(unsigned int seed, int num_states); //Get a generator. This will lock one of the states, guaranteeing that each thread diff --git a/lib/kokkos/benchmarks/policy_performance/script_sample_usage.sh b/lib/kokkos/benchmarks/policy_performance/script_sample_usage.sh index f4bfb87f8f..1c2db56648 100755 --- a/lib/kokkos/benchmarks/policy_performance/script_sample_usage.sh +++ b/lib/kokkos/benchmarks/policy_performance/script_sample_usage.sh @@ -2,7 +2,7 @@ # Sample script for benchmarking policy performance -# Suggested enviroment variables to export prior to executing script: +# Suggested environment variables to export prior to executing script: # KNL: # OMP_NUM_THREADS=256 KMP_AFFINITY=compact # Power: diff --git a/lib/kokkos/bin/hpcbind b/lib/kokkos/bin/hpcbind index b185a92821..6af091a7d8 100755 --- a/lib/kokkos/bin/hpcbind +++ b/lib/kokkos/bin/hpcbind @@ -383,7 +383,7 @@ fi # Check unknown arguments ################################################################################ if [[ ${#UNKNOWN_ARGS[*]} > 0 ]]; then - echo "HPCBIND Uknown options: ${UNKNOWN_ARGS[*]}" > >(tee -a ${HPCBIND_LOG}) + echo "HPCBIND Unknown options: ${UNKNOWN_ARGS[*]}" > >(tee -a ${HPCBIND_LOG}) exit 1 fi diff --git a/lib/kokkos/containers/src/Kokkos_UnorderedMap.hpp b/lib/kokkos/containers/src/Kokkos_UnorderedMap.hpp index aed723288f..1406116e26 100644 --- a/lib/kokkos/containers/src/Kokkos_UnorderedMap.hpp +++ b/lib/kokkos/containers/src/Kokkos_UnorderedMap.hpp @@ -102,7 +102,7 @@ public: KOKKOS_FORCEINLINE_FUNCTION bool existing() const { return (m_status & EXISTING); } - /// Did the map fail to insert the key due to insufficent capacity + /// Did the map fail to insert the key due to insufficient capacity KOKKOS_FORCEINLINE_FUNCTION bool failed() const { return m_index == UnorderedMapInvalidIndex; } diff --git a/lib/kokkos/containers/src/Kokkos_Vector.hpp b/lib/kokkos/containers/src/Kokkos_Vector.hpp index 9b151d9505..fb71f476c6 100644 --- a/lib/kokkos/containers/src/Kokkos_Vector.hpp +++ b/lib/kokkos/containers/src/Kokkos_Vector.hpp @@ -110,7 +110,7 @@ public: void assign (size_t n, const Scalar& val) { - /* Resize if necessary (behavour of std:vector) */ + /* Resize if necessary (behaviour of std:vector) */ if(n>span()) DV::resize(size_t (n*_extra_storage)); @@ -177,7 +177,7 @@ public: const_reference back() const {return DV::h_view(_size - 1);} - /* std::algorithms wich work originally with iterators, here they are implemented as member functions */ + /* std::algorithms witch work originally with iterators, here they are implemented as member functions */ size_t lower_bound (const size_t& start, diff --git a/lib/kokkos/containers/unit_tests/TestBitset.hpp b/lib/kokkos/containers/unit_tests/TestBitset.hpp index 371c0288b1..55d0e8b938 100644 --- a/lib/kokkos/containers/unit_tests/TestBitset.hpp +++ b/lib/kokkos/containers/unit_tests/TestBitset.hpp @@ -216,7 +216,7 @@ void test_bitset() bitset_type bitset(test_sizes[i]); - //std::cout << " Check inital count " << std::endl; + //std::cout << " Check initial count " << std::endl; // nothing should be set { Impl::TestBitsetTest< bitset_type > f(bitset); diff --git a/lib/kokkos/containers/unit_tests/TestViewCtorPropEmbeddedDim.hpp b/lib/kokkos/containers/unit_tests/TestViewCtorPropEmbeddedDim.hpp index d4b7cf0bdb..2dd5c56cd9 100644 --- a/lib/kokkos/containers/unit_tests/TestViewCtorPropEmbeddedDim.hpp +++ b/lib/kokkos/containers/unit_tests/TestViewCtorPropEmbeddedDim.hpp @@ -64,7 +64,7 @@ struct TestViewCtorProp_EmbeddedDim { using DynRankViewIntType = typename Kokkos::DynRankView< int, ExecSpace >; using DynRankViewDoubleType = typename Kokkos::DynRankView< double, ExecSpace >; - // Cuda 7.0 has issues with using a lamda in parallel_for to initialize the view - replace with this functor + // Cuda 7.0 has issues with using a lambda in parallel_for to initialize the view - replace with this functor template < class ViewType > struct Functor { diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.hpp index 8363a45662..cfc46f0461 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.hpp @@ -113,10 +113,10 @@ Kokkos::Impl::CudaLockArrays g_device_cuda_lock_arrays ; #define CUDA_SPACE_ATOMIC_MASK 0x1FFFF -/// \brief Aquire a lock for the address +/// \brief Acquire a lock for the address /// -/// This function tries to aquire the lock for the hash value derived -/// from the provided ptr. If the lock is successfully aquired the +/// This function tries to acquire the lock for the hash value derived +/// from the provided ptr. If the lock is successfully acquired the /// function returns true. Otherwise it returns false. __device__ inline bool lock_address_cuda_space(void* ptr) { @@ -130,7 +130,7 @@ bool lock_address_cuda_space(void* ptr) { /// /// This function releases the lock for the hash value derived /// from the provided ptr. This function should only be called -/// after previously successfully aquiring a lock with +/// after previously successfully acquiring a lock with /// lock_address. __device__ inline void unlock_address_cuda_space(void* ptr) { diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Parallel.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Parallel.hpp index c05fbcc6c1..860d94d6c7 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Parallel.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Parallel.hpp @@ -309,11 +309,11 @@ public: , m_thread_scratch_size {0,0} , m_chunk_size ( 32 ) { - // Make sure league size is permissable + // Make sure league size is permissible if(league_size_ >= int(Impl::cuda_internal_maximum_grid_count())) Impl::throw_runtime_exception( "Requested too large league_size for TeamPolicy on Cuda execution space."); - // Make sure total block size is permissable + // Make sure total block size is permissible if ( m_team_size * m_vector_length > 1024 ) { Impl::throw_runtime_exception(std::string("Kokkos::TeamPolicy< Cuda > the team size is too large. Team size x vector length must be smaller than 1024.")); } @@ -332,7 +332,7 @@ public: , m_thread_scratch_size {0,0} , m_chunk_size ( 32 ) { - // Make sure league size is permissable + // Make sure league size is permissible if(league_size_ >= int(Impl::cuda_internal_maximum_grid_count())) Impl::throw_runtime_exception( "Requested too large league_size for TeamPolicy on Cuda execution space."); } @@ -348,11 +348,11 @@ public: , m_thread_scratch_size {0,0} , m_chunk_size ( 32 ) { - // Make sure league size is permissable + // Make sure league size is permissible if(league_size_ >= int(Impl::cuda_internal_maximum_grid_count())) Impl::throw_runtime_exception( "Requested too large league_size for TeamPolicy on Cuda execution space."); - // Make sure total block size is permissable + // Make sure total block size is permissible if ( m_team_size * m_vector_length > 1024 ) { Impl::throw_runtime_exception(std::string("Kokkos::TeamPolicy< Cuda > the team size is too large. Team size x vector length must be smaller than 1024.")); } @@ -369,7 +369,7 @@ public: , m_thread_scratch_size {0,0} , m_chunk_size ( 32 ) { - // Make sure league size is permissable + // Make sure league size is permissible if(league_size_ >= int(Impl::cuda_internal_maximum_grid_count())) Impl::throw_runtime_exception( "Requested too large league_size for TeamPolicy on Cuda execution space."); } diff --git a/lib/kokkos/core/src/Kokkos_Concepts.hpp b/lib/kokkos/core/src/Kokkos_Concepts.hpp index 98ae141de4..ca2e8b4eb6 100644 --- a/lib/kokkos/core/src/Kokkos_Concepts.hpp +++ b/lib/kokkos/core/src/Kokkos_Concepts.hpp @@ -284,7 +284,7 @@ public: >::type host_mirror_space ; }; -// For backward compatiblity +// For backward compatibility namespace Impl { diff --git a/lib/kokkos/core/src/Kokkos_CopyViews.hpp b/lib/kokkos/core/src/Kokkos_CopyViews.hpp index f919fdb755..9210f21ab7 100644 --- a/lib/kokkos/core/src/Kokkos_CopyViews.hpp +++ b/lib/kokkos/core/src/Kokkos_CopyViews.hpp @@ -1247,7 +1247,7 @@ void deep_copy typename ViewType::value_type >::value , "deep_copy requires non-const type" ); - // If contigous we can simply do a 1D flat loop + // If contiguous we can simply do a 1D flat loop if(dst.span_is_contiguous()) { typedef Kokkos::View diff --git a/lib/kokkos/core/src/Qthreads/Kokkos_Qthreads_TaskQueue_impl.hpp b/lib/kokkos/core/src/Qthreads/Kokkos_Qthreads_TaskQueue_impl.hpp index 152546fadc..c79332f653 100644 --- a/lib/kokkos/core/src/Qthreads/Kokkos_Qthreads_TaskQueue_impl.hpp +++ b/lib/kokkos/core/src/Qthreads/Kokkos_Qthreads_TaskQueue_impl.hpp @@ -318,7 +318,7 @@ void TaskQueue< ExecSpace >::complete // If 'task' is an aggregate then any of the runnable tasks that // it depends upon may be attempting to complete this 'task'. // Must only transition a task once to complete status. - // This is controled by atomically locking the wait queue. + // This is controlled by atomically locking the wait queue. // Stop other tasks from adding themselves to this task's wait queue // by locking the head of this task's wait queue. diff --git a/lib/kokkos/core/src/Threads/Kokkos_ThreadsExec.cpp b/lib/kokkos/core/src/Threads/Kokkos_ThreadsExec.cpp index 347778f289..1a9a837af7 100644 --- a/lib/kokkos/core/src/Threads/Kokkos_ThreadsExec.cpp +++ b/lib/kokkos/core/src/Threads/Kokkos_ThreadsExec.cpp @@ -638,7 +638,7 @@ void ThreadsExec::initialize // Spawn thread executing the 'driver()' function. // Wait until spawned thread has attempted to initialize. - // If spawning and initialization is successfull then + // If spawning and initialization are successful then // an entry in 's_threads_exec' will be assigned. if ( ThreadsExec::spawn() ) { wait_yield( s_threads_process.m_pool_state , ThreadsExec::Inactive ); @@ -666,7 +666,7 @@ void ThreadsExec::initialize memory_fence(); if ( ! thread_spawn_failed ) { - // Bind process to the core on which it was located before spawning occured + // Bind process to the core on which it was located before spawning occurred if (hwloc_can_bind) { Kokkos::hwloc::bind_this_thread( proc_coord ); } diff --git a/lib/kokkos/core/src/Threads/Kokkos_ThreadsExec_base.cpp b/lib/kokkos/core/src/Threads/Kokkos_ThreadsExec_base.cpp index f6443e146d..4876614245 100644 --- a/lib/kokkos/core/src/Threads/Kokkos_ThreadsExec_base.cpp +++ b/lib/kokkos/core/src/Threads/Kokkos_ThreadsExec_base.cpp @@ -52,7 +52,7 @@ #include #include -/* Standard C++ libaries */ +/* Standard C++ libraries */ #include #include @@ -159,7 +159,7 @@ void ThreadsExec::wait_yield( volatile int & flag , const int value ) #include #include -/* Standard C++ libaries */ +/* Standard C++ libraries */ #include #include diff --git a/lib/kokkos/core/src/impl/Kokkos_Error.cpp b/lib/kokkos/core/src/impl/Kokkos_Error.cpp index 33b0ba918d..dea856606c 100644 --- a/lib/kokkos/core/src/impl/Kokkos_Error.cpp +++ b/lib/kokkos/core/src/impl/Kokkos_Error.cpp @@ -110,7 +110,7 @@ std::string human_memory_size(size_t arg_bytes) */ /* Print call stack into an error stream, - * so one knows in which function the error occured. + * so one knows in which function the error occurred. * * Code copied from: * http://stupefydeveloper.blogspot.com/2008/10/cc-call-stack.html diff --git a/lib/kokkos/core/src/impl/Kokkos_HostBarrier.hpp b/lib/kokkos/core/src/impl/Kokkos_HostBarrier.hpp index 2416edbead..f7f1c4b50f 100644 --- a/lib/kokkos/core/src/impl/Kokkos_HostBarrier.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_HostBarrier.hpp @@ -68,7 +68,7 @@ namespace Kokkos { namespace Impl { // called split_release // // The purporse of the split functions is to allow the last thread to arrive -// an opprotunity to perform some actions before releasing the waiting threads +// an opportunity to perform some actions before releasing the waiting threads // // If all threads have arrived (and split_release has been call if using split_arrive) // before a wait type call, the wait may return quickly diff --git a/lib/kokkos/core/src/impl/Kokkos_HostThreadTeam.cpp b/lib/kokkos/core/src/impl/Kokkos_HostThreadTeam.cpp index ccb8393d08..383b2ec2dc 100644 --- a/lib/kokkos/core/src/impl/Kokkos_HostThreadTeam.cpp +++ b/lib/kokkos/core/src/impl/Kokkos_HostThreadTeam.cpp @@ -253,7 +253,7 @@ int HostThreadTeamData::get_work_stealing() noexcept HostThreadTeamData * const * const pool = (HostThreadTeamData**)( m_pool_scratch + m_pool_members ); - // Attempt from begining failed, try to steal from end of neighbor + // Attempt from beginning failed, try to steal from end of neighbor pair_int_t volatile * steal_range = & ( pool[ m_steal_rank ]->m_work_range ); diff --git a/lib/kokkos/core/src/impl/Kokkos_SharedAlloc.hpp b/lib/kokkos/core/src/impl/Kokkos_SharedAlloc.hpp index b5718573a2..54021a71be 100644 --- a/lib/kokkos/core/src/impl/Kokkos_SharedAlloc.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_SharedAlloc.hpp @@ -267,7 +267,7 @@ public: // Use macros instead of inline functions to reduce // pressure on compiler optimization by reducing - // number of symbols and inline functons. + // number of symbols and inline functions. #if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) diff --git a/lib/kokkos/core/src/impl/Kokkos_TaskNode.hpp b/lib/kokkos/core/src/impl/Kokkos_TaskNode.hpp index 35f8853f1f..49aa4b4b21 100644 --- a/lib/kokkos/core/src/impl/Kokkos_TaskNode.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_TaskNode.hpp @@ -536,7 +536,7 @@ public: void acquire_predecessor_from(runnable_task_type& other) { KOKKOS_EXPECTS(m_predecessor == nullptr || other.m_predecessor == m_predecessor); - // since we're transfering, no need to modify the reference count + // since we're transferring, no need to modify the reference count m_predecessor = other.m_predecessor; other.m_predecessor = nullptr; } @@ -545,7 +545,7 @@ public: void acquire_predecessor_from(runnable_task_type& other) volatile { KOKKOS_EXPECTS(m_predecessor == nullptr || other.m_predecessor == m_predecessor); - // since we're transfering, no need to modify the reference count + // since we're transferring, no need to modify the reference count m_predecessor = other.m_predecessor; other.m_predecessor = nullptr; } diff --git a/lib/kokkos/core/src/impl/Kokkos_TaskQueue_impl.hpp b/lib/kokkos/core/src/impl/Kokkos_TaskQueue_impl.hpp index b5f8db0085..7a0e00a2f2 100644 --- a/lib/kokkos/core/src/impl/Kokkos_TaskQueue_impl.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_TaskQueue_impl.hpp @@ -642,7 +642,7 @@ void TaskQueue< ExecSpace, MemorySpace>::complete // If 'task' is an aggregate then any of the runnable tasks that // it depends upon may be attempting to complete this 'task'. // Must only transition a task once to complete status. - // This is controled by atomically locking the wait queue. + // This is controlled by atomically locking the wait queue. // Stop other tasks from adding themselves to this task's wait queue // by locking the head of this task's wait queue. diff --git a/lib/kokkos/core/src/impl/Kokkos_Traits.hpp b/lib/kokkos/core/src/impl/Kokkos_Traits.hpp index a5af82838f..fc501cb73e 100644 --- a/lib/kokkos/core/src/impl/Kokkos_Traits.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_Traits.hpp @@ -132,7 +132,7 @@ template< typename T , class ... Args > struct are_integral { enum { value = // Accept std::is_integral OR std::is_enum as an integral value - // since a simple enum value is automically convertable to an + // since a simple enum value is automically convertible to an // integral value. ( std::is_integral::value || std::is_enum::value ) && diff --git a/lib/kokkos/core/unit_test/TestTeam.hpp b/lib/kokkos/core/unit_test/TestTeam.hpp index 5f325eb905..ff3977637c 100644 --- a/lib/kokkos/core/unit_test/TestTeam.hpp +++ b/lib/kokkos/core/unit_test/TestTeam.hpp @@ -1068,7 +1068,7 @@ struct TestTeamBroadcast { } ASSERT_EQ( size_t( expected_result ), size_t( total ) ); //printf("team_broadcast with value -- expected_result=%d, total=%d\n",expected_result, total); - //team_broadcast with funtion object + //team_broadcast with function object total = 0; Kokkos::parallel_reduce( policy_type_f( league_size, team_size ), functor, total ); @@ -1078,7 +1078,7 @@ struct TestTeamBroadcast { value_type val = ((i%team_size)*3+1)*2*team_size; expected_result+= val; } - ASSERT_EQ( size_t( expected_result ), size_t( total ) ); //printf("team_broadcast with funtion object -- expected_result=%d, total=%d\n",expected_result, total); + ASSERT_EQ( size_t( expected_result ), size_t( total ) ); //printf("team_broadcast with function object -- expected_result=%d, total=%d\n",expected_result, total); } }; diff --git a/lib/kokkos/core/unit_test/TestTeamVector.hpp b/lib/kokkos/core/unit_test/TestTeamVector.hpp index 45433012f9..46f2c98e37 100644 --- a/lib/kokkos/core/unit_test/TestTeamVector.hpp +++ b/lib/kokkos/core/unit_test/TestTeamVector.hpp @@ -570,7 +570,7 @@ struct functor_vec_single { KOKKOS_INLINE_FUNCTION void operator()( typename policy_type::member_type team ) const { - // Warning: this test case intentionally violates permissable semantics. + // Warning: this test case intentionally violates permissible semantics. // It is not valid to get references to members of the enclosing region // inside a parallel_for and write to it. Scalar value = 0; diff --git a/lib/kokkos/core/unit_test/TestViewCtorPropEmbeddedDim.hpp b/lib/kokkos/core/unit_test/TestViewCtorPropEmbeddedDim.hpp index 0b88052129..7730be2e1d 100644 --- a/lib/kokkos/core/unit_test/TestViewCtorPropEmbeddedDim.hpp +++ b/lib/kokkos/core/unit_test/TestViewCtorPropEmbeddedDim.hpp @@ -60,7 +60,7 @@ struct TestViewCtorProp_EmbeddedDim { using ViewIntType = typename Kokkos::View< int**, ExecSpace >; using ViewDoubleType = typename Kokkos::View< double*, ExecSpace >; - // Cuda 7.0 has issues with using a lamda in parallel_for to initialize the view - replace with this functor + // Cuda 7.0 has issues with using a lambda in parallel_for to initialize the view - replace with this functor template < class ViewType > struct Functor { diff --git a/lib/kokkos/core/unit_test/TestWorkGraph.hpp b/lib/kokkos/core/unit_test/TestWorkGraph.hpp index 248733420b..331d79d72a 100644 --- a/lib/kokkos/core/unit_test/TestWorkGraph.hpp +++ b/lib/kokkos/core/unit_test/TestWorkGraph.hpp @@ -55,7 +55,7 @@ namespace { The algorithm computes the N-th fibonacci number as follows: - Each "task" or "work item" computes the i-th fibonacci number - If a task as (i < 2), it will record the known answer ahead of time. - - If a taks has (i >= 2), it will "spawn" two more tasks to compute + - If a task has (i >= 2), it will "spawn" two more tasks to compute the (i - 1) and (i - 2) fibonacci numbers. We do NOT do any de-duplication of these tasks. De-duplication would result in only (N - 2) tasks which must be run in serial. diff --git a/lib/kokkos/example/fenl/fenl_functors.hpp b/lib/kokkos/example/fenl/fenl_functors.hpp index 96c89de29b..538f009a3f 100644 --- a/lib/kokkos/example/fenl/fenl_functors.hpp +++ b/lib/kokkos/example/fenl/fenl_functors.hpp @@ -250,7 +250,7 @@ public: const typename SetType::insert_result result = node_node_set.insert( key ); - // A successfull insert: the first time this pair was added + // A successful insert: the first time this pair was added if ( result.success() ) { // If row node is owned then increment count diff --git a/lib/kokkos/example/multi_fem/BoxMeshPartition.hpp b/lib/kokkos/example/multi_fem/BoxMeshPartition.hpp index b8f43d2a22..ea5d1de008 100644 --- a/lib/kokkos/example/multi_fem/BoxMeshPartition.hpp +++ b/lib/kokkos/example/multi_fem/BoxMeshPartition.hpp @@ -172,7 +172,7 @@ void box_partition_rcb( const BoxType & root_box , //---------------------------------------------------------------------------- /* Determine local id layout and communication maps for partitioned boxes. * - * Local ids are layed out as follows: + * Local ids are laid out as follows: * { [ owned-interior ids not sent ] , * [ owned-boundary ids to be sent to other processes ] , * [ received ids from processor ( my_part + 1 ) % part_count ] diff --git a/lib/kokkos/example/multi_fem/Implicit.hpp b/lib/kokkos/example/multi_fem/Implicit.hpp index f129c59546..7ca180bd2a 100644 --- a/lib/kokkos/example/multi_fem/Implicit.hpp +++ b/lib/kokkos/example/multi_fem/Implicit.hpp @@ -222,7 +222,7 @@ PerformanceData run( const typename FixtureType::FEMeshType & mesh , } //------------------------------------ - // Solve linear sytem + // Solve linear system cgsolve( mesh.parallel_data_map , linsys_matrix , linsys_rhs , linsys_solution , diff --git a/lib/kokkos/example/multi_fem/Nonlinear.hpp b/lib/kokkos/example/multi_fem/Nonlinear.hpp index b9585c7582..f5e462cc4b 100644 --- a/lib/kokkos/example/multi_fem/Nonlinear.hpp +++ b/lib/kokkos/example/multi_fem/Nonlinear.hpp @@ -389,7 +389,7 @@ PerformanceData run( const typename FixtureType::FEMeshType & mesh , } //------------------------------------ - // Solve linear sytem + // Solve linear system size_t cg_iteration_count = 0 ; double cg_residual_norm = 0 ; diff --git a/lib/kokkos/example/tutorial/03_simple_view/Makefile b/lib/kokkos/example/tutorial/03_simple_view/Makefile index de994a8df9..c9dc3a0fd0 100644 --- a/lib/kokkos/example/tutorial/03_simple_view/Makefile +++ b/lib/kokkos/example/tutorial/03_simple_view/Makefile @@ -43,7 +43,7 @@ include $(KOKKOS_PATH)/Makefile.kokkos build: $(EXE) -#for unit testing only, for best preformance with OpenMP 4.0 or better +#for unit testing only, for best performance with OpenMP 4.0 or better test: $(EXE) ./$(EXE) diff --git a/lib/kokkos/example/tutorial/Algorithms/01_random_numbers/random_numbers.cpp b/lib/kokkos/example/tutorial/Algorithms/01_random_numbers/random_numbers.cpp index 48b0d86cb8..f2095e346f 100644 --- a/lib/kokkos/example/tutorial/Algorithms/01_random_numbers/random_numbers.cpp +++ b/lib/kokkos/example/tutorial/Algorithms/01_random_numbers/random_numbers.cpp @@ -61,10 +61,10 @@ typedef Kokkos::HostSpace::execution_space DefaultHostType; // In Kokkos you are required to create a pool of generator states, so that threads can // grep their own. On CPU architectures the pool size is equal to the thread number, // on CUDA about 128k states are generated (enough to give every potentially simultaneously -// running thread its own state). With a kernel a thread is required to aquire a state from the +// running thread its own state). With a kernel a thread is required to acquire a state from the // pool and later return it. // On CPUs the Random number generator is deterministic if using the same number of threads. -// On GPUs (i.e. using the CUDA backend it is not deterministic because threads aquire states via +// On GPUs (i.e. using the CUDA backend it is not deterministic because threads acquire states via // atomics. // A Functor for generating uint64_t random numbers templated on the GeneratorPool type @@ -97,7 +97,7 @@ struct generate_random { for(int k = 0;k *> \verbatim *> -*> DLALSA is an itermediate step in solving the least squares problem +*> DLALSA is an intermediate step in solving the least squares problem *> by computing the SVD of the coefficient matrix in compact form (The *> singular vectors are computed as products of simple orthorgonal *> matrices.). diff --git a/lib/linalg/dlasd7.f b/lib/linalg/dlasd7.f index e0ddedeb57..66f665cf88 100644 --- a/lib/linalg/dlasd7.f +++ b/lib/linalg/dlasd7.f @@ -400,7 +400,7 @@ VL( I ) = VLW( IDXI ) 50 CONTINUE * -* Calculate the allowable deflation tolerence +* Calculate the allowable deflation tolerance * EPS = DLAMCH( 'Epsilon' ) TOL = MAX( ABS( ALPHA ), ABS( BETA ) ) diff --git a/lib/linalg/iparam2stage.F b/lib/linalg/iparam2stage.F index 7062b45aac..ecf30dbea8 100644 --- a/lib/linalg/iparam2stage.F +++ b/lib/linalg/iparam2stage.F @@ -87,14 +87,14 @@ *> *> \param[in] NBI *> \verbatim -*> NBI is INTEGER which is the used in the reduciton, +*> NBI is INTEGER which is the used in the reduction, * (e.g., the size of the band), needed to compute workspace * and LHOUS2. *> \endverbatim *> *> \param[in] IBI *> \verbatim -*> IBI is INTEGER which represent the IB of the reduciton, +*> IBI is INTEGER which represent the IB of the reduction, * needed to compute workspace and LHOUS2. *> \endverbatim *> diff --git a/lib/message/README b/lib/message/README index dafb94e9ef..e6e7d2103d 100644 --- a/lib/message/README +++ b/lib/message/README @@ -2,7 +2,7 @@ This directory contains the CSlib library which is required to use the MESSAGE package and its client/server commands in a LAMMPS input script. -The CSlib libary is included in the LAMMPS distribution. A fuller +The CSlib library is included in the LAMMPS distribution. A fuller version including documentation and test programs is available at http://cslib.sandia.gov. It was developed by Steve Plimpton at Sandia National Laboratories. diff --git a/lib/molfile/molfile_plugin.h b/lib/molfile/molfile_plugin.h index c79e7a5abf..057c403369 100644 --- a/lib/molfile/molfile_plugin.h +++ b/lib/molfile/molfile_plugin.h @@ -662,7 +662,7 @@ typedef struct { int **bondtype, int *nbondtypes, char ***bondtypename); /** - * XXX this function will be augmented and possibly superceded by a + * XXX this function will be augmented and possibly superseded by a * new QM-capable version named read_timestep(), when finished. * * Read the next timestep from the file. Return MOLFILE_SUCCESS, or diff --git a/lib/plumed/README b/lib/plumed/README index 0d5f52f6b2..6b9b22bbce 100644 --- a/lib/plumed/README +++ b/lib/plumed/README @@ -3,7 +3,7 @@ to use the PLUMED package and its fix plumed command in a LAMMPS input script. PLUMED should only be downloaded into this directory if you wish to statically link the library. If you wish to link PLUMED as a dynamic library (as we recommend) then you can compile and build PLUMED -separately to LAMMPS. To use PLUMED in conjuction with LAMMPS you then simply +separately to LAMMPS. To use PLUMED in conjunction with LAMMPS you then simply need to ensure that the PLUMED library is in your path at runtime. More info about the PLUMED library can be found at http://www.plumed.org. diff --git a/lib/poems/SystemProcessor.h b/lib/poems/SystemProcessor.h index 3be168c34d..f376890e99 100644 --- a/lib/poems/SystemProcessor.h +++ b/lib/poems/SystemProcessor.h @@ -124,7 +124,7 @@ POEMSChain * SystemProcessor::AddNewChain(POEMSNode * currentNode){ return NULL; } int * tmp; - POEMSNode * nextNode = NULL; //nextNode stores the proposed next node to add to the chain. this will be checked to make sure no backtracking is occuring before being assigned as the current node. + POEMSNode * nextNode = NULL; //nextNode stores the proposed next node to add to the chain. this will be checked to make sure no backtracking is occurring before being assigned as the current node. POEMSChain * newChain = new POEMSChain; //make a new POEMSChain object. This will be the object returned if(currentNode->links.GetNumElements() == 0) //if we have no links from this node, then the whole chain is only one node. Add this node to the chain and return it; mark node as visited for future reference @@ -226,7 +226,7 @@ bool SystemProcessor::setLinkVisited(POEMSNode * firstNode, POEMSNode * secondNo //cout << "Checking link between nodes " << firstNode->idNumber << " and " << secondNode->idNumber << "... "; ListElement * tmp = firstNode->links.GetHeadElement(); //get the head element of the list of pointers for node 1 ListElement * tmp2 = firstNode->taken.GetHeadElement(); //get the head element of the list of bool isVisited flags for node 1 - while(tmp->value != NULL || tmp2->value != NULL) //go through untill we reach the end of the lists + while(tmp->value != NULL || tmp2->value != NULL) //go through until we reach the end of the lists { if(tmp->value == secondNode) //if we find the link to the other node { diff --git a/lib/poems/fastmatrixops.h b/lib/poems/fastmatrixops.h index e7ccdbd0ca..c7e29f8903 100644 --- a/lib/poems/fastmatrixops.h +++ b/lib/poems/fastmatrixops.h @@ -38,7 +38,7 @@ void FastLUSubs(Mat3x3& LU, Matrix& B, Matrix& C, int *indx); // Appropriate For void FastLUSubs(Mat4x4& LU, Matrix& B, Matrix& C, int *indx); // Appropriate Forward and Back Substitution void FastLUSubs(Mat6x6& LU, Matrix& B, Matrix& C, int *indx); // Appropriate Forward and Back Substitution // The following LUSubsLH routine is incomplete at the moment. -void FastLUSubsLH(Matrix& B, Matrix& LU, Matrix& C, int *indx); // Appropriate Forward and Back Subsitution +void FastLUSubsLH(Matrix& B, Matrix& LU, Matrix& C, int *indx); // Appropriate Forward and Back Substitution void FastTripleSum(Vect3& a, Vect3& b, Vect3& c, Vect3& d); // d = a+b+c void FastTripleSumPPM(Vect3& a, Vect3& b, Vect3& c, Vect3& d); // d = a+b-c diff --git a/lib/poems/joint.cpp b/lib/poems/joint.cpp index 3bdd7b5fcd..3477c7e336 100644 --- a/lib/poems/joint.cpp +++ b/lib/poems/joint.cpp @@ -186,12 +186,12 @@ Mat3x3* Joint::Get_kCpk(){ } Matrix Joint::GetForward_sP(){ - cerr << "ERROR: Forward Spatial Partial Velocity is not suported for joint type " << GetType() << endl; + cerr << "ERROR: Forward Spatial Partial Velocity is not supported for joint type " << GetType() << endl; exit(0); } Matrix Joint::GetBackward_sP(){ - cerr << "ERROR: Backward Spatial Partial Velocity is not suported for joint type " << GetType() << endl; + cerr << "ERROR: Backward Spatial Partial Velocity is not supported for joint type " << GetType() << endl; exit(0); } diff --git a/lib/poems/matrixfun.cpp b/lib/poems/matrixfun.cpp index d193114679..9aa2818555 100644 --- a/lib/poems/matrixfun.cpp +++ b/lib/poems/matrixfun.cpp @@ -209,7 +209,7 @@ Matrix operator+ (const VirtualMatrix &A, const VirtualMatrix &B){ // addit Bcols = B.GetNumCols(); if( !((Arows == Brows) && (Acols == Bcols)) ){ - cerr << "Dimesion mismatch in matrix addition" << endl; + cerr << "Dimension mismatch in matrix addition" << endl; exit(1); } @@ -234,7 +234,7 @@ Matrix operator- (const VirtualMatrix &A, const VirtualMatrix &B){ // subtr Bcols = B.GetNumCols(); if( !((Arows == Brows) && (Acols == Bcols)) ){ - cerr << "Dimesion mismatch in matrix addition" << endl; + cerr << "Dimension mismatch in matrix addition" << endl; exit(1); } @@ -259,7 +259,7 @@ Matrix operator* (const VirtualMatrix &A, const VirtualMatrix &B){ // multi Bcols = B.GetNumCols(); if(Acols != Brows){ - cerr << "Dimesion mismatch in matrix multiplication" << endl; + cerr << "Dimension mismatch in matrix multiplication" << endl; exit(1); } diff --git a/lib/poems/poemstree.h b/lib/poems/poemstree.h index 8f8e80ab66..d330fdad26 100644 --- a/lib/poems/poemstree.h +++ b/lib/poems/poemstree.h @@ -455,7 +455,7 @@ void Tree::Delete(const int& item) TreeNode *DNodePtr, *PNodePtr, *RNodePtr; // search for a node containing data value item. obtain its - // node adress and that of its parent + // node address and that of its parent if ((DNodePtr = FindNode (item, PNodePtr)) == NULL) return; @@ -576,7 +576,7 @@ TreeNode *Tree::CopyTree(TreeNode *t) // us the postorder scanning algorithm to traverse the nodes in -// the tree and delete each node as the vist operation +// the tree and delete each node as the visit operation void Tree::DeleteTree(TreeNode *t) { if (t != NULL) { diff --git a/lib/qmmm/README b/lib/qmmm/README index 13d17c055e..196aa4d7e0 100644 --- a/lib/qmmm/README +++ b/lib/qmmm/README @@ -31,7 +31,7 @@ will need to perform the remaining steps manually, as outlined below. ------------------------------------------------- WARNING: This is code depending on two software packages that are -independently maitained and are under continuous active developement. +independently maitained and are under continuous active development. It is thus much easier to break the QM/MM interface without noticing. Thus please test *very* carefully before using this software for production calculations. diff --git a/lib/scafacos/README b/lib/scafacos/README index e5f1ecd92c..86335d9f98 100644 --- a/lib/scafacos/README +++ b/lib/scafacos/README @@ -3,7 +3,7 @@ is required to use the KSPACE scafacos and its kspace_style scafacos command in a LAMMPS input script. The ScaFaCoS library is available at http://scafacos.de or -on github at https://github.com/scafacos, the libary was +on github at https://github.com/scafacos, the library was developed by a consortium of different universities in Germany (Bonn, Chemnitz, Stuttgart, Wuppertal) and the Research Centre Juelich (Juelich Supercomputing Centre). @@ -47,17 +47,17 @@ Instructions: are: direct, ewald, fmm, p2nfft The other solvers might work, but support is purely experimental at the moment. To - give a list of solvers, use a comma seperated + give a list of solvers, use a comma separated list. --fcs-disable-doc: disables the compilation of the documentation, e.g. if no Latex is available on the system. 4.) To build the library after configuration, run 'make' from the base folder. -5.) To install the libray in the designated installation folder, run 'make install'. +5.) To install the library in the designated installation folder, run 'make install'. Installation is required, as ScaFaCoS does not support an in-source build! -6.) Create two soft links to this directory (lib/scafacos) to where the libary +6.) Create two soft links to this directory (lib/scafacos) to where the library is installed. E.g. if you built ScaFaCoS in the default install directory: % ln -s /usr/local/include includelink % ln -s /usr/local/lib liblink diff --git a/potentials/BNCH-old.ILP b/potentials/BNCH-old.ILP index 30219e2a1e..2830172a86 100644 --- a/potentials/BNCH-old.ILP +++ b/potentials/BNCH-old.ILP @@ -1,5 +1,5 @@ # Interlayer Potential (ILP) for bilayer graphene/graphene, graphene/hBN and hBN/hBN junctions -# The parameters below are fitted against the HSE + MBD DFT referece data from 3.1 A to 15 A. +# The parameters below are fitted against the HSE + MBD DFT reference data from 3.1 A to 15 A. # Cite J. Chem.Theory Comput. 2016, 12, 2896-905 and J. Phys. Chem. C 2017, 121, 22826-22835. # beta alpha delta epsilon C d sR reff C6 S rcut diff --git a/potentials/BNCH.ILP b/potentials/BNCH.ILP index ed58adf946..eb15c35e0b 100644 --- a/potentials/BNCH.ILP +++ b/potentials/BNCH.ILP @@ -1,5 +1,5 @@ # Interlayer Potential (ILP) for bilayer graphene/graphene, graphene/hBN and hBN/hBN junctions -# The parameters below are fitted against the HSE + MBD DFT referece data from 2.5 A to 15 A. +# The parameters below are fitted against the HSE + MBD DFT reference data from 2.5 A to 15 A. # Cite as W. Ouyang, D. Mandelli, M. Urbakh and O. Hod, Nano Letters 18, 6009-6016 (2018). # # ----------------- Repulsion Potential ------------------++++++++++++++ Vdw Potential ++++++++++++++++************ diff --git a/potentials/BNC_MBD_bulk.ILP b/potentials/BNC_MBD_bulk.ILP index 9502e0a89a..9093f01447 100644 --- a/potentials/BNC_MBD_bulk.ILP +++ b/potentials/BNC_MBD_bulk.ILP @@ -1,5 +1,5 @@ # Interlayer Potential (ILP) for graphite, bulk-hBN and their heterojunctions -# The parameters below are fitted against the HSE + MBD DFT referece data from 2 A to 10 A. +# The parameters below are fitted against the HSE + MBD DFT reference data from 2 A to 10 A. # Cite as W. Ouyang et al., J. Chem. Theory Comput. 16(1), 666-676 (2020). # # ------------------------------ Repulsion Potential --------------------++++++++++++++ Vdw Potential ++++++++++++++++************ diff --git a/potentials/BNC_TS_bulk.ILP b/potentials/BNC_TS_bulk.ILP index 1baca2ace0..13de8b25fc 100644 --- a/potentials/BNC_TS_bulk.ILP +++ b/potentials/BNC_TS_bulk.ILP @@ -1,5 +1,5 @@ # Interlayer Potential (ILP) for graphite, bulk-hBN and their heterojunctions -# The parameters below are fitted against the HSE + TS DFT referece data from 2 A to 10 A. +# The parameters below are fitted against the HSE + TS DFT reference data from 2 A to 10 A. # Cite as W. Ouyang et al., J. Chem. Theory Comput. 16(1), 666-676 (2020). # # ------------------------------ Repulsion Potential ------------------++++++++++++++ Vdw Potential ++++++++++++++++************ diff --git a/python/examples/pylammps/montecarlo/mc.ipynb b/python/examples/pylammps/montecarlo/mc.ipynb index 86a2a8bc95..8509845a3d 100644 --- a/python/examples/pylammps/montecarlo/mc.ipynb +++ b/python/examples/pylammps/montecarlo/mc.ipynb @@ -887,7 +887,7 @@ " // Register the callback with on_msg.\n", " comm.on_msg(function(msg) {\n", " //console.log('receiving', msg['content']['data'], msg);\n", - " // Pass the mpl event to the overriden (by mpl) onmessage function.\n", + " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", " ws.onmessage(msg['content']['data'])\n", " });\n", " return ws;\n", diff --git a/python/lammps.py b/python/lammps.py index 484c30d9ac..bbe9c07a30 100644 --- a/python/lammps.py +++ b/python/lammps.py @@ -1037,7 +1037,7 @@ def get_thermo_data(output): items = line.split() # Convert thermo output and store it. # It must have the same number of columns and - # all of them must be convertable to floats. + # all of them must be convertible to floats. # Otherwise we ignore the line if len(items) == len(columns): try: diff --git a/src/COLLOID/pair_lubricateU.cpp b/src/COLLOID/pair_lubricateU.cpp index e8715cec36..b0e21256ac 100644 --- a/src/COLLOID/pair_lubricateU.cpp +++ b/src/COLLOID/pair_lubricateU.cpp @@ -988,7 +988,7 @@ void PairLubricateU::compute_RU() fy = vxmu2f*fy; fz = vxmu2f*fz; - // Add to the total forc + // Add to the total force f[i][0] -= fx; f[i][1] -= fy; @@ -1449,7 +1449,7 @@ void PairLubricateU::compute_RE() fy = vxmu2f*fy; fz = vxmu2f*fz; - // Add to the total forc + // Add to the total force f[i][0] -= fx; f[i][1] -= fy; @@ -1614,7 +1614,7 @@ void PairLubricateU::compute_RE(double **x) fy = vxmu2f*fy; fz = vxmu2f*fz; - // Add to the total forc + // Add to the total force f[i][0] -= fx; f[i][1] -= fy; diff --git a/src/COLLOID/pair_lubricateU_poly.cpp b/src/COLLOID/pair_lubricateU_poly.cpp index 0f16d94300..6b6727172d 100644 --- a/src/COLLOID/pair_lubricateU_poly.cpp +++ b/src/COLLOID/pair_lubricateU_poly.cpp @@ -849,7 +849,7 @@ void PairLubricateUPoly::compute_RU(double **x) fy = vxmu2f*fy; fz = vxmu2f*fz; - // Add to the total forc + // Add to the total force f[i][0] -= fx; f[i][1] -= fy; @@ -1044,7 +1044,7 @@ void PairLubricateUPoly::compute_RE(double **x) fy = vxmu2f*fy; fz = vxmu2f*fz; - // Add to the total forc + // Add to the total force f[i][0] -= fx; f[i][1] -= fy; diff --git a/src/CORESHELL/pair_born_coul_wolf_cs.cpp b/src/CORESHELL/pair_born_coul_wolf_cs.cpp index 398c2ba1ee..870a776a22 100644 --- a/src/CORESHELL/pair_born_coul_wolf_cs.cpp +++ b/src/CORESHELL/pair_born_coul_wolf_cs.cpp @@ -98,7 +98,7 @@ void PairBornCoulWolfCS::compute(int eflag, int vflag) if (rsq < cutsq[itype][jtype]) { rsq += EPSILON; - // Add EPISLON for case: r = 0; Interaction must be removed + // Add EPSILON for case: r = 0; Interaction must be removed // by special bond r2inv = 1.0/rsq; diff --git a/src/CORESHELL/pair_coul_wolf_cs.cpp b/src/CORESHELL/pair_coul_wolf_cs.cpp index 20b7339480..997a202e00 100644 --- a/src/CORESHELL/pair_coul_wolf_cs.cpp +++ b/src/CORESHELL/pair_coul_wolf_cs.cpp @@ -93,7 +93,7 @@ void PairCoulWolfCS::compute(int eflag, int vflag) if (rsq < cut_coulsq) { rsq += EPSILON; - // Add EPISLON for case: r = 0; Interaction must be removed + // Add EPSILON for case: r = 0; Interaction must be removed // by special bond r = sqrt(rsq); prefactor = qqrd2e*qtmp*q[j]/r; diff --git a/src/GPU/pair_born_coul_wolf_cs_gpu.cpp b/src/GPU/pair_born_coul_wolf_cs_gpu.cpp index b00b5a0b56..4e488abc15 100644 --- a/src/GPU/pair_born_coul_wolf_cs_gpu.cpp +++ b/src/GPU/pair_born_coul_wolf_cs_gpu.cpp @@ -249,7 +249,7 @@ void PairBornCoulWolfCSGPU::cpu_compute(int start, int inum, int eflag, jtype = type[j]; if (rsq < cutsq[itype][jtype]) { - rsq += EPSILON; // Add EPISLON for case: r = 0; Interaction must be removed by special bond + rsq += EPSILON; // Add EPSILON for case: r = 0; Interaction must be removed by special bond r2inv = 1.0/rsq; if (rsq < cut_coulsq) { diff --git a/src/KIM/README b/src/KIM/README index e61f47426f..d01ea42a7c 100644 --- a/src/KIM/README +++ b/src/KIM/README @@ -11,7 +11,7 @@ maintains the code that implements these commands. Using this package requires the KIM-API library and its models (interatomic potentials) to be downloaded and installed on your system. The library can be downloaded and built in lib/kim or -elsewhere on your system, which must be done before bulding LAMMPS +elsewhere on your system, which must be done before building LAMMPS with this package. Details of the download, build, and install process for the KIM-API are given in the lib/kim/README file, and scripts are provided to help automate the process. Also see the diff --git a/src/KIM/kim_units.cpp b/src/KIM/kim_units.cpp index 45f9b81a35..b059ec0d73 100644 --- a/src/KIM/kim_units.cpp +++ b/src/KIM/kim_units.cpp @@ -140,7 +140,7 @@ double const kcal_si = 4184.0; // [J] kilocalorie (heat energy // involved in warming up one // kilogram of water by one // degree Kelvin) -double const ev_si = 1.6021766208e-19; // [J] electon volt (amount of +double const ev_si = 1.6021766208e-19; // [J] electron volt (amount of // energy gained or lost by the // charge of a single electron // moving across an electric diff --git a/src/KOKKOS/atom_vec_bond_kokkos.cpp b/src/KOKKOS/atom_vec_bond_kokkos.cpp index 74c05a506c..4475131d77 100644 --- a/src/KOKKOS/atom_vec_bond_kokkos.cpp +++ b/src/KOKKOS/atom_vec_bond_kokkos.cpp @@ -625,7 +625,7 @@ struct AtomVecBondKokkos_PackExchangeFunctor { _lo(lo),_hi(hi){ // 3 comp of x, 3 comp of v, 1 tag, 1 type, 1 mask, 1 image, 1 molecule, 3 nspecial, // maxspecial special, 1 num_bond, bond_per_atom bond_type, bond_per_atom bond_atom, - // 1 to store buffer lenght + // 1 to store buffer length elements = 16+atom->maxspecial+atom->bond_per_atom+atom->bond_per_atom; const int maxsendlist = (buf.template view().extent(0)* buf.template view().extent(1))/elements; diff --git a/src/KOKKOS/comm_kokkos.cpp b/src/KOKKOS/comm_kokkos.cpp index 774d7040cc..a1ece37efd 100644 --- a/src/KOKKOS/comm_kokkos.cpp +++ b/src/KOKKOS/comm_kokkos.cpp @@ -478,7 +478,7 @@ void CommKokkos::reverse_comm_dump(Dump *dump) atoms exchanged with all 6 stencil neighbors send out atoms that have left my box, receive ones entering my box atoms will be lost if not inside some proc's box - can happen if atom moves outside of non-periodic bounary + can happen if atom moves outside of non-periodic boundary or if atom moves more than one proc away this routine called before every reneighboring for triclinic, atoms must be in lamda coords (0-1) before exchange is called diff --git a/src/KOKKOS/comm_tiled_kokkos.cpp b/src/KOKKOS/comm_tiled_kokkos.cpp index fc6de0a0d7..a29d9f63b3 100644 --- a/src/KOKKOS/comm_tiled_kokkos.cpp +++ b/src/KOKKOS/comm_tiled_kokkos.cpp @@ -113,7 +113,7 @@ void CommTiledKokkos::reverse_comm() atoms exchanged with procs that touch sub-box in each of 3 dims send out atoms that have left my box, receive ones entering my box atoms will be lost if not inside a touching proc's box - can happen if atom moves outside of non-periodic bounary + can happen if atom moves outside of non-periodic boundary or if atom moves more than one proc away this routine called before every reneighboring for triclinic, atoms must be in lamda coords (0-1) before exchange is called diff --git a/src/KOKKOS/fix_eos_table_rx_kokkos.h b/src/KOKKOS/fix_eos_table_rx_kokkos.h index 91d73f1036..21ec3d203b 100644 --- a/src/KOKKOS/fix_eos_table_rx_kokkos.h +++ b/src/KOKKOS/fix_eos_table_rx_kokkos.h @@ -207,6 +207,6 @@ Self-explanatory. E: Maxit exceeded in secant solver -The maximum number of interations was exceeded in the secant solver +The maximum number of iterations was exceeded in the secant solver */ diff --git a/src/KOKKOS/npair_ssa_kokkos.cpp b/src/KOKKOS/npair_ssa_kokkos.cpp index 5234c4e6d2..f9708e5fe8 100644 --- a/src/KOKKOS/npair_ssa_kokkos.cpp +++ b/src/KOKKOS/npair_ssa_kokkos.cpp @@ -234,7 +234,7 @@ int NPairSSAKokkosExecute::exclusion(const int &i,const int &j, /* ---------------------------------------------------------------------- binned neighbor list construction with full Newton's 3rd law - for use by Shardlow Spliting Algorithm + for use by Shardlow Splitting Algorithm each owned atom i checks its own bin and other bins in Newton stencil every pair stored exactly once by some processor ------------------------------------------------------------------------- */ diff --git a/src/KOKKOS/pair_exp6_rx_kokkos.cpp b/src/KOKKOS/pair_exp6_rx_kokkos.cpp index 8698687377..f3f63c98b2 100644 --- a/src/KOKKOS/pair_exp6_rx_kokkos.cpp +++ b/src/KOKKOS/pair_exp6_rx_kokkos.cpp @@ -1944,7 +1944,7 @@ void PairExp6rxKokkos::getMixingWeights(int id,double &epsilon1,doub fraction2 = nMolecules2/nTotal; } - // If Site1 or Site2 matches is a fluid, then compute the paramters + // If Site1 or Site2 matches is a fluid, then compute the parameters if (isOneFluidApprox(isite1) || isOneFluidApprox(isite2)) { if (isite1 == d_params[iparam].ispecies || isite2 == d_params[iparam].ispecies) continue; rmi = d_params[iparam].rm; @@ -2271,7 +2271,7 @@ void PairExp6rxKokkos::getMixingWeightsVect(const int np_total, int } } - // If Site1 or Site2 matches is a fluid, then compute the paramters + // If Site1 or Site2 matches is a fluid, then compute the parameters if (isOneFluidApprox(isite1) || isOneFluidApprox(isite2)) { if (isite1 == d_params[iparam].ispecies || isite2 == d_params[iparam].ispecies) continue; diff --git a/src/KOKKOS/pppm_kokkos.cpp b/src/KOKKOS/pppm_kokkos.cpp index 7085f06101..08a0c18f9c 100644 --- a/src/KOKKOS/pppm_kokkos.cpp +++ b/src/KOKKOS/pppm_kokkos.cpp @@ -836,7 +836,7 @@ void PPPMKokkos::allocate() h_rho_coeff = k_rho_coeff.h_view; // create 2 FFTs and a Remap - // 1st FFT keeps data in FFT decompostion + // 1st FFT keeps data in FFT decomposition // 2nd FFT returns data in 3d brick decomposition // remap takes data from 3d brick to FFT decomposition diff --git a/src/KOKKOS/sna_kokkos.h b/src/KOKKOS/sna_kokkos.h index 133db2139f..48d9114fbf 100644 --- a/src/KOKKOS/sna_kokkos.h +++ b/src/KOKKOS/sna_kokkos.h @@ -228,7 +228,7 @@ private: // data for bispectrum coefficients - // Same accross all SNAKokkos + // Same across all SNAKokkos t_sna_1d cglist; t_sna_2d rootpqarray; diff --git a/src/KOKKOS/sna_kokkos_impl.h b/src/KOKKOS/sna_kokkos_impl.h index c8c9a07e3e..ef3312bd16 100644 --- a/src/KOKKOS/sna_kokkos_impl.h +++ b/src/KOKKOS/sna_kokkos_impl.h @@ -877,7 +877,7 @@ void SNAKokkos::compute_uarray(const typename Kokkos::TeamPolicyall(FLERR,"Matrix factorization to split dispersion coefficients failed"); @@ -1454,7 +1454,7 @@ int PPPMDisp::qr_alg(double **A, double **Q, int n) // allocate an auxiliary matrix Qi memory->create(Qi,n,n,"pppm/disp:Qi"); - // alllocate an auxillary matrices for the matrix multiplication + // alllocate an auxiliary matrices for the matrix multiplication memory->create(C,n,n,"pppm/disp:C"); memory->create(D,n,n,"pppm/disp:D"); memory->create(E,n,n,"pppm/disp:E"); @@ -3657,7 +3657,7 @@ void PPPMDisp::set_n_pppm_6() // initial value for the grid spacing h = h_x = h_y = h_z = 4.0/g_ewald_6; - // decrease grid spacing untill required precision is obtained + // decrease grid spacing until required precision is obtained int count = 0; while(1) { @@ -5760,7 +5760,7 @@ void PPPMDisp::fieldforce_c_ad() ekx *= hx_inv; eky *= hy_inv; ekz *= hz_inv; - // convert E-field to force and substract self forces + // convert E-field to force and subtract self forces const double qfactor = force->qqrd2e * scale; s1 = x[i][0]*hx_inv; diff --git a/src/KSPACE/pppm_disp_tip4p.cpp b/src/KSPACE/pppm_disp_tip4p.cpp index bc46152e2b..45217eb7a5 100644 --- a/src/KSPACE/pppm_disp_tip4p.cpp +++ b/src/KSPACE/pppm_disp_tip4p.cpp @@ -335,7 +335,7 @@ void PPPMDispTIP4P::fieldforce_c_ad() eky *= hy_inv; ekz *= hz_inv; - // convert E-field to force and substract self forces + // convert E-field to force and subtract self forces const double qfactor = force->qqrd2e * scale; s1 = x[i][0]*hx_inv; diff --git a/src/KSPACE/pppm_stagger.cpp b/src/KSPACE/pppm_stagger.cpp index 7b708d0355..d7466ee0d4 100644 --- a/src/KSPACE/pppm_stagger.cpp +++ b/src/KSPACE/pppm_stagger.cpp @@ -876,7 +876,7 @@ void PPPMStagger::fieldforce_ad() eky *= hy_inv; ekz *= hz_inv; - // convert E-field to force and substract self forces + // convert E-field to force and subtract self forces const double qfactor = qqrd2e * scale / float(nstagger); diff --git a/src/KSPACE/pppm_tip4p.cpp b/src/KSPACE/pppm_tip4p.cpp index 5a0ced3674..e2019d3f83 100644 --- a/src/KSPACE/pppm_tip4p.cpp +++ b/src/KSPACE/pppm_tip4p.cpp @@ -327,7 +327,7 @@ void PPPMTIP4P::fieldforce_ad() eky *= hy_inv; ekz *= hz_inv; - // convert E-field to force and substract self forces + // convert E-field to force and subtract self forces const double qfactor = qqrd2e * scale; diff --git a/src/MAKE/MACHINES/Makefile.redsky b/src/MAKE/MACHINES/Makefile.redsky index 551952181e..8e943bbb78 100644 --- a/src/MAKE/MACHINES/Makefile.redsky +++ b/src/MAKE/MACHINES/Makefile.redsky @@ -16,7 +16,7 @@ SHELL = /bin/sh # IMPORTANT NOTE: # to run efficiently on RedSky, use the "numa_wrapper" mpiexec option, -# to insure proceses and their memory are locked to specific cores +# to insure processes and their memory are locked to specific cores # e.g. in your batch script: # nodes=$SLURM_JOB_NUM_NODES # cores=8 diff --git a/src/MANYBODY/pair_airebo.cpp b/src/MANYBODY/pair_airebo.cpp index 1d9dd18887..84565a2e50 100644 --- a/src/MANYBODY/pair_airebo.cpp +++ b/src/MANYBODY/pair_airebo.cpp @@ -2081,9 +2081,9 @@ double PairAIREBO::bondorder(int i, int j, double rij[3], This function calculates S(t_b(b_ij*)) as specified in the AIREBO paper. To do so, it needs to compute b_ij*, i.e. the bondorder given that the -atoms i and j are placed a ficticious distance rijmag_mod apart. +atoms i and j are placed a fictitious distance rijmag_mod apart. Now there are two approaches to calculate the resulting forces: -1. Carry through the ficticious distance and corresponding vector +1. Carry through the fictitious distance and corresponding vector rij_mod, correcting afterwards using the derivative of r/|r|. 2. Perform all the calculations using the real distance, and do not use a correction, only using rijmag_mod where necessary. diff --git a/src/MANYBODY/pair_bop.h b/src/MANYBODY/pair_bop.h index eca0ec52b8..ea8da2844e 100644 --- a/src/MANYBODY/pair_bop.h +++ b/src/MANYBODY/pair_bop.h @@ -48,12 +48,12 @@ class PairBOP : public Pair { int maxbopn; // maximum size of bop neighbor list for allocation int maxnall; // maximum size of bop neighbor list for allocation int *map; // mapping from atom types to elements - int nelements; // # of unique elments + int nelements; // # of unique elements int nr; // increments for the BOP pair potential int ntheta; // increments for the angle function int npower; // power of the angular function int nBOt; // second BO increments - int bop_types; // number of elments in potential + int bop_types; // number of elements in potential int npairs; // number of element pairs char **elements; // names of unique elements int ***elem2param; diff --git a/src/MANYBODY/pair_lcbop.cpp b/src/MANYBODY/pair_lcbop.cpp index cc97fd9e9b..7c29f44afc 100644 --- a/src/MANYBODY/pair_lcbop.cpp +++ b/src/MANYBODY/pair_lcbop.cpp @@ -256,7 +256,7 @@ void PairLCBOP::SR_neigh() double **x = atom->x; - if (atom->nmax > maxlocal) { // ensure ther is enough space + if (atom->nmax > maxlocal) { // ensure there is enough space maxlocal = atom->nmax; // for atoms and ghosts allocated memory->destroy(SR_numneigh); memory->sfree(SR_firstneigh); diff --git a/src/MISC/dump_xtc.cpp b/src/MISC/dump_xtc.cpp index 1a2b71ab6d..a28d6acdfa 100644 --- a/src/MISC/dump_xtc.cpp +++ b/src/MISC/dump_xtc.cpp @@ -439,7 +439,7 @@ int xdropen(XDR *xdrs, const char *filename, const char *type) } xdrmodes[xdrid] = *type; - /* next test isn't usefull in the case of C language + /* next test isn't useful in the case of C language * but is used for the Fortran interface * (C users are expected to pass the address of an already allocated * XDR staructure) @@ -610,7 +610,7 @@ static int sizeofints( const int num_of_ints, unsigned int sizes[]) | this routine is used internally by xdr3dfcoord, to send a set of | small integers to the buffer. | Multiplication with fixed (specified maximum ) sizes is used to get - | to one big, multibyte integer. Allthough the routine could be + | to one big, multibyte integer. Although the routine could be | modified to handle sizes bigger than 16777216, or more than just | a few integers, this is not done, because the gain in compression | isn't worth the effort. Note that overflowing the multiplication @@ -758,7 +758,7 @@ static void receiveints(int buf[], const int num_of_ints, int num_of_bits, | using multiplication by *precision and rounding to the nearest integer. | Then the minimum and maximum value are calculated to determine the range. | The limited range of integers so found, is used to compress the coordinates. - | In addition the differences between succesive coordinates is calculated. + | In addition the differences between successive coordinates is calculated. | If the difference happens to be 'small' then only the difference is saved, | compressing the data even more. The notion of 'small' is changed dynamically | and is enlarged or reduced whenever needed or possible. diff --git a/src/MISC/fix_deposit.cpp b/src/MISC/fix_deposit.cpp index 5279b2df36..90b1063924 100644 --- a/src/MISC/fix_deposit.cpp +++ b/src/MISC/fix_deposit.cpp @@ -569,7 +569,7 @@ void FixDeposit::pre_exchange() // old code: unsuccessful if no proc performed insertion of an atom // don't think that check is necessary - // if get this far, should always be succesful + // if get this far, should always be successful // would be hard to undo partial insertion for a molecule // better to check how many atoms could be inserted (w/out inserting) // then sum to insure all are inserted, before doing actual insertion diff --git a/src/MPIIO/restart_mpiio.cpp b/src/MPIIO/restart_mpiio.cpp index e8ef5c6c4e..db511c7bc0 100644 --- a/src/MPIIO/restart_mpiio.cpp +++ b/src/MPIIO/restart_mpiio.cpp @@ -120,7 +120,7 @@ void RestartMPIIO::write(MPI_Offset headerOffset, int send_size, double *buf) if the consolidated chunksize is greater than INT_MAX can only happen in extreme situation of reading restart file on much fewer ranks than written and with relatively large data sizes - follow the collective IO call with rank independant IO to read remaining data + follow the collective IO call with rank independent IO to read remaining data ------------------------------------------------------------------------- */ void RestartMPIIO::read(MPI_Offset chunkOffset, bigint chunkSize, double *buf) diff --git a/src/MSCG/README b/src/MSCG/README index ed0ef37452..ab64c26792 100644 --- a/src/MSCG/README +++ b/src/MSCG/README @@ -8,7 +8,7 @@ developed by Jacob Wagner in Greg Voth's group at the University of Chicago. The library can be downloaded and built in lib/mscg or elsewhere on -your system, which must be done before bulding LAMMPS with this +your system, which must be done before building LAMMPS with this package. Details of the download, build, and install process for MSCG are given in the lib/mscg/README file. Also see the LAMMPS manual for general information on building LAMMPS with external libraries. The diff --git a/src/PERI/fix_peri_neigh.h b/src/PERI/fix_peri_neigh.h index 79006ab541..247ceaaa43 100644 --- a/src/PERI/fix_peri_neigh.h +++ b/src/PERI/fix_peri_neigh.h @@ -63,8 +63,8 @@ class FixPeriNeigh : public Fix { int maxpartner; // max # of peridynamic neighs for any atom int *npartner; // # of neighbors for each atom tagint **partner; // neighs for each atom, stored as global IDs - double **deviatorextention; // Deviatoric extention - double **deviatorBackextention; // Deviatoric back extention + double **deviatorextention; // Deviatoric extension + double **deviatorBackextention; // Deviatoric back extension double **deviatorPlasticextension; // Deviatoric plastic extension double *lambdaValue; double **r0; // initial distance to partners diff --git a/src/PERI/pair_peri_ves.cpp b/src/PERI/pair_peri_ves.cpp index 1cef9635a9..1d9f3819ff 100644 --- a/src/PERI/pair_peri_ves.cpp +++ b/src/PERI/pair_peri_ves.cpp @@ -317,7 +317,7 @@ void PairPeriVES::compute(int eflag, int vflag) dr - (theta[i]* r0[i][jj] / 3.0); deltaed = deviatoric_extension-deviatorextention[i][jj]; - // back extention at current step + // back extension at current step edbNp1 = deviatorextention[i][jj]*(1-decay) + deviatorBackextention[i][jj]*decay+betai*deltaed; @@ -357,7 +357,7 @@ void PairPeriVES::compute(int eflag, int vflag) // find stretch in bond I-J and break if necessary // use s0 from previous timestep - // store current deviatoric extention + // store current deviatoric extension deviatorextention[i][jj]=deviatoric_extension; deviatorBackextention[i][jj]=edbNp1; diff --git a/src/PYTHON/fix_python_move.h b/src/PYTHON/fix_python_move.h index 7b830a3d20..2220709970 100644 --- a/src/PYTHON/fix_python_move.h +++ b/src/PYTHON/fix_python_move.h @@ -11,7 +11,7 @@ See the README file in the top-level LAMMPS directory. Pair zero is a dummy pair interaction useful for requiring a - force cutoff distance in the absense of pair-interactions or + force cutoff distance in the absence of pair-interactions or with hybrid/overlay if a larger force cutoff distance is required. This can be used in conjunction with bond/create to create bonds diff --git a/src/PYTHON/pair_python.h b/src/PYTHON/pair_python.h index 69671f7322..4c3c00a70d 100644 --- a/src/PYTHON/pair_python.h +++ b/src/PYTHON/pair_python.h @@ -11,7 +11,7 @@ See the README file in the top-level LAMMPS directory. Pair zero is a dummy pair interaction useful for requiring a - force cutoff distance in the absense of pair-interactions or + force cutoff distance in the absence of pair-interactions or with hybrid/overlay if a larger force cutoff distance is required. This can be used in conjunction with bond/create to create bonds diff --git a/src/REPLICA/fix_event_hyper.h b/src/REPLICA/fix_event_hyper.h index 4c5d4a93ee..af685ee539 100644 --- a/src/REPLICA/fix_event_hyper.h +++ b/src/REPLICA/fix_event_hyper.h @@ -29,7 +29,7 @@ class FixEventHyper : public FixEvent { int event_number; // event counter bigint event_timestep; // timestep of last event on any replica bigint clock; // total elapsed timesteps across all replicas - int replica_number; // replica where last event occured + int replica_number; // replica where last event occurred int correlated_event; // 1 if last event was correlated, 0 otherwise int ncoincident; // # of simultaneous events on different replicas diff --git a/src/REPLICA/fix_event_prd.h b/src/REPLICA/fix_event_prd.h index 0924fb2bdc..363de31e9d 100644 --- a/src/REPLICA/fix_event_prd.h +++ b/src/REPLICA/fix_event_prd.h @@ -29,7 +29,7 @@ class FixEventPRD : public FixEvent { int event_number; // event counter bigint event_timestep; // timestep of last event on any replica bigint clock; // total elapsed timesteps across all replicas - int replica_number; // replica where last event occured + int replica_number; // replica where last event occurred int correlated_event; // 1 if last event was correlated, 0 otherwise int ncoincident; // # of simultaneous events on different replicas diff --git a/src/REPLICA/fix_hyper_global.cpp b/src/REPLICA/fix_hyper_global.cpp index 62ba35abfc..bc5df921c6 100644 --- a/src/REPLICA/fix_hyper_global.cpp +++ b/src/REPLICA/fix_hyper_global.cpp @@ -189,7 +189,7 @@ void FixHyperGlobal::pre_neighbor() // closest current I or J atoms to old I may now be ghost atoms // closest_image() returns the ghost atom index in that case // also compute max drift of any atom in a bond - // drift = displacement from quenched coord while event has not yet occured + // drift = displacement from quenched coord while event has not yet occurred // NOTE: drift calc is now done in bond_build(), between 2 quenched states for (i = 0; i < nall_old; i++) old2now[i] = -1; diff --git a/src/REPLICA/fix_hyper_local.cpp b/src/REPLICA/fix_hyper_local.cpp index dc02432751..eebcd08bdd 100644 --- a/src/REPLICA/fix_hyper_local.cpp +++ b/src/REPLICA/fix_hyper_local.cpp @@ -379,7 +379,7 @@ void FixHyperLocal::pre_neighbor() // closest current I or J atoms to old I may now be ghost atoms // closest_image() returns the ghost atom index in that case // also compute max drift of any atom in a bond - // drift = displacement from quenched coord while event has not yet occured + // drift = displacement from quenched coord while event has not yet occurred // NOTE: drift calc is now done in bond_build(), between 2 quenched states for (i = 0; i < nall_old; i++) old2now[i] = -1; @@ -796,7 +796,7 @@ void FixHyperLocal::pre_reverse(int /* eflag */, int /* vflag */) rmaxeverbig = rmax2all[1]; } - // if requsted, check for any biased bonds that are too close to each other + // if requested, check for any biased bonds that are too close to each other // keep a running count for output // requires 2 additional local comm operations @@ -887,7 +887,7 @@ void FixHyperLocal::build_bond_list(int natom) // reset Vmax to current bias coeff average // only if requested and elapsed time >= resetfreq - // ave = curent ave of all bias coeffs + // ave = current ave of all bias coeffs // if reset, adjust all Cij to keep Cij*Vmax unchanged if (resetfreq >= 0) { diff --git a/src/REPLICA/prd.cpp b/src/REPLICA/prd.cpp index f631cc6a0a..63e569d0c2 100644 --- a/src/REPLICA/prd.cpp +++ b/src/REPLICA/prd.cpp @@ -608,7 +608,7 @@ void PRD::quench() if replica_num is non-negative only check for event on replica_num if multiple events, choose one at random return -1 if no event - else return ireplica = world in which event occured + else return ireplica = world in which event occurred ------------------------------------------------------------------------- */ int PRD::check_event(int replica_num) diff --git a/src/RIGID/fix_rigid.cpp b/src/RIGID/fix_rigid.cpp index 9f6a1e5d46..d77bf988a6 100644 --- a/src/RIGID/fix_rigid.cpp +++ b/src/RIGID/fix_rigid.cpp @@ -2185,7 +2185,7 @@ void FixRigid::setup_bodies_static() /* ---------------------------------------------------------------------- one-time initialization of dynamic rigid body attributes set vcm and angmom, computed explicitly from constituent particles - not done if body properites read from file, e.g. for overlapping particles + not done if body properties read from file, e.g. for overlapping particles ------------------------------------------------------------------------- */ void FixRigid::setup_bodies_dynamic() @@ -2279,7 +2279,7 @@ void FixRigid::setup_bodies_dynamic() /* ---------------------------------------------------------------------- read per rigid body info from user-provided file - which = 0 to read everthing except 6 moments of inertia + which = 0 to read everything except 6 moments of inertia which = 1 to read 6 moments of inertia flag inbody = 0 for bodies whose info is read from file nlines = # of lines of rigid body info diff --git a/src/RIGID/fix_rigid_nh.h b/src/RIGID/fix_rigid_nh.h index 08208e5aac..1126e7bb50 100644 --- a/src/RIGID/fix_rigid_nh.h +++ b/src/RIGID/fix_rigid_nh.h @@ -54,7 +54,7 @@ class FixRigidNH : public FixRigid { int kspace_flag; // 1 if KSpace invoked, 0 if not int nrigidfix; // number of rigid fixes - int *rfix; // indicies of rigid fixes + int *rfix; // indices of rigid fixes double vol0; // reference volume double t0; // reference temperature diff --git a/src/RIGID/fix_rigid_nh_small.h b/src/RIGID/fix_rigid_nh_small.h index 207c2d0a11..e04290aee8 100644 --- a/src/RIGID/fix_rigid_nh_small.h +++ b/src/RIGID/fix_rigid_nh_small.h @@ -53,7 +53,7 @@ class FixRigidNHSmall : public FixRigidSmall { int kspace_flag; // 1 if KSpace invoked, 0 if not int nrigidfix; // number of rigid fixes - int *rfix; // indicies of rigid fixes + int *rfix; // indices of rigid fixes double vol0; // reference volume double t0; // reference temperature diff --git a/src/RIGID/fix_rigid_small.cpp b/src/RIGID/fix_rigid_small.cpp index 0b2c2d967f..9974a7f888 100644 --- a/src/RIGID/fix_rigid_small.cpp +++ b/src/RIGID/fix_rigid_small.cpp @@ -1091,7 +1091,7 @@ void FixRigidSmall::final_integrate_respa(int ilevel, int /*iloop*/) when unwrapped by true image flags then set_xv() will compute huge displacements every step to reset coords of all the body atoms to be back inside the box, ditto for triclinic box flip - note: so just want to avoid that numeric probem? + note: so just want to avoid that numeric problem? ------------------------------------------------------------------------- */ void FixRigidSmall::pre_neighbor() @@ -2320,7 +2320,7 @@ void FixRigidSmall::setup_bodies_static() /* ---------------------------------------------------------------------- one-time initialization of dynamic rigid body attributes vcm and angmom, computed explicitly from constituent particles - not done if body properites read from file, e.g. for overlapping particles + not done if body properties read from file, e.g. for overlapping particles ------------------------------------------------------------------------- */ void FixRigidSmall::setup_bodies_dynamic() @@ -2426,7 +2426,7 @@ void FixRigidSmall::setup_bodies_dynamic() /* ---------------------------------------------------------------------- read per rigid body info from user-provided file - which = 0 to read everthing except 6 moments of inertia + which = 0 to read everything except 6 moments of inertia which = 1 to read just 6 moments of inertia flag inbody = 0 for local bodies this proc initializes from file nlines = # of lines of rigid body info, 0 is OK diff --git a/src/RIGID/fix_shake.cpp b/src/RIGID/fix_shake.cpp index 054985ba72..3342f02194 100644 --- a/src/RIGID/fix_shake.cpp +++ b/src/RIGID/fix_shake.cpp @@ -3082,7 +3082,7 @@ void FixShake::correct_coordinates(int vflag) { dtfsq = 0.5 * update->dt * update->dt * force->ftm2v; FixShake::post_force(vflag); - // integrate coordiantes: x' = xnp1 + dt^2/2m_i * f, where f is the constraining force + // integrate coordinates: x' = xnp1 + dt^2/2m_i * f, where f is the constraining force // NOTE: After this command, the coordinates geometry of the molecules will be correct! double dtfmsq; diff --git a/src/SPIN/README b/src/SPIN/README index ad296c69b7..6dbad91d8d 100644 --- a/src/SPIN/README +++ b/src/SPIN/README @@ -9,7 +9,7 @@ atom in the system * implementing magnetic pair interactions and magnetic forces * thermostating and applying a transverse damping to the magnetic spins * performing geodesic NEB calculations -* computing and outputing magnetic quantities +* computing and outputting magnetic quantities * minimizing the energy or total torque of a magnetic system The different options provided by this package are explained in the diff --git a/src/SPIN/min_spin.cpp b/src/SPIN/min_spin.cpp index e39eb18744..f6a6b90891 100644 --- a/src/SPIN/min_spin.cpp +++ b/src/SPIN/min_spin.cpp @@ -127,7 +127,7 @@ int MinSpin::iterate(int maxiter) ntimestep = ++update->ntimestep; niter++; - // optimize timestep accross processes / replicas + // optimize timestep across processes / replicas // need a force calculation for timestep optimization if (iter == 0) energy_force(0); diff --git a/src/SPIN/min_spin_cg.cpp b/src/SPIN/min_spin_cg.cpp index 8815ad89db..de1ef39f66 100644 --- a/src/SPIN/min_spin_cg.cpp +++ b/src/SPIN/min_spin_cg.cpp @@ -205,7 +205,7 @@ int MinSpinCG::iterate(int maxiter) ntimestep = ++update->ntimestep; niter++; - // optimize timestep accross processes / replicas + // optimize timestep across processes / replicas // need a force calculation for timestep optimization if (use_line_search) { diff --git a/src/SPIN/min_spin_lbfgs.cpp b/src/SPIN/min_spin_lbfgs.cpp index 7f6d7692cd..df12782528 100644 --- a/src/SPIN/min_spin_lbfgs.cpp +++ b/src/SPIN/min_spin_lbfgs.cpp @@ -217,7 +217,7 @@ int MinSpinLBFGS::iterate(int maxiter) ntimestep = ++update->ntimestep; niter++; - // optimize timestep accross processes / replicas + // optimize timestep across processes / replicas // need a force calculation for timestep optimization if (use_line_search) { diff --git a/src/SRD/fix_srd.cpp b/src/SRD/fix_srd.cpp index d5eec91f50..cb193356d8 100644 --- a/src/SRD/fix_srd.cpp +++ b/src/SRD/fix_srd.cpp @@ -454,7 +454,7 @@ void FixSRD::setup(int /*vflag*/) setup_search_stencil(); } else nbins2 = 0; - // perform first bining of SRD and big particles and walls + // perform first binding of SRD and big particles and walls // set reneighflag to turn off SRD rotation // don't do SRD rotation in setup, only during timestepping @@ -1067,7 +1067,7 @@ void FixSRD::vbin_comm(int ishift) // send/recv bins in both directions in each dimension // don't send if nsend = 0 - // due to static bins aliging with proc boundary + // due to static bins aligning with proc boundary // due to dynamic bins across non-periodic global boundary // copy to self if sendproc = me // MPI send to another proc if sendproc != me @@ -1169,7 +1169,7 @@ void FixSRD::xbin_comm(int ishift, int nval) // send/recv bins in both directions in each dimension // don't send if nsend = 0 - // due to static bins aliging with proc boundary + // due to static bins aligning with proc boundary // due to dynamic bins across non-periodic global boundary // copy to self if sendproc = me // MPI send to another proc if sendproc != me diff --git a/src/USER-ATC/fix_atc.cpp b/src/USER-ATC/fix_atc.cpp index 0e9cd02ad6..2165132856 100644 --- a/src/USER-ATC/fix_atc.cpp +++ b/src/USER-ATC/fix_atc.cpp @@ -123,7 +123,7 @@ FixATC::FixATC(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), # be used as a localization function \n fix AtC kernel quartic_sphere 10.0 \n \n # create a uniform 1 x 1 x 1 mesh that covers region contain the group \n - # with periodicity this effectively creats a system average \n + # with periodicity this effectively creates a system average \n fix_modify AtC mesh create 1 1 1 box p p p \n\n # change from default lagrangian map to eulerian \n # refreshed every 100 steps \n diff --git a/src/USER-DIFFRACTION/README b/src/USER-DIFFRACTION/README index 5488cd3416..00203aeae2 100644 --- a/src/USER-DIFFRACTION/README +++ b/src/USER-DIFFRACTION/README @@ -1,4 +1,4 @@ -This package contains the commands neeed to calculate x-ray and +This package contains the commands needed to calculate x-ray and electron diffraction intensities based on kinematic diffraction theory. Detailed discription of the computation can be found in the following works: diff --git a/src/USER-DIFFRACTION/compute_saed.cpp b/src/USER-DIFFRACTION/compute_saed.cpp index 3ae25f223c..7b5b2f4f5b 100644 --- a/src/USER-DIFFRACTION/compute_saed.cpp +++ b/src/USER-DIFFRACTION/compute_saed.cpp @@ -75,7 +75,7 @@ ComputeSAED::ComputeSAED(LAMMPS *lmp, int narg, char **arg) : if (lambda < 0) error->all(FLERR,"Compute SAED: Wavelength must be greater than zero"); - // Define atom types for atomic scattering factor coefficents + // Define atom types for atomic scattering factor coefficients int iarg = 4; ztype = new int[ntypes]; for (int i = 0; i < ntypes; i++){ @@ -394,7 +394,7 @@ void ComputeSAED::compute_vector() */ - // determining paramater set to use based on maximum S = sin(theta)/lambda + // determining parameter set to use based on maximum S = sin(theta)/lambda double Smax = Kmax / 2; int offset = 0; // offset the ASFSAED matrix for appropriate value @@ -449,8 +449,8 @@ void ComputeSAED::compute_vector() Fatom1 = 0.0; Fatom2 = 0.0; - // Calculate the atomic structre factor by type - // determining paramater set to use based on S = sin(theta)/lambda <> 2 + // Calculate the atomic structure factor by type + // determining parameter set to use based on S = sin(theta)/lambda <> 2 for (int ii = 0; ii < ntypes; ii++){ f[ii] = 0; for (int C = 0; C < 5; C++){ diff --git a/src/USER-DIFFRACTION/fix_saed_vtk.cpp b/src/USER-DIFFRACTION/fix_saed_vtk.cpp index c3a72e494b..b6c00c2374 100644 --- a/src/USER-DIFFRACTION/fix_saed_vtk.cpp +++ b/src/USER-DIFFRACTION/fix_saed_vtk.cpp @@ -98,7 +98,7 @@ FixSAEDVTK::FixSAEDVTK(LAMMPS *lmp, int narg, char **arg) : if (strcmp(compute_saed->style,"saed") != 0) error->all(FLERR,"Fix saed/vtk has invalid compute assigned"); - // Gather varialbes from specified compute_saed + // Gather variables from specified compute_saed double *saed_var = compute_saed->saed_var; lambda = saed_var[0]; Kmax = saed_var[1]; diff --git a/src/USER-DPD/fix_rx.h b/src/USER-DPD/fix_rx.h index ca87fc51fd..e2f9f5b88b 100644 --- a/src/USER-DPD/fix_rx.h +++ b/src/USER-DPD/fix_rx.h @@ -124,7 +124,7 @@ class FixRX : public Fix { // ODE Diagnostics //int nSteps; //!< # of accepted steps taken over all atoms. - //int nIters; //!< # of attemped steps for all atoms. + //int nIters; //!< # of attempted steps for all atoms. //int nFuncs; //!< # of RHS evaluations for all atoms. //int nFails; //!< # of ODE systems that failed (for some reason). diff --git a/src/USER-DPD/npair_half_bin_newton_ssa.cpp b/src/USER-DPD/npair_half_bin_newton_ssa.cpp index 2139173d47..4fb5714d11 100644 --- a/src/USER-DPD/npair_half_bin_newton_ssa.cpp +++ b/src/USER-DPD/npair_half_bin_newton_ssa.cpp @@ -64,7 +64,7 @@ NPairHalfBinNewtonSSA::~NPairHalfBinNewtonSSA() /* ---------------------------------------------------------------------- binned neighbor list construction with full Newton's 3rd law - for use by Shardlow Spliting Algorithm + for use by Shardlow Splitting Algorithm each owned atom i checks its own bin and other bins in Newton stencil every pair stored exactly once by some processor ------------------------------------------------------------------------- */ diff --git a/src/USER-DRUDE/pair_lj_cut_thole_long.cpp b/src/USER-DRUDE/pair_lj_cut_thole_long.cpp index f5d5467a9c..fa4f761663 100644 --- a/src/USER-DRUDE/pair_lj_cut_thole_long.cpp +++ b/src/USER-DRUDE/pair_lj_cut_thole_long.cpp @@ -587,7 +587,7 @@ void PairLJCutTholeLong::write_data_all(FILE *fp) /* ---------------------------------------------------------------------- */ // No point in having single() since it has no information about topology or Drude particles. -// Charges qi and qj are defined by the user (or 1.0 by defaut) +// Charges qi and qj are defined by the user (or 1.0 by default) /* ---------------------------------------------------------------------- */ diff --git a/src/USER-DRUDE/pair_thole.cpp b/src/USER-DRUDE/pair_thole.cpp index 129ed57900..4dd6cb12c0 100644 --- a/src/USER-DRUDE/pair_thole.cpp +++ b/src/USER-DRUDE/pair_thole.cpp @@ -369,7 +369,7 @@ double PairThole::single(int i, int j, int itype, int jtype, double qi,qj,factor_f,factor_e,dcoul,asr,exp_asr; // single() has no information about topology or Drude particles. - // Charges qi and qj are defined by the user (or 1.0 by defaut) + // Charges qi and qj are defined by the user (or 1.0 by default) qi = atom->q[i]; qj = atom->q[j]; diff --git a/src/USER-INTEL/README b/src/USER-INTEL/README index 786033ca85..650e2c3a2d 100644 --- a/src/USER-INTEL/README +++ b/src/USER-INTEL/README @@ -36,7 +36,7 @@ be added or changed in the Makefile depending on the version: 2017 update 2 - No changes needed 2017 updates 3 or 4 - Use -xCOMMON-AVX512 and not -xHost or -xCORE-AVX512 -2018 inital release - Use -xCOMMON-AVX512 and not -xHost or -xCORE-AVX512 +2018 initial release - Use -xCOMMON-AVX512 and not -xHost or -xCORE-AVX512 2018u1 or newer - Use -xHost or -xCORE-AVX512 and -qopt-zmm-usage=high ----------------------------------------------------------------------------- diff --git a/src/USER-INTEL/pair_airebo_intel.cpp b/src/USER-INTEL/pair_airebo_intel.cpp index eedf45d75e..e6e8503bb0 100644 --- a/src/USER-INTEL/pair_airebo_intel.cpp +++ b/src/USER-INTEL/pair_airebo_intel.cpp @@ -4480,7 +4480,7 @@ exceed_limits: * Calculate the lennard-jones interaction. * Uses the above hash-map, and outlines the calculation if the bondorder is * needed. - * Agressively compresses to get the most values calculated. + * Aggressively compresses to get the most values calculated. */ template static void aut_lennard_jones(KernelArgsAIREBOT * ka) { diff --git a/src/USER-INTEL/pair_lj_charmm_coul_charmm_intel.cpp b/src/USER-INTEL/pair_lj_charmm_coul_charmm_intel.cpp index f3f81651fc..ff8a9869b7 100644 --- a/src/USER-INTEL/pair_lj_charmm_coul_charmm_intel.cpp +++ b/src/USER-INTEL/pair_lj_charmm_coul_charmm_intel.cpp @@ -487,7 +487,7 @@ void PairLJCharmmCoulCharmmIntel::pack_force_const(ForceConst &fc, // Repeat cutsq calculation because done after call to init_style if (cut_lj > cut_coul) error->all(FLERR, - "Intel varient of lj/charmm/coul/long expects lj cutoff<=coulombic"); + "Intel variant of lj/charmm/coul/long expects lj cutoff<=coulombic"); for (int i = 1; i <= atom->ntypes; i++) { for (int j = i; j <= atom->ntypes; j++) { double cut; diff --git a/src/USER-INTEL/pair_lj_charmm_coul_charmm_intel.h b/src/USER-INTEL/pair_lj_charmm_coul_charmm_intel.h index 64d6077477..a48a84b5ce 100644 --- a/src/USER-INTEL/pair_lj_charmm_coul_charmm_intel.h +++ b/src/USER-INTEL/pair_lj_charmm_coul_charmm_intel.h @@ -92,7 +92,7 @@ E: The 'package intel' command is required for /intel styles Self-explanatory. -E: Intel varient of lj/charmm/coul/charmm expects lj cutoff<=coulombic +E: Intel variant of lj/charmm/coul/charmm expects lj cutoff<=coulombic The intel accelerated version of the CHARMM style requires that the Lennard-Jones cutoff is not greater than the coulombic cutoff. diff --git a/src/USER-INTEL/pair_lj_charmm_coul_long_intel.cpp b/src/USER-INTEL/pair_lj_charmm_coul_long_intel.cpp index b4697ad122..5a4069e199 100644 --- a/src/USER-INTEL/pair_lj_charmm_coul_long_intel.cpp +++ b/src/USER-INTEL/pair_lj_charmm_coul_long_intel.cpp @@ -557,7 +557,7 @@ void PairLJCharmmCoulLongIntel::pack_force_const(ForceConst &fc, // Repeat cutsq calculation because done after call to init_style if (cut_lj > cut_coul) error->all(FLERR, - "Intel varient of lj/charmm/coul/long expects lj cutoff<=coulombic"); + "Intel variant of lj/charmm/coul/long expects lj cutoff<=coulombic"); for (int i = 1; i <= atom->ntypes; i++) { for (int j = i; j <= atom->ntypes; j++) { double cut; diff --git a/src/USER-INTEL/pair_lj_charmm_coul_long_intel.h b/src/USER-INTEL/pair_lj_charmm_coul_long_intel.h index 0066745078..31b2182cb5 100644 --- a/src/USER-INTEL/pair_lj_charmm_coul_long_intel.h +++ b/src/USER-INTEL/pair_lj_charmm_coul_long_intel.h @@ -96,7 +96,7 @@ E: The 'package intel' command is required for /intel styles Self-explanatory. -E: Intel varient of lj/charmm/coul/long expects lj cutoff<=coulombic +E: Intel variant of lj/charmm/coul/long expects lj cutoff<=coulombic The intel accelerated version of the CHARMM style requires that the Lennard-Jones cutoff is not greater than the coulombic cutoff. diff --git a/src/USER-INTEL/pppm_disp_intel.cpp b/src/USER-INTEL/pppm_disp_intel.cpp index 9d075c78a1..c3711ef404 100644 --- a/src/USER-INTEL/pppm_disp_intel.cpp +++ b/src/USER-INTEL/pppm_disp_intel.cpp @@ -348,7 +348,7 @@ void PPPMDispIntel::compute(int eflag, int vflag) } if (function[1]) { - //perfrom calculations for geometric mixing + //perform calculations for geometric mixing if (fix->precision() == FixIntel::PREC_MODE_MIXED) { particle_map(delxinv_6, delyinv_6, delzinv_6, shift_6, diff --git a/src/USER-MANIFOLD/fix_nve_manifold_rattle.cpp b/src/USER-MANIFOLD/fix_nve_manifold_rattle.cpp index 7f8d9d5675..d62a5bba2a 100644 --- a/src/USER-MANIFOLD/fix_nve_manifold_rattle.cpp +++ b/src/USER-MANIFOLD/fix_nve_manifold_rattle.cpp @@ -149,7 +149,7 @@ FixNVEManifoldRattle::FixNVEManifoldRattle( LAMMPS *lmp, int &narg, char **arg, nevery = force->inumeric(FLERR,arg[argi+1]); next_output = update->ntimestep + nevery; if (comm->me == 0) { - fprintf(screen,"Outputing every %d steps, next is %d\n", + fprintf(screen,"Outputting every %d steps, next is %d\n", nevery, next_output); } argi += 2; diff --git a/src/USER-MANIFOLD/manifold_thylakoid.cpp b/src/USER-MANIFOLD/manifold_thylakoid.cpp index e4ef039832..e473f00a03 100644 --- a/src/USER-MANIFOLD/manifold_thylakoid.cpp +++ b/src/USER-MANIFOLD/manifold_thylakoid.cpp @@ -142,7 +142,7 @@ void manifold_thylakoid::init_domains() { if (wB + 2*lB > LT) { char msg[2048]; - sprintf(msg,"LT = %f not large enough to accomodate bridge with " + sprintf(msg,"LT = %f not large enough to accommodate bridge with " "wB = %f and lB = %f! %f > %f\n", LT, wB, lB, wB + 2*lB, LT); error->one(FLERR,msg); } diff --git a/src/USER-MEAMC/README b/src/USER-MEAMC/README index c1faf7c0c4..dcb70d670c 100644 --- a/src/USER-MEAMC/README +++ b/src/USER-MEAMC/README @@ -19,7 +19,7 @@ The original Fortran implementation was created by Use "make yes-user-meamc" to enable this package when building LAMMPS. -In your LAMMPS input script, specifiy +In your LAMMPS input script, specify pair_style meam/c to enable the use of this implementation. All parameters, input files and outputs are exactly identical to these used with pair_style meam. diff --git a/src/USER-MEAMC/meam_funcs.cpp b/src/USER-MEAMC/meam_funcs.cpp index a67cbf2833..706075ffd0 100644 --- a/src/USER-MEAMC/meam_funcs.cpp +++ b/src/USER-MEAMC/meam_funcs.cpp @@ -271,7 +271,7 @@ MEAM::get_Zij(const lattice_t latt) return 12; case B2: return 8; - case CH4: // DYNAMO currenly implemented this way while it needs two Z values, 4 and 1 + case CH4: // DYNAMO currently implemented this way while it needs two Z values, 4 and 1 return 4; case LIN: case ZIG: diff --git a/src/USER-MEAMC/meam_setup_done.cpp b/src/USER-MEAMC/meam_setup_done.cpp index 8dfebe8ed5..b37f56dda2 100644 --- a/src/USER-MEAMC/meam_setup_done.cpp +++ b/src/USER-MEAMC/meam_setup_done.cpp @@ -95,7 +95,7 @@ MEAM::alloyparams(void) for (i = 0; i < this->neltypes; i++) { for (j = 0; j < this->neltypes; j++) { // Treat off-diagonal pairs - // If i>j, set all equal to ij, set all equal to i j) { this->re_meam[i][j] = this->re_meam[j][i]; diff --git a/src/USER-MGPT/pair_mgpt.cpp b/src/USER-MGPT/pair_mgpt.cpp index 0634872c70..213f73f05a 100644 --- a/src/USER-MGPT/pair_mgpt.cpp +++ b/src/USER-MGPT/pair_mgpt.cpp @@ -118,7 +118,7 @@ void PairMGPT::make_bond(const double xx[][3],int i,int j,bond_data *bptr) { double t0,t1; - /* Check that alignment requirements for SIMD code are fullfilled */ + /* Check that alignment requirements for SIMD code are fulfilled */ assert( (((unsigned long long int) (bptr->H.m )) & 31) == 0 ); assert( (((unsigned long long int) (bptr->Hx.m)) & 31) == 0 ); assert( (((unsigned long long int) (bptr->Hy.m)) & 31) == 0 ); diff --git a/src/USER-MISC/compute_cnp_atom.cpp b/src/USER-MISC/compute_cnp_atom.cpp index 3a1d5271c6..34882b0272 100644 --- a/src/USER-MISC/compute_cnp_atom.cpp +++ b/src/USER-MISC/compute_cnp_atom.cpp @@ -161,7 +161,7 @@ void ComputeCNPAtom::compute_peratom() numneigh = list->numneigh; firstneigh = list->firstneigh; - // find the neigbors of each atom within cutoff using full neighbor list + // find the neighbors of each atom within cutoff using full neighbor list // nearest[] = atom indices of nearest neighbors, up to MAXNEAR // do this for all atoms, not just compute group // since CNP calculation requires neighbors of neighbors diff --git a/src/USER-MISC/compute_stress_mop.cpp b/src/USER-MISC/compute_stress_mop.cpp index 2f932321e1..c403ed3247 100644 --- a/src/USER-MISC/compute_stress_mop.cpp +++ b/src/USER-MISC/compute_stress_mop.cpp @@ -318,7 +318,7 @@ void ComputeStressMop::compute_pairs() if (newton_pair || j < nlocal) { - //check if ij pair is accross plane, add contribution to pressure + //check if ij pair is across plane, add contribution to pressure if ( ((xi[dir]>pos) && (xj[dir]pos1) && (xj[dir]single(i,j,itype,jtype,rsq,factor_coul,factor_lj,fpair); diff --git a/src/USER-MISC/compute_stress_mop_profile.cpp b/src/USER-MISC/compute_stress_mop_profile.cpp index 5f6d0a36b2..9649a61090 100644 --- a/src/USER-MISC/compute_stress_mop_profile.cpp +++ b/src/USER-MISC/compute_stress_mop_profile.cpp @@ -333,7 +333,7 @@ void ComputeStressMopProfile::compute_pairs() pos = coord[ibin][0]; pos1 = coordp[ibin][0]; - //check if ij pair is accross plane, add contribution to pressure + //check if ij pair is across plane, add contribution to pressure if ( ((xi[dir]>pos) && (xj[dir]pos1) && (xj[dir]pos) && (xj[dir]pos1) && (xj[dir]f_unspecified) && (i==0)) err_msg << "\n (This sometimes occurs if users forget to specify the \"NOF\" option.)\n"; error->one(FLERR, err_msg.str().c_str()); diff --git a/src/USER-MISC/dihedral_table_cut.cpp b/src/USER-MISC/dihedral_table_cut.cpp index 8d530253c2..194c25f536 100644 --- a/src/USER-MISC/dihedral_table_cut.cpp +++ b/src/USER-MISC/dihedral_table_cut.cpp @@ -1140,7 +1140,7 @@ void DihedralTableCut::read_table(Table *tb, char *file, char *keyword) if (! line_ss) { stringstream err_msg; err_msg << "Read error in table "<< keyword<<", near line "<f_unspecified) && (i==0)) err_msg << "\n (This sometimes occurs if users forget to specify the \"NOF\" option.)\n"; error->one(FLERR, err_msg.str().c_str()); diff --git a/src/USER-MISC/fix_flow_gauss.cpp b/src/USER-MISC/fix_flow_gauss.cpp index 218ba3cfa6..c7b7f86d37 100644 --- a/src/USER-MISC/fix_flow_gauss.cpp +++ b/src/USER-MISC/fix_flow_gauss.cpp @@ -188,7 +188,7 @@ void FixFlowGauss::post_force(int /*vflag*/) for (ii=0; ii<3; ii++) a_app[ii] = -f_tot[ii] / mTot; - //apply added accelleration to each atom + //apply added acceleration to each atom double f_app[3]; double peAdded=0.0; for( ii = 0; iiuniverse_all(FLERR,"Unkown method parameter for fix pimd"); + else error->universe_all(FLERR,"Unknown method parameter for fix pimd"); } else if(strcmp(arg[i],"fmass")==0) { @@ -79,7 +79,7 @@ FixPIMD::FixPIMD(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) nhc_nchain = atoi(arg[i+1]); if(nhc_nchain<2) error->universe_all(FLERR,"Invalid nhc value for fix pimd"); } - else error->universe_all(arg[i],i+1,"Unkown keyword for fix pimd"); + else error->universe_all(arg[i],i+1,"Unknown keyword for fix pimd"); } /* Initiation */ diff --git a/src/USER-MISC/fix_pimd.h b/src/USER-MISC/fix_pimd.h index c298af0b69..bed5b0a256 100644 --- a/src/USER-MISC/fix_pimd.h +++ b/src/USER-MISC/fix_pimd.h @@ -61,7 +61,7 @@ class FixPIMD : public Fix { void spring_force(); - /* fictious mass */ + /* fictitious mass */ double fmass, *mass; diff --git a/src/USER-MISC/fix_wall_reflect_stochastic.cpp b/src/USER-MISC/fix_wall_reflect_stochastic.cpp index bb6ffd7698..18bb7ec011 100644 --- a/src/USER-MISC/fix_wall_reflect_stochastic.cpp +++ b/src/USER-MISC/fix_wall_reflect_stochastic.cpp @@ -71,7 +71,7 @@ FixWallReflectStochastic(LAMMPS *lmp, int narg, char **arg) : seedfix = force->inumeric(FLERR,arg[4]); - if (seedfix <= 0) error->all(FLERR,"Random seed must be a postive number"); + if (seedfix <= 0) error->all(FLERR,"Random seed must be a positive number"); int iarg = 5; while (iarg < narg) { @@ -114,7 +114,7 @@ FixWallReflectStochastic(LAMMPS *lmp, int narg, char **arg) : if ((wallvel[nwall][dir] !=0) & (dir == dim)) error->all(FLERR,"The wall velocity must be tangential"); - // DIFFUSIVE = no accomodation coeffs + // DIFFUSIVE = no accommodation coeffs // MAXWELL = one for all dimensions // CCL = one for each dimension diff --git a/src/USER-MISC/pair_cosine_squared.cpp b/src/USER-MISC/pair_cosine_squared.cpp index 7c0cb3372d..7f3f6259d4 100644 --- a/src/USER-MISC/pair_cosine_squared.cpp +++ b/src/USER-MISC/pair_cosine_squared.cpp @@ -180,7 +180,7 @@ void PairCosineSquared::coeff(int narg, char **arg) } /* ---------------------------------------------------------------------- - init specific to this pair style (unneccesary) + init specific to this pair style (unnecessary) ------------------------------------------------------------------------- */ /* diff --git a/src/USER-MISC/pair_coul_shield.cpp b/src/USER-MISC/pair_coul_shield.cpp index 980b4a71d5..e6916f0d22 100644 --- a/src/USER-MISC/pair_coul_shield.cpp +++ b/src/USER-MISC/pair_coul_shield.cpp @@ -102,7 +102,7 @@ void PairCoulShield::compute(int eflag, int vflag) rsq = delx*delx + dely*dely + delz*delz; jtype = type[j]; - // only include the interation between different layers + // only include the interaction between different layers if (rsq < cutsq[itype][jtype] && atom->molecule[i] != atom->molecule[j]) { r = sqrt(rsq); r3 = rsq*r; diff --git a/src/USER-MISC/pair_drip.cpp b/src/USER-MISC/pair_drip.cpp index 20ec3abcf9..020216f503 100644 --- a/src/USER-MISC/pair_drip.cpp +++ b/src/USER-MISC/pair_drip.cpp @@ -405,7 +405,7 @@ void PairDRIP::compute(int eflag, int vflag) Param& p = params[iparam_ij]; double rcutsq = p.rcutsq; - // only include the interation between different layers + // only include the interaction between different layers if (rsq < rcutsq && atom->molecule[i] != atom->molecule[j]) { double fj[DIM] = {0., 0., 0.}; diff --git a/src/USER-MISC/pair_e3b.cpp b/src/USER-MISC/pair_e3b.cpp index ae324e0a4a..46f22e714d 100644 --- a/src/USER-MISC/pair_e3b.cpp +++ b/src/USER-MISC/pair_e3b.cpp @@ -31,7 +31,7 @@ #include "domain.h" #include "citeme.h" -//these are defined here to avoid confusing hardcoded indicies, but +//these are defined here to avoid confusing hardcoded indices, but //they do not allow flexibility. If they are changed the code will break #define DIM 3 #define NUMH 2 //number of hydrogen atoms per water molecule diff --git a/src/USER-MISC/pair_extep.cpp b/src/USER-MISC/pair_extep.cpp index df232e029c..62ef24da85 100644 --- a/src/USER-MISC/pair_extep.cpp +++ b/src/USER-MISC/pair_extep.cpp @@ -718,7 +718,7 @@ void PairExTeP::read_file(char *file) // reallocate with new size words = new char*[params_per_line+1]; - // intialize F_corr_data to all zeros + // initialize F_corr_data to all zeros for (int iel=0;ielmolecule[i] != atom->molecule[j]) { int iparam_ij = elem2param[map[itype]][map[jtype]]; @@ -593,7 +593,7 @@ void PairILPGrapheneHBN::calc_FRep(int eflag, int /* vflag */) delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; - // only include the interation between different layers + // only include the interaction between different layers if (rsq < cutsq[itype][jtype] && atom->molecule[i] != atom->molecule[j]) { int iparam_ij = elem2param[map[itype]][map[jtype]]; @@ -675,7 +675,7 @@ void PairILPGrapheneHBN::calc_FRep(int eflag, int /* vflag */) } /* ---------------------------------------------------------------------- - create ILP neighbor list from main neighbor list to calcualte normals + create ILP neighbor list from main neighbor list to calculate normals ------------------------------------------------------------------------- */ void PairILPGrapheneHBN::ILP_neigh() diff --git a/src/USER-MISC/pair_kolmogorov_crespi_full.cpp b/src/USER-MISC/pair_kolmogorov_crespi_full.cpp index 92fbc4e9c0..3f624fc785 100644 --- a/src/USER-MISC/pair_kolmogorov_crespi_full.cpp +++ b/src/USER-MISC/pair_kolmogorov_crespi_full.cpp @@ -502,7 +502,7 @@ void PairKolmogorovCrespiFull::calc_FvdW(int eflag, int /* vflag */) delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; - // only include the interation between different layers + // only include the interaction between different layers if (rsq < cutsq[itype][jtype] && atom->molecule[i] != atom->molecule[j]) { int iparam_ij = elem2param[map[itype]][map[jtype]]; @@ -593,7 +593,7 @@ void PairKolmogorovCrespiFull::calc_FRep(int eflag, int /* vflag */) delz = ztmp - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; - // only include the interation between different layers + // only include the interaction between different layers if (rsq < cutsq[itype][jtype] && atom->molecule[i] != atom->molecule[j]) { int iparam_ij = elem2param[map[itype]][map[jtype]]; diff --git a/src/USER-MISC/pair_mesocnt.cpp b/src/USER-MISC/pair_mesocnt.cpp index b073705dda..4864dab950 100644 --- a/src/USER-MISC/pair_mesocnt.cpp +++ b/src/USER-MISC/pair_mesocnt.cpp @@ -866,7 +866,7 @@ void PairMesoCNT::read_data(FILE *fp, double *data, } } - // warn if data was read incompletely, e.g. colums were missing + // warn if data was read incompletely, e.g. columns were missing if (cerror) { char str[128]; @@ -934,7 +934,7 @@ void PairMesoCNT::read_data(FILE *fp, double **data, } } - // warn if data was read incompletely, e.g. colums were missing + // warn if data was read incompletely, e.g. columns were missing if (cerror) { char str[128]; diff --git a/src/USER-OMP/msm_cg_omp.cpp b/src/USER-OMP/msm_cg_omp.cpp index 3c5439db5d..7ca01dbd6a 100644 --- a/src/USER-OMP/msm_cg_omp.cpp +++ b/src/USER-OMP/msm_cg_omp.cpp @@ -199,7 +199,7 @@ void MSMCGOMP::compute(int eflag, int vflag) } - // compute direct interation for top grid level for non-periodic + // compute direct interaction for top grid level for non-periodic // and for second from top grid level for periodic if (active_flag[levels-1]) { diff --git a/src/USER-OMP/pair_airebo_omp.cpp b/src/USER-OMP/pair_airebo_omp.cpp index 7890c8aed3..aedf5056a6 100644 --- a/src/USER-OMP/pair_airebo_omp.cpp +++ b/src/USER-OMP/pair_airebo_omp.cpp @@ -1848,9 +1848,9 @@ double PairAIREBOOMP::bondorder_thr(int i, int j, double rij[3], double rijmag, This function calculates S(t_b(b_ij*)) as specified in the AIREBO paper. To do so, it needs to compute b_ij*, i.e. the bondorder given that the -atoms i and j are placed a ficticious distance rijmag_mod apart. +atoms i and j are placed a fictitious distance rijmag_mod apart. Now there are two approaches to calculate the resulting forces: -1. Carry through the ficticious distance and corresponding vector +1. Carry through the fictitious distance and corresponding vector rij_mod, correcting afterwards using the derivative of r/|r|. 2. Perform all the calculations using the real distance, and do not use a correction, only using rijmag_mod where necessary. diff --git a/src/USER-OMP/pair_lj_long_tip4p_long_omp.cpp b/src/USER-OMP/pair_lj_long_tip4p_long_omp.cpp index 7735d6fde4..d8eedc6c0b 100644 --- a/src/USER-OMP/pair_lj_long_tip4p_long_omp.cpp +++ b/src/USER-OMP/pair_lj_long_tip4p_long_omp.cpp @@ -66,7 +66,7 @@ void PairLJLongTIP4PLongOMP::compute(int eflag, int vflag) ev_init(eflag,vflag); // reallocate hneigh_thr & newsite_thr if necessary - // initialize hneigh_thr[0] to -1 on steps when reneighboring occured + // initialize hneigh_thr[0] to -1 on steps when reneighboring occurred // initialize hneigh_thr[2] to 0 every step const int nlocal = atom->nlocal; const int nall = nlocal + atom->nghost; @@ -354,7 +354,7 @@ void PairLJLongTIP4PLongOMP::compute(int eflag, int vflag) void PairLJLongTIP4PLongOMP::compute_inner() { // reallocate hneigh_thr & newsite_thr if necessary - // initialize hneigh_thr[0] to -1 on steps when reneighboring occured + // initialize hneigh_thr[0] to -1 on steps when reneighboring occurred // initialize hneigh_thr[2] to 0 every step const int nall = atom->nlocal + atom->nghost; @@ -432,7 +432,7 @@ void PairLJLongTIP4PLongOMP::compute_outer(int eflag, int vflag) const int nall = atom->nlocal + atom->nghost; // reallocate hneigh_thr & newsite_thr if necessary - // initialize hneigh_thr[0] to -1 on steps when reneighboring occured + // initialize hneigh_thr[0] to -1 on steps when reneighboring occurred // initialize hneigh_thr[2] to 0 every step if (atom->nmax > nmax) { diff --git a/src/USER-OMP/pppm_cg_omp.cpp b/src/USER-OMP/pppm_cg_omp.cpp index 1117979f1f..f9967bf52a 100644 --- a/src/USER-OMP/pppm_cg_omp.cpp +++ b/src/USER-OMP/pppm_cg_omp.cpp @@ -281,7 +281,7 @@ void PPPMCGOMP::compute_gf_ad() } } thr->timer(Timer::KSPACE); - } // end of paralle region + } // end of parallel region // compute the coefficients for the self-force correction @@ -570,7 +570,7 @@ void PPPMCGOMP::fieldforce_ad() eky *= hy_inv; ekz *= hz_inv; - // convert E-field to force and substract self forces + // convert E-field to force and subtract self forces const double qi = q[i]; const double qfactor = qqrd2e * scale * qi; diff --git a/src/USER-OMP/pppm_disp_tip4p_omp.cpp b/src/USER-OMP/pppm_disp_tip4p_omp.cpp index bdd8f23ee4..ec294cd56d 100644 --- a/src/USER-OMP/pppm_disp_tip4p_omp.cpp +++ b/src/USER-OMP/pppm_disp_tip4p_omp.cpp @@ -951,7 +951,7 @@ void PPPMDispTIP4POMP::fieldforce_c_ad() eky *= hy_inv; ekz *= hz_inv; - // convert E-field to force and substract self forces + // convert E-field to force and subtract self forces const double qi = q[i]; const double qfactor = qqrd2e * scale * qi; diff --git a/src/USER-OMP/pppm_omp.cpp b/src/USER-OMP/pppm_omp.cpp index c6aaafaa31..b9b39826ff 100644 --- a/src/USER-OMP/pppm_omp.cpp +++ b/src/USER-OMP/pppm_omp.cpp @@ -281,7 +281,7 @@ void PPPMOMP::compute_gf_ad() } } thr->timer(Timer::KSPACE); - } // end of paralle region + } // end of parallel region // compute the coefficients for the self-force correction @@ -578,7 +578,7 @@ void PPPMOMP::fieldforce_ad() eky *= hy_inv; ekz *= hz_inv; - // convert E-field to force and substract self forces + // convert E-field to force and subtract self forces const double qi = q[i]; const double qfactor = qqrd2e * scale * qi; diff --git a/src/USER-OMP/pppm_tip4p_omp.cpp b/src/USER-OMP/pppm_tip4p_omp.cpp index 322730b573..359b5dcc8d 100644 --- a/src/USER-OMP/pppm_tip4p_omp.cpp +++ b/src/USER-OMP/pppm_tip4p_omp.cpp @@ -283,7 +283,7 @@ void PPPMTIP4POMP::compute_gf_ad() } } thr->timer(Timer::KSPACE); - } // end of paralle region + } // end of parallel region // compute the coefficients for the self-force correction @@ -681,7 +681,7 @@ void PPPMTIP4POMP::fieldforce_ad() eky *= hy_inv; ekz *= hz_inv; - // convert E-field to force and substract self forces + // convert E-field to force and subtract self forces const double qi = q[i]; const double qfactor = qqrd2e * scale * qi; diff --git a/src/USER-OMP/thr_data.h b/src/USER-OMP/thr_data.h index 2c1e42a3a3..4853d6dbbf 100644 --- a/src/USER-OMP/thr_data.h +++ b/src/USER-OMP/thr_data.h @@ -146,7 +146,7 @@ class ThrData { //////////////////////////////////////////////////////////////////////// // helper functions operating on data replicated for thread support // //////////////////////////////////////////////////////////////////////// -// generic per thread data reduction for continous arrays of nthreads*nmax size +// generic per thread data reduction for continuous arrays of nthreads*nmax size void data_reduce_thr(double *, int, int, int, int); } #endif diff --git a/src/USER-PHONON/fix_phonon.h b/src/USER-PHONON/fix_phonon.h index 91a380247a..f75139ce42 100644 --- a/src/USER-PHONON/fix_phonon.h +++ b/src/USER-PHONON/fix_phonon.h @@ -73,7 +73,7 @@ class FixPhonon : public Fix { double *M_inv_sqrt; - class FFT3d *fft; // to do fft via the fft3d wraper + class FFT3d *fft; // to do fft via the fft3d wrapper int nxlo,nxhi,mysize; // size info for local MPI_FFTW int mynpt,mynq,fft_nsend; int *fft_cnts, *fft_disp; diff --git a/src/USER-REACTION/fix_bond_react.cpp b/src/USER-REACTION/fix_bond_react.cpp index b2bb66b288..44e2bd172e 100644 --- a/src/USER-REACTION/fix_bond_react.cpp +++ b/src/USER-REACTION/fix_bond_react.cpp @@ -617,7 +617,7 @@ void FixBondReact::post_constructor() delete [] exclude_PARENT_group; // on to statted_tags (system-wide thermostat) - // intialize per-atom statted_flags to 1 + // initialize per-atom statted_flags to 1 // (only if not already initialized by restart) if (fix3->restart_reset != 1) { int flag; @@ -650,7 +650,7 @@ void FixBondReact::post_constructor() statted_id = new char[len]; strcpy(statted_id,idprop); - // intialize per-atom statted_tags to 1 + // initialize per-atom statted_tags to 1 // need to correct for smooth restarts //int flag; //int index = atom->find_custom(statted_id,flag); @@ -1325,7 +1325,7 @@ void FixBondReact::make_a_guess() // if so, this constitutes a fail // because still undergoing a previous reaction! // could technically fail unnecessarily during a wrong guess if near edge atoms - // we accept this temporary and infrequent decrease in reaction occurences + // we accept this temporary and infrequent decrease in reaction occurrences for (int i = 0; i < nxspecial[atom->map(glove[pion][1])][0]; i++) { if (atom->map(xspecial[atom->map(glove[pion][1])][i]) < 0) { @@ -1922,7 +1922,7 @@ void FixBondReact::find_landlocked_atoms(int myrxn) { // landlocked_atoms are atoms for which all topology is contained in reacted template // if dihedrals/impropers exist: this means that edge atoms are not in their 1-3 neighbor list - // note: due to various usage/defintions of impropers, treated same as dihedrals + // note: due to various usage/definitions of impropers, treated same as dihedrals // if angles exist: this means edge atoms not in their 1-2 neighbors list // if just bonds: this just means that edge atoms are not landlocked // Note: landlocked defined in terms of reacted template diff --git a/src/USER-SMD/atom_vec_smd.cpp b/src/USER-SMD/atom_vec_smd.cpp index 604504c5a7..ef14eacdc2 100644 --- a/src/USER-SMD/atom_vec_smd.cpp +++ b/src/USER-SMD/atom_vec_smd.cpp @@ -219,7 +219,7 @@ int AtomVecSMD::pack_comm_vel(int n, int *list, double *buf, int pbc_flag, int * // no need to communicate x0 here, as it is not changed by time integration // if x0 is changed when the ref config is updated, this communication is performed in the fix_integrate/tlsph - // similarily, rmass could be removed here. + // similarly, rmass could be removed here. // radius should be communicated here for future time-integration of the radius with ulsph (not implemented yet) int i, j, m; double dx, dy, dz, dvx, dvy, dvz; diff --git a/src/USER-SMD/pair_smd_tlsph.cpp b/src/USER-SMD/pair_smd_tlsph.cpp index 82b7c8ff9d..cad9923054 100644 --- a/src/USER-SMD/pair_smd_tlsph.cpp +++ b/src/USER-SMD/pair_smd_tlsph.cpp @@ -913,7 +913,7 @@ void PairTlsph::settings(int narg, char **arg) { /* * default value for update_threshold for updates of reference configuration: * The maximum relative displacement which is tracked by the construction of LAMMPS' neighborlists - * is the folowing. + * is the following. */ cut_comm = MAX(neighbor->cutneighmax, comm->cutghostuser); // cutoff radius within which ghost atoms are communicated. diff --git a/src/USER-SMD/pair_smd_tlsph.h b/src/USER-SMD/pair_smd_tlsph.h index 62e7ce2295..31a238d564 100644 --- a/src/USER-SMD/pair_smd_tlsph.h +++ b/src/USER-SMD/pair_smd_tlsph.h @@ -195,7 +195,7 @@ protected: private: double **Lookup; // holds per-type material parameters for the quantities defined in enum statement above. - bool first; // if first is true, do not perform any computations, beacuse reference configuration is not ready yet. + bool first; // if first is true, do not perform any computations, because reference configuration is not ready yet. }; } diff --git a/src/USER-SMD/pair_smd_triangulated_surface.cpp b/src/USER-SMD/pair_smd_triangulated_surface.cpp index f9052be087..53a93df7f7 100644 --- a/src/USER-SMD/pair_smd_triangulated_surface.cpp +++ b/src/USER-SMD/pair_smd_triangulated_surface.cpp @@ -481,7 +481,7 @@ double PairTriSurf::memory_usage() { % Release: 1.2 Fixed Bug because of typo in region 5 20101013 % Release: 1.3 Fixed Bug because of typo in region 2 20101014 - % Possible extention could be a version tailored not to return the distance + % Possible extension could be a version tailored not to return the distance % and additionally the closest point, but instead return only the closest % point. Could lead to a small speed gain. diff --git a/src/USER-SMD/smd_material_models.cpp b/src/USER-SMD/smd_material_models.cpp index 5ee67fbb4e..096600df52 100644 --- a/src/USER-SMD/smd_material_models.cpp +++ b/src/USER-SMD/smd_material_models.cpp @@ -263,7 +263,7 @@ void LinearPlasticStrength(const double G, const double yieldStress, const Matri if (J2 < yieldStress) { /* - * no yielding has occured. + * no yielding has occurred. * final deviatoric stress is trial deviatoric stress */ sigma_dev_rate__ = dev_rate; @@ -274,7 +274,7 @@ void LinearPlasticStrength(const double G, const double yieldStress, const Matri } else { //printf("yiedl\n"); /* - * yielding has occured + * yielding has occurred */ plastic_strain_increment = (J2 - yieldStress) / (3.0 * G); @@ -288,7 +288,7 @@ void LinearPlasticStrength(const double G, const double yieldStress, const Matri * new deviatoric stress rate */ sigma_dev_rate__ = sigmaFinal_dev__ - sigmaInitial_dev; - //printf("yielding has occured.\n"); + //printf("yielding has occurred.\n"); } } @@ -344,7 +344,7 @@ void JohnsonCookStrength(const double G, const double cp, const double espec, co if (J2 < yieldStress) { /* - * no yielding has occured. + * no yielding has occurred. * final deviatoric stress is trial deviatoric stress */ sigma_dev_rate__ = dev_rate; @@ -355,7 +355,7 @@ void JohnsonCookStrength(const double G, const double cp, const double espec, co } else { //printf("yiedl\n"); /* - * yielding has occured + * yielding has occurred */ plastic_strain_increment = (J2 - yieldStress) / (3.0 * G); @@ -369,7 +369,7 @@ void JohnsonCookStrength(const double G, const double cp, const double espec, co * new deviatoric stress rate */ sigma_dev_rate__ = sigmaFinal_dev__ - sigmaInitial_dev; - //printf("yielding has occured.\n"); + //printf("yielding has occurred.\n"); } } @@ -452,7 +452,7 @@ double JohnsonCookFailureStrain(const double p, const Matrix3d Sdev, const doubl } // determine stress triaxiality - double triax = p / (vm + 0.01 * fabs(p)); // have softening in denominator to avoid divison by zero + double triax = p / (vm + 0.01 * fabs(p)); // have softening in denominator to avoid division by zero if (triax < 0.0) { triax = 0.0; } else if (triax > 3.0) { diff --git a/src/USER-SMTBQ/pair_smtbq.h b/src/USER-SMTBQ/pair_smtbq.h index 05e4b67242..c83e1b5cf1 100644 --- a/src/USER-SMTBQ/pair_smtbq.h +++ b/src/USER-SMTBQ/pair_smtbq.h @@ -56,8 +56,8 @@ protected: double rmin,dr,ds; // table parameter int kmax; bigint Qstep; // Frequency of charge resolution - double precision; // acuracy of convergence - int loopmax; // max of interation + double precision; // accuracy of convergence + int loopmax; // max of iteration double cutmax; // max cutoff for all elements int nelements; // # of unique elements diff --git a/src/USER-UEF/fix_nh_uef.cpp b/src/USER-UEF/fix_nh_uef.cpp index 8873688eb7..a3a2dc476c 100644 --- a/src/USER-UEF/fix_nh_uef.cpp +++ b/src/USER-UEF/fix_nh_uef.cpp @@ -53,7 +53,7 @@ static const char cite_user_uef_package[] = "}\n\n"; /* ---------------------------------------------------------------------- - * Parse fix specific keywords, do some error checking, and initalize + * Parse fix specific keywords, do some error checking, and initialize * temp/pressure fixes ---------------------------------------------------------------------- */ FixNHUef::FixNHUef(LAMMPS *lmp, int narg, char **arg) : diff --git a/src/USER-VTK/dump_vtk.h b/src/USER-VTK/dump_vtk.h index 8df14c7f34..e8de87f11c 100644 --- a/src/USER-VTK/dump_vtk.h +++ b/src/USER-VTK/dump_vtk.h @@ -185,7 +185,7 @@ E: Compute used in dump between runs is not current The compute was not invoked on the current timestep, therefore it cannot be used in a dump between runs. -E: Threshhold for an atom property that isn't allocated +E: Threshold for an atom property that isn't allocated A dump threshold has been requested on a quantity that is not defined by the atom style used in this simulation. diff --git a/src/USER-YAFF/pair_lj_switch3_coulgauss_long.cpp b/src/USER-YAFF/pair_lj_switch3_coulgauss_long.cpp index 022b93a0d2..37fc143e8b 100644 --- a/src/USER-YAFF/pair_lj_switch3_coulgauss_long.cpp +++ b/src/USER-YAFF/pair_lj_switch3_coulgauss_long.cpp @@ -166,7 +166,7 @@ void PairLJSwitch3CoulGaussLong::compute(int eflag, int vflag) forcelj = r6inv*(12.0*lj3[itype][jtype]*r6inv - 6.0*lj4[itype][jtype]); // Correction for Gaussian radii if (lj2[itype][jtype]==0.0) { - // This means a point charge is considerd, so the correction is zero + // This means a point charge is considered, so the correction is zero expn2 = 0.0; erfc2 = 0.0; forcecoul2 = 0.0; diff --git a/src/VORONOI/README b/src/VORONOI/README index 9a83c95a8d..ede104a678 100644 --- a/src/VORONOI/README +++ b/src/VORONOI/README @@ -7,7 +7,7 @@ developed by Chris H. Rycroft while at UC Berkeley / Lawrence Berkeley Laboratory. That library can be downloaded and built in lib/voronoi or elsewhere -on your system, which must be done before bulding LAMMPS with this +on your system, which must be done before building LAMMPS with this package. Details of the download, build, and install process for Voro++ are given in the lib/voronoi/README file, and scripts are provided to help automate the process. Also see the LAMMPS manual for diff --git a/src/comm.cpp b/src/comm.cpp index f5b1c0246b..6a762036d1 100644 --- a/src/comm.cpp +++ b/src/comm.cpp @@ -845,7 +845,7 @@ void Comm::ring(int n, int nper, void *inbuf, int messtag, rendezvous communication operation three stages: first comm sends inbuf from caller decomp to rvous decomp - callback operates on data in rendevous decomp + callback operates on data in rendezvous decomp second comm sends outbuf from rvous decomp back to caller decomp inputs: which = perform (0) irregular or (1) MPI_All2allv communication @@ -977,7 +977,7 @@ rendezvous_all2all(int n, char *inbuf, int insize, int inorder, int *procs, bigint *offsets; char *inbuf_a2a,*outbuf_a2a; - // create procs and inbuf for All2all if necesary + // create procs and inbuf for All2all if necessary if (!inorder) { memory->create(procs_a2a,nprocs,"rendezvous:procs"); @@ -1080,7 +1080,7 @@ rendezvous_all2all(int n, char *inbuf, int insize, int inorder, int *procs, return 0; // all nout_rvous are 0, no 2nd irregular } - // create procs and outbuf for All2all if necesary + // create procs and outbuf for All2all if necessary if (!outorder) { memory->create(procs_a2a,nprocs,"rendezvous_a2a:procs"); diff --git a/src/comm_brick.cpp b/src/comm_brick.cpp index ecf382ab03..c5ec8b35f4 100644 --- a/src/comm_brick.cpp +++ b/src/comm_brick.cpp @@ -567,7 +567,7 @@ void CommBrick::reverse_comm() atoms exchanged with all 6 stencil neighbors send out atoms that have left my box, receive ones entering my box atoms will be lost if not inside a stencil proc's box - can happen if atom moves outside of non-periodic bounary + can happen if atom moves outside of non-periodic boundary or if atom moves more than one proc away this routine called before every reneighboring for triclinic, atoms must be in lamda coords (0-1) before exchange is called diff --git a/src/comm_tiled.cpp b/src/comm_tiled.cpp index 57b7f7e91e..a7eb6dfe80 100644 --- a/src/comm_tiled.cpp +++ b/src/comm_tiled.cpp @@ -618,7 +618,7 @@ void CommTiled::reverse_comm() atoms exchanged with procs that touch sub-box in each of 3 dims send out atoms that have left my box, receive ones entering my box atoms will be lost if not inside a touching proc's box - can happen if atom moves outside of non-periodic bounary + can happen if atom moves outside of non-periodic boundary or if atom moves more than one proc away this routine called before every reneighboring for triclinic, atoms must be in lamda coords (0-1) before exchange is called diff --git a/src/compute_cna_atom.cpp b/src/compute_cna_atom.cpp index 054798f637..c11f4016b5 100644 --- a/src/compute_cna_atom.cpp +++ b/src/compute_cna_atom.cpp @@ -142,7 +142,7 @@ void ComputeCNAAtom::compute_peratom() numneigh = list->numneigh; firstneigh = list->firstneigh; - // find the neigbours of each atom within cutoff using full neighbor list + // find the neighbours of each atom within cutoff using full neighbor list // nearest[] = atom indices of nearest neighbors, up to MAXNEAR // do this for all atoms, not just compute group // since CNA calculation requires neighbors of neighbors diff --git a/src/compute_orientorder_atom.cpp b/src/compute_orientorder_atom.cpp index dcb104fc3a..3dafd08a0f 100644 --- a/src/compute_orientorder_atom.cpp +++ b/src/compute_orientorder_atom.cpp @@ -508,7 +508,7 @@ void ComputeOrientOrderAtom::calc_boop(double **rlist, // TODO: // 1. [done]Need to allocate extra memory in qnarray[] for this option // 2. [done]Need to add keyword option - // 3. [done]Need to caclulate Clebsch-Gordan/Wigner 3j coefficients + // 3. [done]Need to calculate Clebsch-Gordan/Wigner 3j coefficients // (Can try getting them from boop.py first) // 5. [done]Compare to bcc values in /Users/athomps/netapp/codes/MatMiner/matminer/matminer/featurizers/boop.py // 6. [done]I get the right answer for W_l, but need to make sure that factor of 1/sqrt(l+1) is right for cglist diff --git a/src/dump_image.cpp b/src/dump_image.cpp index 7e6bc0c44c..a78c214e08 100644 --- a/src/dump_image.cpp +++ b/src/dump_image.cpp @@ -403,7 +403,7 @@ DumpImage::DumpImage(LAMMPS *lmp, int narg, char **arg) : image->buffers(); - // communication neede for bonds colored by atoms + // communication needed for bonds colored by atoms if (bondflag) { if (bcolor == ATOM || bdiam == ATOM) comm_forward = 3; diff --git a/src/fix_balance.cpp b/src/fix_balance.cpp index 5ca1ec124a..83973efab7 100644 --- a/src/fix_balance.cpp +++ b/src/fix_balance.cpp @@ -239,7 +239,7 @@ void FixBalance::pre_exchange() /* ---------------------------------------------------------------------- compute final imbalance factor based on nlocal after comm->exchange() - only do this if rebalancing just occured + only do this if rebalancing just occurred ------------------------------------------------------------------------- */ void FixBalance::pre_neighbor() diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index 9d84c4bb62..727065dafb 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -971,7 +971,7 @@ void FixDeform::restart(char *buf) set[i].hi_initial = set_restart[i].hi_initial; set[i].vol_initial = set_restart[i].vol_initial; set[i].tilt_initial = set_restart[i].tilt_initial; - // check if style settings are consitent (should do the whole set?) + // check if style settings are consistent (should do the whole set?) if (set[i].style != set_restart[i].style) samestyle = 0; if (set[i].substyle != set_restart[i].substyle) diff --git a/src/fix_tmd.cpp b/src/fix_tmd.cpp index cfe9a9572e..604660e7c4 100644 --- a/src/fix_tmd.cpp +++ b/src/fix_tmd.cpp @@ -13,7 +13,7 @@ /* ---------------------------------------------------------------------- Contributing authors: Paul Crozier (SNL) - Christian Burisch (Bochum Univeristy, Germany) + Christian Burisch (Bochum University, Germany) ------------------------------------------------------------------------- */ #include "fix_tmd.h" diff --git a/src/hashlittle.cpp b/src/hashlittle.cpp index c3824b71fe..5c336c2082 100644 --- a/src/hashlittle.cpp +++ b/src/hashlittle.cpp @@ -173,7 +173,7 @@ uint32_t LAMMPS_NS::hashlittle(const void *key, size_t length, uint32_t initval) * rest of the string. Every machine with memory protection I've seen * does it on word boundaries, so is OK with this. But VALGRIND will * still catch it and complain. The masking trick does make the hash - * noticably faster for short strings (like English words). + * noticeably faster for short strings (like English words). */ #ifndef VALGRIND diff --git a/src/input.cpp b/src/input.cpp index 6adf37e847..7024814896 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -1177,7 +1177,7 @@ void Input::print() if (narg < 1) error->all(FLERR,"Illegal print command"); // copy 1st arg back into line (copy is being used) - // check maxline since arg[0] could have been exanded by variables + // check maxline since arg[0] could have been expanded by variables // substitute for $ variables (no printing) and print arg int n = strlen(arg[0]) + 1; diff --git a/src/kspace.h b/src/kspace.h index 4bae983364..5a0790b63d 100644 --- a/src/kspace.h +++ b/src/kspace.h @@ -64,7 +64,7 @@ class KSpace : protected Pointers { double accuracy; // accuracy of KSpace solver (force units) double accuracy_absolute; // user-specified accuracy in force units double accuracy_relative; // user-specified dimensionless accuracy - // accurary = acc_rel * two_charge_force + // accuracy = acc_rel * two_charge_force double accuracy_real_6; // real space accuracy for // dispersion solver (force units) double accuracy_kspace_6; // reciprocal space accuracy for diff --git a/src/lammps.cpp b/src/lammps.cpp index 4b09429b52..0e3ec7d062 100644 --- a/src/lammps.cpp +++ b/src/lammps.cpp @@ -785,7 +785,7 @@ void LAMMPS::create() /* ---------------------------------------------------------------------- check suffix consistency with installed packages - invoke package-specific deafult package commands + invoke package-specific default package commands only invoke if suffix is set and enabled also check if suffix2 is set called from LAMMPS constructor and after clear() command diff --git a/src/my_pool_chunk.h b/src/my_pool_chunk.h index a313e45f05..da196f5ec9 100644 --- a/src/my_pool_chunk.h +++ b/src/my_pool_chunk.h @@ -18,7 +18,7 @@ MyPoolChunk = templated class for storing chunks of datums in pages replaces many small mallocs with a few large mallocs pages are never freed, so can reuse w/out reallocs usage: - continously get() and put() chunks as needed + continuously get() and put() chunks as needed NOTE: could add a clear() if retain info on mapping of pages to bins inputs: template T = one datum, e.g. int, double, struct diff --git a/src/neigh_request.cpp b/src/neigh_request.cpp index 1ad111d9c5..006ff5e87b 100644 --- a/src/neigh_request.cpp +++ b/src/neigh_request.cpp @@ -37,7 +37,7 @@ NeighRequest::NeighRequest(LAMMPS *lmp) : Pointers(lmp) half = 1; full = 0; - // attribute flags, mutiple can be set to 1 + // attribute flags, multiple can be set to 1 // default is every reneighboring, not occasional // default is use newton_pair setting in force // default is no neighbors of ghosts diff --git a/src/pair_zero.h b/src/pair_zero.h index 058edbd053..3af37aedb4 100644 --- a/src/pair_zero.h +++ b/src/pair_zero.h @@ -11,7 +11,7 @@ See the README file in the top-level LAMMPS directory. Pair zero is a dummy pair interaction useful for requiring a - force cutoff distance in the absense of pair-interactions or + force cutoff distance in the absence of pair-interactions or with hybrid/overlay if a larger force cutoff distance is required. This can be used in conjunction with bond/create to create bonds diff --git a/src/reset_ids.cpp b/src/reset_ids.cpp index 857738e841..4f81abd3fd 100644 --- a/src/reset_ids.cpp +++ b/src/reset_ids.cpp @@ -86,7 +86,7 @@ void ResetIDs::command(int narg, char ** /* arg */) tag[i] = 0; } - // assign new contigous IDs to owned atoms via tag_extend() + // assign new contiguous IDs to owned atoms via tag_extend() atom->tag_extend(); diff --git a/src/write_restart.cpp b/src/write_restart.cpp index 4b84e790b8..924584892b 100644 --- a/src/write_restart.cpp +++ b/src/write_restart.cpp @@ -299,7 +299,7 @@ void WriteRestart::write(char *file) // max_size = largest buffer needed by any proc // NOTE: are assuming size_restart() returns 32-bit int // for a huge one-proc problem, nlocal could be 32-bit - // but nlocal * doubles-peratom could oveflow + // but nlocal * doubles-peratom could overflow int max_size; int send_size = atom->avec->size_restart(); diff --git a/tools/amber2lmp/amber2lammps.py b/tools/amber2lmp/amber2lammps.py index 16b8ded46a..cb0820f96c 100644 --- a/tools/amber2lmp/amber2lammps.py +++ b/tools/amber2lmp/amber2lammps.py @@ -7,7 +7,7 @@ # # Modified by Vikas Varshney, U Akron, 5 July 2005, as described in README # Bug Fixed :Third argument in Dihedral Coeffs section is an integer - Ketan S Khare September 26, 2011 -# Modified by Vikas Varshney, Oct 8, 2013 to include additional flags (Atomic_Number, Coulombic and van der Waals 1-4 factors which are included in newer vesions of .top and .crd files in amber12. +# Modified by Vikas Varshney, Oct 8, 2013 to include additional flags (Atomic_Number, Coulombic and van der Waals 1-4 factors which are included in newer versions of .top and .crd files in amber12. #============================================================ diff --git a/tools/ch2lmp/charmm2lammps.pl b/tools/ch2lmp/charmm2lammps.pl index b53bd00541..c1ec8ad895 100755 --- a/tools/ch2lmp/charmm2lammps.pl +++ b/tools/ch2lmp/charmm2lammps.pl @@ -12,7 +12,7 @@ # - $project.psf ; CHARMM configs # - top_$forcefield.rtf ; # - par_$forcefield.prm ; -# Ouput: +# Output: # - $project.data ; LAMMPS data file # - $project.in ; LAMMPS input file # - $project_ctrl.pdb ; PDB control file @@ -329,7 +329,7 @@ } - sub PSFDihedrals # hack to accomodate + sub PSFDihedrals # hack to accommodate { # LAMMPS' way of calc $idihedral = 0; # LJ 1-4 interactions return $ndihedral if (($dihedral_flag = $ndihedral ? 1 : 0)); @@ -1785,7 +1785,7 @@ $C_flag = 0; } - # Quit if one of the atom types dosen't exist + # Quit if one of the atom types doesn't exist if ( $C_counter == 0 or ($CA_counter == 0 and $CA_GLY_counter == 0 and $CA_PRO_counter == 0) or ($N_counter == 0 and $N_PRO_counter == 0) ) { diff --git a/tools/ch2lmp/example/par_all27_na.prm b/tools/ch2lmp/example/par_all27_na.prm index b721c37393..542d30e917 100644 --- a/tools/ch2lmp/example/par_all27_na.prm +++ b/tools/ch2lmp/example/par_all27_na.prm @@ -124,7 +124,7 @@ ON2 P3 300.0 1.68 !PPI2, from nad/ppi, adm jr. 7/01 ON3 P3 480.0 1.53 !PPI2, from nad/ppi, adm jr. 7/01 ON4 P3 237.0 1.58 !PPI2, from MP_1, ADM Jr. NN5 HN1 460.0 1.01 !sugar model, adm jr. -!@@@@@@@@@ Begining of endocyclic bonds for deoxy-ribose @@@@@@@@@ +!@@@@@@@@@ Beginning of endocyclic bonds for deoxy-ribose @@@@@@@@@ CN7B ON6 260.0 1.420 ! From exp CN7B CN8 200.0 1.518 ! From exp CN7 ON6 240.0 1.446 ! Fom exp. @@ -135,21 +135,21 @@ CN7 HN7 309.0 1.111 !Alkanes, sacred CN8 HN8 309.0 1.111 !Alkanes, sacred CN7B HN7 309.0 1.111 ! From CN8 HN7 (NF) !@@@@@@@@@ End of endocyclic bonds for deoxy-ribose @@@@@@@@@ -!@@@@@@@@@ Begining of endocyclic bonds for ribose @@@@@@@@@ +!@@@@@@@@@ Beginning of endocyclic bonds for ribose @@@@@@@@@ CN7B ON6B 260.0 1.420 ! From CN7B ON6 CN7 ON6B 240.0 1.480 ! From CN7 ON6 CN7B CN7B 200.0 1.450 ! CN7 CN7B 222.5 1.460 ! Specific to RNA !@@@@@@@@@ End of endocyclic bonds for ribose @@@@@@@@@ -!@@@@@@@@@ Begining of endocyclic bonds for arabinose @@@@@@@@@ -! Transfered from DNA +!@@@@@@@@@ Beginning of endocyclic bonds for arabinose @@@@@@@@@ +! Transferred from DNA CN7B CN7C 200.0 1.518 ! For arabinose, from CN7B CN8 CN7 CN7C 222.5 1.516 ! For arabinose, from CN7 CN8 CN7C HN7 309.0 1.111 ! From CN8 HN7 !@@@@@@@@@ End of endocyclic bonds for arabinose @@@@@@@@@ -!@@@@@@@@@ Begining of exocyclic bonds for deoxy-ribose @@@@@@@@@ +!@@@@@@@@@ Beginning of exocyclic bonds for deoxy-ribose @@@@@@@@@ CN7 CN8B 222.5 1.512 ! From exp. CN8B ON2 320.0 1.44 ! From exp !CN8B ON5 250.0 1.44 ! From CN8B ON2 @@ -169,19 +169,19 @@ CN8B HN8 309.0 1.111 !Alkanes, sacred ON5 HN5 545.0 0.960 !RIBOSE, MeOH !@@@@@@@@@ End of exocyclic bonds for deoxy-ribose @@@@@@@@@ -!@@@@@@@@@ Begining of exocyclic bonds for ribose @@@@@@@@@ +!@@@@@@@@@ Beginning of exocyclic bonds for ribose @@@@@@@@@ !CN7B ON5 250.0 1.400 ! From CN7 ON5 CN7B ON5 428.0 1.400 ! check adm jr., !FC should be 428.000 based on Meoh !@@@@@@@@@ End of exocyclic bonds for ribose @@@@@@@@@ -!@@@@@@@@@ Begining of exocyclic bonds for arabinose @@@@@@@@@ +!@@@@@@@@@ Beginning of exocyclic bonds for arabinose @@@@@@@@@ !CN7C ON5 250.0 1.400 ! From CN7 ON5 CN7C ON5 428.0 1.400 ! check adm jr., !FC should be 428.000 based on Meoh !@@@@@@@@@ End of exocyclic bonds for arabinose @@@@@@@@@ -!@@@@@@@@@ Begining of bonds for nucleotide analogue @@@@@@@@@ +!@@@@@@@@@ Beginning of bonds for nucleotide analogue @@@@@@@@@ CN8 ON2 340.0 1.44 ! !@@@@@@@@@ End of bonds for nucleotide analogue @@@@@@@@@ @@ -1075,9 +1075,9 @@ CN7 ON6 CN7B NR1 0.0 3 0.0 CN7 ON6B CN7B NR1 0.0 3 0.0 ! RNUS NR1 CN7B CN8 CN7 0.0 3 0.0 !%%%%%%% new terms for dna and the deoxyribose-based model compounds %%%%%% -! The following is for: THF3P (model for espilon), THFM3P (model for puckering), +! The following is for: THF3P (model for epsilon), THFM3P (model for puckering), ! THF5P (model for gamma and beta), THFCH3IM (model for chi), nucleotide analogue -!@@@@@@ Begining of chi +!@@@@@@ Beginning of chi !============= added for torsion about chi in adenine ============ !For link from sugar to base: CN7B NN2 CN4 HN3 0.3 2 180.0 ! NF @@ -1214,7 +1214,7 @@ HN7 CN7B CN7B NN2B 0.0 3 0.0 HN7 CN7C CN7B NN2 0.0 3 0.0 HN7 CN7C CN7B NN2B 0.0 3 0.0 -!@@@@@@ Begining of torsions involving exocyclic sugar atoms: +!@@@@@@ Beginning of torsions involving exocyclic sugar atoms: !======= CN7 CN8B ON2 P = C4'-C5'-O5'-P CN7 CN8B ON2 P 0.2 1 120.0 !bet C4'-C5'-O5'-P, adm jr. ! the following differ significantly from the alcohols @@ -1354,7 +1354,7 @@ HN7 CN7 CN7 ON5 0.195 3 0.0 !======== CN7 CN7 ON2 P = C4'-C3'-O3'-P CN7 CN7 ON2 P 0.6 5 0.0 !eps CN7 CN7 ON2 P 0.2 4 0.0 !eps, locat of 200 mimima -CN7 CN7 ON2 P 0.0 3 180.0 !eps, barE beteen minima +CN7 CN7 ON2 P 0.0 3 180.0 !eps, barE between minima CN7 CN7 ON2 P 0.4 2 0.0 !eps, relE of 200 vs 275 min CN7 CN7 ON2 P 1.9 1 180.0 !eps !======== CN8 CN7 ON2 P = C2'-C3'-O3'-P @@ -1378,20 +1378,20 @@ CN7B CN7 ON5 HN5 0.8 3 0.0 ! RNA CN7B CN7 ON5 HN5 0.5 1 0.0 ! RNA CN7C CN7 ON5 HN5 0.8 3 0.0 ! Arabinose (from DNA) CN7C CN7 ON5 HN5 0.5 1 0.0 ! Arabinose (from DNA) -! Was simply transfered from HN7 CN7 ON2 P +! Was simply transferred from HN7 CN7 ON2 P ! adm jr. should convert to alcohol term (see ribose etc) HN7 CN7 ON5 HN5 0.0 3 0.0 HN7 CN7 CN8B HN8 0.195 3 0.0 !gam H-C4'-C5'-H HN7 CN7 CN7 CN8B 0.195 3 0.0 !gam H-C3'-C4'-C5' !@@@@@@ End of torsions involving exocyclic atoms: -!@@@@@@ Begining of torsions for endocyclic atoms only: +!@@@@@@ Beginning of torsions for endocyclic atoms only: CN8 CN7B ON6 CN7 0.6 6 180.0 !C2'-C1'-O4'-C4' CN8 CN7 CN7 ON6 0.0 3 0.0 !C2'-C3'-C4'-O4' CN7B CN7B ON6B CN7 0.0 6 0.0 ! RNA, Lowers barrier CN7B CN7 CN7 ON6B 0.0 3 0.0 ! RNA CN7C CN7B ON6 CN7 0.6 6 180.0 ! Arabinose (from DNA) CN7C CN7 CN7 ON6 0.0 3 0.0 ! Arabinose (from DNA) -!======== CN7 CN8 CN7B ON6 for nucleosides, transfered from ========= +!======== CN7 CN8 CN7B ON6 for nucleosides, transferred from ========= !======== CN7 CN8 CN8 ON6 from thfoh ============================== CN7 CN8 CN7B ON6 0.6 6 0.0 ! C3'-C2'-C1'-O4', adjust barrier CN7 CN7B CN7B ON6B 0.4 6 0.0 ! RNA @@ -1402,7 +1402,7 @@ CN7B CN8 CN7 CN7 0.4 6 0.0 ! good for amplitudes CN7B CN7B CN7 CN7 0.0 6 0.0 ! RNA CN7B CN7B CN8 CN7 0.0 6 0.0 ! RNA, 25P1 CN7B CN7C CN7 CN7 0.4 6 0.0 ! Arabinose (from DNA) -!======== CN7 CN7 ON6 CN7B for nucleosides, transfered from ======== +!======== CN7 CN7 ON6 CN7B for nucleosides, transferred from ======== !======== CN7 CN7 ON6 CN8 from thfohch3 ============================ CN7 CN7 ON6 CN7B 0.6 6 180.0 ! C3'-C4'-O4'-C1' CN7 CN7 ON6B CN7B 0.0 6 180.0 ! RNA @@ -1438,7 +1438,7 @@ HN7 CN7 CN7C HN7 0.195 3 0.0 !Arabinose (from DNA), H-C3'-C2'-H HN7 CN7C CN7 CN7 0.195 3 0.0 !Arabinose (from DNA), useful *cccc* !@@@@@@ End of torsions for endocyclic atoms only -!@@@@@@ Begining of torsions specifically defined for RNA @@@@@@ +!@@@@@@ Beginning of torsions specifically defined for RNA @@@@@@ ! N9-C1'-C2'-O2': NN2 CN7B CN7B ON5 0.000 3 0.0 ! Adenine and cytosine NN2B CN7B CN7B ON5 0.000 3 0.0 ! Guanine and uracil @@ -1461,7 +1461,7 @@ HN5 ON5 CN7B CN7 0.300 3 0.0 ! 030298 HN5 ON5 CN7B CN7 0.000 1 0.0 ! 030298 !@@@@@@ End of torsions specifically defined for RNA @@@@@@ -!@@@@@@ Begining of torsions specifically defined for arabinose @@@@@@ +!@@@@@@ Beginning of torsions specifically defined for arabinose @@@@@@ ON6 CN7B CN7C ON5 0.000 3 0.0 ! the following differ significantly from the protein based ! alcohol parameters (based on ethanol, see above) diff --git a/tools/colvars/abf_data.cpp b/tools/colvars/abf_data.cpp index 8b1ebd0a96..2ce2b927eb 100644 --- a/tools/colvars/abf_data.cpp +++ b/tools/colvars/abf_data.cpp @@ -82,7 +82,7 @@ ABFdata::ABFdata(const char *gradFileName) pos[i] = 0; for (unsigned int i = 0; i < scalar_dim; i++) { - // Here we do the Euclidian division iteratively + // Here we do the Euclidean division iteratively for (int k = Nvars - 1; k > 0; k--) { if (pos[k] == sizes[k]) { pos[k] = 0; @@ -213,7 +213,7 @@ void ABFdata::write_histogram(const char *fileName) pos[i] = 0; for (index = 0; index < scalar_dim; index++) { - // Here we do the Euclidian division iteratively + // Here we do the Euclidean division iteratively for (i = Nvars - 1; i > 0; i--) { if (pos[i] == sizes[i]) { pos[i] = 0; @@ -271,7 +271,7 @@ void ABFdata::write_bias(const char *fileName) } for (index = 0; index < scalar_dim; index++) { - // Here we do the Euclidian division iteratively + // Here we do the Euclidean division iteratively for (i = Nvars - 1; i > 0; i--) { if (pos[i] == sizes[i]) { pos[i] = 0; @@ -316,7 +316,7 @@ void ABFdata::write_field(double *field, const char *fileName) f = field; for (index = 0; index < scalar_dim; index++) { - // Here we do the Euclidian division iteratively + // Here we do the Euclidean division iteratively for (i = Nvars - 1; i > 0; i--) { if (pos[i] == sizes[i]) { pos[i] = 0; diff --git a/tools/doxygen/README b/tools/doxygen/README index c6a6229995..847acf2bb9 100644 --- a/tools/doxygen/README +++ b/tools/doxygen/README @@ -73,7 +73,7 @@ Results The doxygen documentation for LAMMPS is created in the following directories: - "tools/doxygen/doc" = LAMMPS documetation in "doxygen" html format. + "tools/doxygen/doc" = LAMMPS documentation in "doxygen" html format. In order to read the html documentation, start with loading the "index.html" file into an internet browser of choice from this directory. The generation of other formats (pdf, docbook, rtf or man) is disabled by default but can be diff --git a/tools/eff/lmp2radii.c b/tools/eff/lmp2radii.c index b62da070ba..f7ec790b1b 100644 --- a/tools/eff/lmp2radii.c +++ b/tools/eff/lmp2radii.c @@ -1759,7 +1759,7 @@ PyMODINIT_FUNC PyInit_lmp2radii(void) Py_ssize_t __pyx_5 = 0; PyObject *__pyx_6 = 0; __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - /*--- Libary function declarations ---*/ + /*--- Library function declarations ---*/ __pyx_init_filenames(); /*--- Initialize various global constants etc. ---*/ if (unlikely(__Pyx_InitGlobals() < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} diff --git a/tools/i-pi/drivers/LJ.f90 b/tools/i-pi/drivers/LJ.f90 index 342425f29e..8341c64be7 100644 --- a/tools/i-pi/drivers/LJ.f90 +++ b/tools/i-pi/drivers/LJ.f90 @@ -182,7 +182,7 @@ start = 1 DO i = 1, natoms - 1 - ! Only loops over the neigbour list, not all the atoms. + ! Only loops over the neighbour list, not all the atoms. DO j = start, index_list(i) CALL vector_separation(cell_h, cell_ih, atoms(i,:), atoms(n_list(j),:), rij, r2) IF (r2 < rc*rc) THEN ! Only calculates contributions between neighbouring particles. diff --git a/tools/i-pi/drivers/SG.f90 b/tools/i-pi/drivers/SG.f90 index 42d3e4945d..bb243b3469 100644 --- a/tools/i-pi/drivers/SG.f90 +++ b/tools/i-pi/drivers/SG.f90 @@ -250,7 +250,7 @@ start = 1 DO i = 1, natoms - 1 - ! Only loops over the neigbour list, not all the atoms. + ! Only loops over the neighbour list, not all the atoms. DO j = start, index_list(i) CALL vector_separation(cell_h, cell_ih, atoms(i,:), atoms(n_list(j),:), rij, r2) IF (r2 < rc*rc) THEN ! Only calculates contributions between neighbouring particles. diff --git a/tools/i-pi/ipi/engine/ensembles.py b/tools/i-pi/ipi/engine/ensembles.py index 9660ca983c..ef592405b0 100644 --- a/tools/i-pi/ipi/engine/ensembles.py +++ b/tools/i-pi/ipi/engine/ensembles.py @@ -104,7 +104,7 @@ class Ensemble(dobject): conserved quantity the dependencies are defined in bind. Args: - beads: The beads object from whcih the bead positions are taken. + beads: The beads object from which the bead positions are taken. nm: A normal modes object used to do the normal modes transformation. cell: The cell object from which the system box is taken. bforce: The forcefield object from which the force and virial are @@ -303,7 +303,7 @@ class NVTEnsemble(NVEEnsemble): higher simulation temperature, as is appropriate. Args: - beads: The beads object from whcih the bead positions are taken. + beads: The beads object from which the bead positions are taken. nm: A normal modes object used to do the normal modes transformation. cell: The cell object from which the system box is taken. bforce: The forcefield object from which the force and virial are @@ -422,7 +422,7 @@ class NPTEnsemble(NVTEnsemble): higher simulation temperature, as is appropriate. Args: - beads: The beads object from whcih the bead positions are taken. + beads: The beads object from which the bead positions are taken. nm: A normal modes object used to do the normal modes transformation. cell: The cell object from which the system box is taken. bforce: The forcefield object from which the force and virial are diff --git a/tools/i-pi/ipi/engine/outputs.py b/tools/i-pi/ipi/engine/outputs.py index fb5ebda96e..605d6a3b2d 100644 --- a/tools/i-pi/ipi/engine/outputs.py +++ b/tools/i-pi/ipi/engine/outputs.py @@ -85,7 +85,7 @@ class PropertyOutput(dobject): self.simul = simul # Checks as soon as possible if some asked-for properties are - # missing or mispelled + # missing or misspelled for what in self.outlist: key = getkey(what) if not key in self.simul.properties.property_dict.keys(): @@ -218,7 +218,7 @@ class TrajectoryOutput(dobject): self.simul = simul - # Checks as soon as possible if some asked-for trajs are missing or mispelled + # Checks as soon as possible if some asked-for trajs are missing or misspelled key = getkey(self.what) if not key in self.simul.trajs.traj_dict.keys(): print "Computable trajectories list: ", self.simul.trajs.traj_dict.keys() diff --git a/tools/i-pi/ipi/engine/properties.py b/tools/i-pi/ipi/engine/properties.py index a76aca1faf..e9c9646708 100644 --- a/tools/i-pi/ipi/engine/properties.py +++ b/tools/i-pi/ipi/engine/properties.py @@ -141,7 +141,7 @@ def help_latex(idict, standalone=True): } """ rstr += "\n\\begin{document}\n" - rstr += "The following are the different allowable ouputs:\n\\par" + rstr += "The following are the different allowable outputs:\n\\par" for out in sorted(idict): rstr += "\\ipiitem{" + out + "}" diff --git a/tools/i-pi/ipi/engine/simulation.py b/tools/i-pi/ipi/engine/simulation.py index 3c16a99621..eba03cc036 100644 --- a/tools/i-pi/ipi/engine/simulation.py +++ b/tools/i-pi/ipi/engine/simulation.py @@ -172,7 +172,7 @@ class Simulation(dobject): self.forces.run() - # prints inital configuration -- only if we are not restarting + # prints initial configuration -- only if we are not restarting if (self.step == 0): self.step = -1 for o in self.outputs: diff --git a/tools/i-pi/ipi/engine/thermostats.py b/tools/i-pi/ipi/engine/thermostats.py index 1fb048ec27..943deb47fd 100644 --- a/tools/i-pi/ipi/engine/thermostats.py +++ b/tools/i-pi/ipi/engine/thermostats.py @@ -532,9 +532,9 @@ class ThermoGLE(Thermostat): J. Chem. Phys. 134, 084104 (2011)). Attributes: - ns: The number of auxilliary degrees of freedom. + ns: The number of auxiliary degrees of freedom. s: An array holding all the momenta, including the ones for the - auxilliary degrees of freedom. + auxiliary degrees of freedom. Depend objects: A: Drift matrix giving the damping time scales for all the different @@ -560,7 +560,7 @@ class ThermoGLE(Thermostat): SST = Constants.kb*(self.C - np.dot(self.T,np.dot(self.C,self.T.T))) - # Uses a symetric decomposition rather than Cholesky, since it is more stable + # Uses a symmetric decomposition rather than Cholesky, since it is more stable return root_herm(SST) def get_C(self): @@ -675,10 +675,10 @@ class ThermoNMGLE(Thermostat): GLE for each normal mode Attributes: - ns: The number of auxilliary degrees of freedom. + ns: The number of auxiliary degrees of freedom. nb: The number of beads. s: An array holding all the momenta, including the ones for the - auxilliary degrees of freedom. + auxiliary degrees of freedom. Depend objects: A: Drift matrix giving the damping time scales for all the different diff --git a/tools/i-pi/ipi/tests/README b/tools/i-pi/ipi/tests/README index 17df9d7a7c..029c87a726 100644 --- a/tools/i-pi/ipi/tests/README +++ b/tools/i-pi/ipi/tests/README @@ -3,7 +3,7 @@ * This is the directory containing the tests that can be run with nosetests. * Files: - - common.py: Common helper funtions for use in the tests. + - common.py: Common helper functions for use in the tests. - datest.py: Tests the dependency utility and some of the numpy facilities. - test_*.py: The actual tests for at least some of the code basis. diff --git a/tools/i-pi/ipi/utils/depend.py b/tools/i-pi/ipi/utils/depend.py index 4b87323533..6c7f4ce24d 100644 --- a/tools/i-pi/ipi/utils/depend.py +++ b/tools/i-pi/ipi/utils/depend.py @@ -209,7 +209,7 @@ class depend_base(object): further down the dependency tree until either all objects have been tainted, or it reaches only objects that have already been tainted. Note that in the case of a dependency loop the initial setting of _tainted to - True prevents an infinite loop occuring. + True prevents an infinite loop occurring. Also, in the case of a synchro object, the manually set quantity is not tainted, as it is assumed that synchro objects only depend on each other. diff --git a/tools/i-pi/ipi/utils/inputvalue.py b/tools/i-pi/ipi/utils/inputvalue.py index d1bbc631fd..aae989a3c9 100644 --- a/tools/i-pi/ipi/utils/inputvalue.py +++ b/tools/i-pi/ipi/utils/inputvalue.py @@ -252,7 +252,7 @@ class Input(object): called, so that their tags are written between the start and end tags of this object, as is required for the xml format. - This also adds an indent to the lower levels of the xml heirarchy, + This also adds an indent to the lower levels of the xml hierarchy, so that it is easy to see which tags contain other tags. Args: diff --git a/tools/i-pi/ipi/utils/io/io_xml.py b/tools/i-pi/ipi/utils/io/io_xml.py index 5e43854408..fbf8867aaf 100644 --- a/tools/i-pi/ipi/utils/io/io_xml.py +++ b/tools/i-pi/ipi/utils/io/io_xml.py @@ -119,7 +119,7 @@ class xml_handler(ContentHandler): Adds the opening tag to the list of open tags, adds a new space in the buffer, reads the appropriate attributes and adds a new level to the - heirarchy. + hierarchy. Args: name: The tag_name. @@ -139,7 +139,7 @@ class xml_handler(ContentHandler): def characters(self, data): """Reads data. - Adds the data to the buffer of the current level of the heirarchy. + Adds the data to the buffer of the current level of the hierarchy. Data is read as a string, and needs to be converted to the required type later. diff --git a/tools/ipp/ipp b/tools/ipp/ipp index a7eac67247..081d19e243 100644 --- a/tools/ipp/ipp +++ b/tools/ipp/ipp @@ -2,7 +2,7 @@ # ipp: a preprocessor script # author : Reese Jones rjones@sandia.gov (based on dprepro [Sandia]) # to do : -# priority (overide file defaults e.g. a=1 pfile a=2 -> a=2) +# priority (override file defaults e.g. a=1 pfile a=2 -> a=2) # also order precedence: a=10 -p p.file b=12 # nested if/else/endif blocks diff --git a/tools/lmp2cfg/lmp2cfg.f b/tools/lmp2cfg/lmp2cfg.f index 80071f53db..14a5d5c56d 100644 --- a/tools/lmp2cfg/lmp2cfg.f +++ b/tools/lmp2cfg/lmp2cfg.f @@ -96,7 +96,7 @@ C clear data array. c-------------------------------------------------------------------- -c-------This section writes each ts to a seperate .cfg file---------- +c-------This section writes each ts to a separate .cfg file---------- ciframe='.cfg' write(snapshot,'(i5.5,a4)')iframe,ciframe open(unit=iframe+20,file=snapshot,status='new', diff --git a/tools/matlab/readdump_one.m b/tools/matlab/readdump_one.m index 762ca9bb20..7be751c888 100644 --- a/tools/matlab/readdump_one.m +++ b/tools/matlab/readdump_one.m @@ -124,7 +124,7 @@ varargout{1}.x_bound = x_bound; varargout{1}.y_bound = y_bound; varargout{1}.z_bound = z_bound; varargout{1}.atom_data = atom_data; -varargout{1}.position = p; %gives postion of ITEM: TIMESTEP line +varargout{1}.position = p; %gives position of ITEM: TIMESTEP line %------------------------------ fclose(dump); diff --git a/tools/matlab/readlog.m b/tools/matlab/readlog.m index 1fc88243ff..073b6c22ee 100644 --- a/tools/matlab/readlog.m +++ b/tools/matlab/readlog.m @@ -34,7 +34,7 @@ while feof(fid) == 0 end %------------------------------------------------------- - %---------Seperate column headings---------------------- + %---------Separate column headings---------------------- j=1; k=1; Ch=''; diff --git a/tools/matlab/readrdf.m b/tools/matlab/readrdf.m index 540bea7daf..4ec253942f 100644 --- a/tools/matlab/readrdf.m +++ b/tools/matlab/readrdf.m @@ -1,5 +1,5 @@ function varargout = readrdf(varargin) -% Function to read Radial Distribution Funtion output from LAMMPS +% Function to read Radial Distribution Function output from LAMMPS % Input % 'bin' --> number of bins in rdf histogram % 'runtime' --> Run length of each of the run commands diff --git a/tools/moltemplate/README.txt b/tools/moltemplate/README.txt index ca6a013244..97f68a85de 100644 --- a/tools/moltemplate/README.txt +++ b/tools/moltemplate/README.txt @@ -51,7 +51,7 @@ e.g. via: Updates to this distribution method are less frequent, than others, so if you need a more recent version, you can download it as a .tar.gz or .zip -archive from the moltemplate home page or GitHub (see linke above). After +archive from the moltemplate home page or GitHub (see link above). After downloading an archive and unpacking it, you should have 3 folders. moltemplate/ <-- source code and force fields @@ -65,7 +65,7 @@ the unpacked source archive: pip install . --user If you want to install into a system folder, then you need to run pip with -superuser priviledges. e.g. with: +superuser privileges. e.g. with: sudo pip install . diff --git a/tools/msi2lmp/frc_files/cvff.frc b/tools/msi2lmp/frc_files/cvff.frc index e3791aa86d..ba27e305e4 100644 --- a/tools/msi2lmp/frc_files/cvff.frc +++ b/tools/msi2lmp/frc_files/cvff.frc @@ -15,7 +15,7 @@ #version cvff.frc 2.4 01-Mar-02 ! Currently Insight does not handle version numbers on lines correctly. -! It uses the first occurence of a line, so when making changes you +! It uses the first occurrence of a line, so when making changes you ! can either comment the original out temporarily or put the correct ! line first. @@ -4624,7 +4624,7 @@ for silicate, copied directly from previous si and o parameters. @Date 07-Nov-91 #reference 15 -Adding a torsion parametr, cp cp o c = 1.8 so that the rotation barrier +Adding a torsion parameter, cp cp o c = 1.8 so that the rotation barrier around bond cp-o in anisole matches the experimental value ~3.0kcal/mole and the equilibrium geometry of anisole has torsion angle cp-cp-o-c =0 @Author Shenghua Shi diff --git a/tools/msi2lmp/frc_files/cvff_aug.frc b/tools/msi2lmp/frc_files/cvff_aug.frc index 75af9ace24..c9e19624fd 100644 --- a/tools/msi2lmp/frc_files/cvff_aug.frc +++ b/tools/msi2lmp/frc_files/cvff_aug.frc @@ -123,7 +123,7 @@ ! Currently Insight does not handle version numbers on lines correctly. -! It uses the first occurence of a line, so when making changes you +! It uses the first occurrence of a line, so when making changes you ! can either comment the original out temporarily or put the correct ! line first. @@ -5080,7 +5080,7 @@ for silicate, copied directly from previous si and o parameters. @Date 07-Nov-91 #reference 15 -Adding a torsion parametr, cp cp o c = 1.8 so that the rotation barrier +Adding a torsion parameter, cp cp o c = 1.8 so that the rotation barrier around bond cp-o in anisole matches the experimental value ~3.0kcal/mole and the equilibrium geometry of anisole has torsion angle cp-cp-o-c =0 @Author Shenghua Shi diff --git a/tools/msi2lmp/frc_files/oplsaa.frc b/tools/msi2lmp/frc_files/oplsaa.frc index fff69c819c..02a7dce867 100644 --- a/tools/msi2lmp/frc_files/oplsaa.frc +++ b/tools/msi2lmp/frc_files/oplsaa.frc @@ -1,6 +1,6 @@ !BIOSYM forcefield 1 -! This is a modified version of msi2lmp for use specifically wtih the +! This is a modified version of msi2lmp for use specifically with the ! OPLS force field. No out-of-plane or cross-terms are included. ! Atom types from SPC water and CLAYFF are also included. diff --git a/tools/msi2lmp/src/ReadCarFile.c b/tools/msi2lmp/src/ReadCarFile.c index 7932f7d6e2..7cde0914c4 100644 --- a/tools/msi2lmp/src/ReadCarFile.c +++ b/tools/msi2lmp/src/ReadCarFile.c @@ -227,7 +227,7 @@ void ReadCarFile(void) /* Search coordinates to find lowest and highest for x, y, and z */ if (periodic == 0) { - /* Added if/else statment STLM Oct 5 2010 */ + /* Added if/else statement STLM Oct 5 2010 */ if (TriclinicFlag == 0) { /* no need to re-center the box, if we use min/max values */ center[0] = center[1] = center[2] = 0.0; diff --git a/tools/phonon/dynmat.cpp b/tools/phonon/dynmat.cpp index 3b7bfe8268..36dcc97aba 100644 --- a/tools/phonon/dynmat.cpp +++ b/tools/phonon/dynmat.cpp @@ -408,7 +408,7 @@ void DynMat::EnforceASR() for (int i = 0; i < fftdim; ++i){ printf("%lg ", egvs[i]); if (i%10 == 9) printf("\n"); - if (i == 99){ printf("...... (%d more skiped)", fftdim-100); break;} + if (i == 99){ printf("...... (%d more skipped)", fftdim-100); break;} } printf("\n"); for (int i = 0; i < 80; ++i) printf("="); diff --git a/tools/phonon/green.cpp b/tools/phonon/green.cpp index 35514c03fb..16b2588a41 100644 --- a/tools/phonon/green.cpp +++ b/tools/phonon/green.cpp @@ -140,7 +140,7 @@ return; } /*------------------------------------------------------------------------------ - * Private method to compute the LDOS via the recusive method for system with + * Private method to compute the LDOS via the recursive method for system with * many atoms *----------------------------------------------------------------------------*/ void Green::Recursion() @@ -217,7 +217,7 @@ return; } /*------------------------------------------------------------------------------ - * Private method to compute the LDOS via the recusive method for system with + * Private method to compute the LDOS via the recursive method for system with * a few atoms (less than NMAX) *----------------------------------------------------------------------------*/ void Green::recursion() diff --git a/tools/polybond/lmpsdata.py b/tools/polybond/lmpsdata.py index 36cd6a0aa3..338090ed34 100644 --- a/tools/polybond/lmpsdata.py +++ b/tools/polybond/lmpsdata.py @@ -3,7 +3,7 @@ # lmpsdata.py # # For reading, writing and manipulating lammps data files -# For calculation of certain properities using lammps data files +# For calculation of certain proprieties using lammps data files # For creating VMD input text files using lammps data files # All x,y,z calculations assume the information includes image flags @@ -328,7 +328,7 @@ class Lmpsdata: if no modifications to any of the lammpsdata structures (modflag=0) Use Keywords to write lammpsdata structures directly if modifications to any of the lammpsdata structures (modflag=1) - Key Lammpsdata structures like atom numbers, coeficient numbers + Key Lammpsdata structures like atom numbers, coefficient numbers need to be modified to match the other modified lammpsdata structures This section will still use the keywords to write lammpsdata structures. For all modflags, the code will write data to the file until all of the @@ -403,7 +403,7 @@ class Lmpsdata: for line in self.atoms: f.write('\n') #creates a new line for adding body data for item in line: - f.write(' {0}'.format(item)) #adds in each peice of body data with space imbetween + f.write(' {0}'.format(item)) #adds in each piece of body data with space imbetween f.write('\n') #allows space to be added between the end of body data and a new keyword elif row=='Velocities': f.write('\n{0}'.format(row)) #new line between header and body portion or two body keywords @@ -411,7 +411,7 @@ class Lmpsdata: for line in self.velocities: f.write('\n') #creates a new line for adding body data for item in line: - f.write(' {0}'.format(item)) #adds in each peice of body data with space imbetween + f.write(' {0}'.format(item)) #adds in each piece of body data with space imbetween f.write('\n') #allows space to be added between the end of body data and a new keyword elif row=='Masses': f.write('\n{0}'.format(row)) #new line between header and body portion or two body keywords @@ -419,7 +419,7 @@ class Lmpsdata: for line in self.masses: f.write('\n') #creates a new line for adding body data for item in line: - f.write(' {0}'.format(item)) #adds in each peice of body data with space imbetween + f.write(' {0}'.format(item)) #adds in each piece of body data with space imbetween f.write('\n') #allows space to be added between the end of body data and a new keyword elif row=='Shapes': f.write('\n{0}'.format(row)) #new line between header and body portion or two body keywords @@ -427,7 +427,7 @@ class Lmpsdata: for line in self.shapes: f.write('\n') #creates a new line for adding body data for item in line: - f.write(' {0}'.format(item)) #adds in each peice of body data with space imbetween + f.write(' {0}'.format(item)) #adds in each piece of body data with space imbetween f.write('\n') #allows space to be added between the end of body data and a new keyword elif row=='Dipoles': f.write('\n{0}'.format(row)) #new line between header and body portion or two body keywords @@ -435,7 +435,7 @@ class Lmpsdata: for line in self.dipoles: f.write('\n') #creates a new line for adding body data for item in line: - f.write(' {0}'.format(item)) #adds in each peice of body data with space imbetween + f.write(' {0}'.format(item)) #adds in each piece of body data with space imbetween f.write('\n') #allows space to be added between the end of body data and a new keyword elif row=='Bonds': f.write('\n{0}'.format(row)) #new line between header and body portion or two body keywords @@ -443,7 +443,7 @@ class Lmpsdata: for line in self.bonds: f.write('\n') #creates a new line for adding body data for item in line: - f.write(' {0}'.format(item)) #adds in each peice of body data with space imbetween + f.write(' {0}'.format(item)) #adds in each piece of body data with space imbetween f.write('\n') #allows space to be added between the end of body data and a new keyword elif row=='Angles': f.write('\n{0}'.format(row)) #new line between header and body portion or two body keywords @@ -451,7 +451,7 @@ class Lmpsdata: for line in self.angles: f.write('\n') #creates a new line for adding body data for item in line: - f.write(' {0}'.format(item)) #adds in each peice of body data with space imbetween + f.write(' {0}'.format(item)) #adds in each piece of body data with space imbetween f.write('\n') #allows space to be added between the end of body data and a new keyword elif row=='Dihedrals': f.write('\n{0}'.format(row)) #new line between header and body portion or two body keywords @@ -459,14 +459,14 @@ class Lmpsdata: for line in self.dihedrals: f.write('\n') #creates a new line for adding body data for item in line: - f.write(' {0}'.format(item)) #adds in each peice of body data with space imbetween + f.write(' {0}'.format(item)) #adds in each piece of body data with space imbetween elif row=='Impropers': f.write('\n{0}'.format(row)) #new line between header and body portion or two body keywords f.write('\n') #new line between body keyword and body data for line in self.impropers: f.write('\n') #creates a new line for adding body data for item in line: - f.write(' {0}'.format(item)) #adds in each peice of body data with space imbetween + f.write(' {0}'.format(item)) #adds in each piece of body data with space imbetween f.write('\n') #allows space to be added between the end of body data and a new keyword elif row=='Pair Coeffs': f.write('\n{0}'.format(row)) #new line between header and body portion or two body keywords @@ -474,7 +474,7 @@ class Lmpsdata: for line in self.paircoef: f.write('\n') #creates a new line for adding body data for item in line: - f.write(' {0}'.format(item)) #adds in each peice of body data with space imbetween + f.write(' {0}'.format(item)) #adds in each piece of body data with space imbetween f.write('\n') #allows space to be added between the end of body data and a new keyword elif row=='Bond Coeffs': f.write('\n{0}'.format(row)) #new line between header and body portion or two body keywords @@ -482,7 +482,7 @@ class Lmpsdata: for line in self.bondcoef: f.write('\n') #creates a new line for adding body data for item in line: - f.write(' {0}'.format(item)) #adds in each peice of body data with space imbetween + f.write(' {0}'.format(item)) #adds in each piece of body data with space imbetween f.write('\n') #allows space to be added between the end of body data and a new keyword elif row=='Angle Coeffs': f.write('\n{0}'.format(row)) #new line between header and body portion or two body keywords @@ -490,7 +490,7 @@ class Lmpsdata: for line in self.anglecoef: f.write('\n') #creates a new line for adding body data for item in line: - f.write(' {0}'.format(item)) #adds in each peice of body data with space imbetween + f.write(' {0}'.format(item)) #adds in each piece of body data with space imbetween f.write('\n') #allows space to be added between the end of body data and a new keyword elif row=='Dihedral Coeffs': f.write('\n{0}'.format(row)) #new line between header and body portion or two body keywords @@ -498,7 +498,7 @@ class Lmpsdata: for line in self.dihedralcoef: f.write('\n') #creates a new line for adding body data for item in line: - f.write(' {0}'.format(item)) #adds in each peice of body data with space imbetween + f.write(' {0}'.format(item)) #adds in each piece of body data with space imbetween f.write('\n') #allows space to be added between the end of body data and a new keyword elif row=='Improper Coeffs': f.write('\n{0}'.format(row)) #new line between header and body portion or two body keywords @@ -506,7 +506,7 @@ class Lmpsdata: for line in self.impropercoef: f.write('\n') #creates a new line for adding body data for item in line: - f.write(' {0}'.format(item)) #adds in each peice of body data with space imbetween + f.write(' {0}'.format(item)) #adds in each piece of body data with space imbetween f.write('\n') #allows space to be added between the end of body data and a new keyword else: pass @@ -514,7 +514,7 @@ class Lmpsdata: def atomorder(self): """Takes self.atoms and organizes the atom id from least to greatest. - If the atom ids are allready ordered this algorithm will do nothing.""" + If the atom ids are already ordered this algorithm will do nothing.""" current=range(len(self.atoms[0])) # initialize current [assumes self.atoms coloumn #'s does not change] for i in range(1,len(self.atoms)): #when i=0, self.atoms will not change; therefore its skipped for k in range(len(self.atoms[i])): @@ -715,7 +715,7 @@ class Lmpsdata: extracts the individual molecules' data back into lmpsdata. This extraction takes place through a 4 step process. Step 1: Use a molecule's keywords to alter the lmpsdata data structures to empty. - To acomplish this procedure use the lmpsdata method deletebodydata. + To accomplish this procedure use the lmpsdata method deletebodydata. Step 2: Add the molecules' atoms to lmpsdata's atoms using the method addatoms. Return a list of atom id changes for each molecule. Step 3: Utilize each molecules list of atom id changes to change their data's atom id numbers. @@ -966,7 +966,7 @@ def distance(a,coord,atomtype): class particlesurface: def __init__(self,particle,cutoff,atomid,atomtype,shape='sphere'): """Builds a particle surface with a specific shape from a particle - The atoms choosen from the surface will have the specific atomid + The atoms chosen from the surface will have the specific atomid atomid will be given in terms of an integer and not a string.""" self.particle=particle.atoms self.atomtype=atomtype @@ -1026,7 +1026,7 @@ class particlesurface: def deleteatoms(self,structure,rows): """delete atoms from particle and shifts the structure down""" new=[] - #mulitple copying of b to the rows being replaced. + #multiple copying of b to the rows being replaced. if rows==[]: for line in structure: new.append(line) #if no rows need replacing copy structure @@ -1081,7 +1081,7 @@ class particlesurface: self.particle.append([]) self.surface.append([]) - pposition=len(self.particle)-1 #particle postion + pposition=len(self.particle)-1 #particle position sposition=len(self.surface)-1 #surface position # Adds the atom id number to the new row @@ -1122,7 +1122,7 @@ class particlesurface: def createxyz(self,file,data,routine='mass', values=None): - """This shows the particle surface. To show the particle surface after bonding has occured, + """This shows the particle surface. To show the particle surface after bonding has occurred, you will need to extract the particle than reinsert the particle into the class and use createxyz. Two possible routines one to use the masses from data and the other to use the atom type and values supplied by the user. The mass version is assessed by setting the routine to 'mass' which is the default method. @@ -1199,7 +1199,7 @@ def molecules(data,init,final,processors, method='all'): p.join() return molecule -class Lmpsmolecule: #Technically should be a meta class but written as a seperate class for easier coding. +class Lmpsmolecule: #Technically should be a meta class but written as a separate class for easier coding. def __init__(self,moleculenum,data,method): """initiates lammps molecule structures and than extract the appropriate molecular structures from the base class data""" @@ -1510,7 +1510,7 @@ class Lmpsmolecule: #Technically should be a meta class but written as a seperat """delete rows in a structure and shifts the structure up rows must be in increasing order for this algorithm to work correctly""" new=[] - #mulitple copying of b to the rows being replaced. + #multiple copying of b to the rows being replaced. if rows==[]: for line in structure: new.append(line) #if no rows need replacing copy structure @@ -1598,7 +1598,7 @@ class Lmpsmolecule: #Technically should be a meta class but written as a seperat if nextatoms[i]==atom: #checking if atom is in next atom del nextatoms[i] #delete the atom at i break - if nextatoms==[]: break #all bonds from find bonds have allready been added to bondedatoms + if nextatoms==[]: break #all bonds from find bonds have already been added to bondedatoms #append next atoms into bondedatoms #copy next atoms into prevatoms @@ -1607,7 +1607,7 @@ class Lmpsmolecule: #Technically should be a meta class but written as a seperat bondedatoms.append(atom) prevatoms.append(atom) - #iterative proccess for finding the rest of the atoms bonded to atomnumbers in the direction of atomid. + #iterative process for finding the rest of the atoms bonded to atomnumbers in the direction of atomid. while prevatoms!=[]: nextatoms=self.findbonds(prevatoms) #need to remove atoms from nextatoms which are in the prevatoms @@ -1616,7 +1616,7 @@ class Lmpsmolecule: #Technically should be a meta class but written as a seperat if nextatoms[i]==atom: #checking if atom is in next atom del nextatoms[i] #delete the atom at i break - if nextatoms==[]: break #all bonds from find bonds have allready been added to bondedatoms + if nextatoms==[]: break #all bonds from find bonds have already been added to bondedatoms #append next atoms into bondedatoms #copy next atoms into prevatoms @@ -1694,8 +1694,8 @@ class Lmpsmolecule: #Technically should be a meta class but written as a seperat def listorder(self,struct): """Takes struct and organizes the list from least to greatest. - If the list is allready ordered this algorithm will do nothing.""" - if len(struct)==1: return struct #with the length at 1; thier is only one element and theirfore nothing to order + If the list is already ordered this algorithm will do nothing.""" + if len(struct)==1: return struct #with the length at 1; there is only one element and therefore nothing to order for i in range(1,len(struct)): #when i=0, struct will not change; therefore its skipped copy=struct[i] for j in range(i-1,-1,-1): @@ -1756,8 +1756,8 @@ class Lmpsmolecule: #Technically should be a meta class but written as a seperat The second index correspons with the molecule/particle combination The third index corresponds with whether the value is the molecule or the particle Always bonds the two ends of the molecule that meet cutoff requirement. - All other possible bonds are randomly choosen until the required bondnumbers are met. - After every bond is choosen, the particle object's boolean list is updated, and possiblebonds is updated. + All other possible bonds are randomly chosen until the required bondnumbers are met. + After every bond is chosen, the particle object's boolean list is updated, and possiblebonds is updated. The update to possiblebonds involves removing the row from which the bonded molecule's atom is located and also removing the particle atom and it's corresponding bonded atom from other rows of possiblebonds. The final bonds are all stored in self.bonding as a 2 dimensional list""" @@ -1896,7 +1896,7 @@ class Lmpsmolecule: #Technically should be a meta class but written as a seperat # Alters the charge of the molecule's atoms bonded to the particle to newcharge self.modifyatom(self.bondinginformation[i][0]+1,3,newcharge) - #This is a seperate loop so atom id's and row indexes for previous steps wont get out of sync + #This is a separate loop so atom id's and row indexes for previous steps wont get out of sync #create atomnumbers to begin deletion process. atomnumbers=[] for i in range(len(self.bondinginformation)): @@ -1906,7 +1906,7 @@ class Lmpsmolecule: #Technically should be a meta class but written as a seperat #Than delete those atoms and all molecule structures which contain those atoms. self.deleteatoms(atomnumbers,atomid) - print 'begining deletion process of the surface atoms for which the molecule atoms have replaced' + print 'beginning deletion process of the surface atoms for which the molecule atoms have replaced' #Goes through the bondinginformation and superficially removes the surfaceatom for i in range(len(self.bondinginformation)): particle.removesurfatom(self.bondinginformation[i][1]) #uses the row number diff --git a/tools/pymol_asphere/src/cartesian.cpp b/tools/pymol_asphere/src/cartesian.cpp index a244d07dac..e137c51e7a 100644 --- a/tools/pymol_asphere/src/cartesian.cpp +++ b/tools/pymol_asphere/src/cartesian.cpp @@ -879,7 +879,7 @@ double c::closest_approach(const cPt &l1_1, const cPt &l1_2, const cPt &l2_1, double tc, tN, tD = D; // compute the closest points between the two lines - if (D < 0.00000000001) { // parrallel lines + if (D < 0.00000000001) { // parallel lines sN = 0.0; sD = 1.0; tN = e; tD = c; } else { // get the closest points on the infinite lines sN = (b*e - c*d); @@ -936,7 +936,7 @@ void c::closest_approach_points(const cPt &l1_1, const cPt &l1_2, double tc, tN, tD = D; // compute the closest points between the two lines - if (D < 0.00000000001) { // parrallel lines + if (D < 0.00000000001) { // parallel lines sN = 0.0; sD = 1.0; tN = e; tD = c; } else { // get the closest points on the infinite lines sN = (b*e - c*d); diff --git a/tools/pymol_asphere/src/error.h b/tools/pymol_asphere/src/error.h index f14af6f253..c0775d6506 100644 --- a/tools/pymol_asphere/src/error.h +++ b/tools/pymol_asphere/src/error.h @@ -112,7 +112,7 @@ class Notice { * to format it for the string. Forced newlines can be specified with \n * * Programs can check whether or not errors have been generated using the [] - * operator and can 'handle' them by outputing the message or dismissing + * operator and can 'handle' them by outputting the message or dismissing * them without any output * * Notices are generated using the public Notice class (see Notice()) diff --git a/tools/reax/reaxc_bond.pl b/tools/reax/reaxc_bond.pl index 9b0fa50672..cc0fd8f238 100755 --- a/tools/reax/reaxc_bond.pl +++ b/tools/reax/reaxc_bond.pl @@ -126,7 +126,7 @@ sub bonds { } close (OUTPUT2); #close the temp file as output - open INPUT3, ") { next if(/Frame/); split; diff --git a/tools/replica/reorder_remd_traj.py b/tools/replica/reorder_remd_traj.py index 5f4f316b14..01a179351d 100644 --- a/tools/replica/reorder_remd_traj.py +++ b/tools/replica/reorder_remd_traj.py @@ -160,7 +160,7 @@ def get_byte_index(rep_inds, byteindfns, intrajfns): :param intrajfns: list of (unordered) input traj filenames """ for n in rep_inds: - # check if the byte indices for this traj has aleady been computed + # check if the byte indices for this traj has already been computed if os.path.isfile(byteindfns[n]): continue # extract bytes diff --git a/tools/spin/interpolate_gneb/README b/tools/spin/interpolate_gneb/README index ab30373249..cf52ccb274 100644 --- a/tools/spin/interpolate_gneb/README +++ b/tools/spin/interpolate_gneb/README @@ -20,7 +20,7 @@ geodesic dist to next replica All those information can be provided by the verbose output of a neb/spin calculation -The progam outputs the interpolation result, and the +The program outputs the interpolation result, and the interpolated MEP in "interpolation_result.dat". This code is a courtesy of Aleksei Ivanov, University of diff --git a/tools/xmgrace/lammpsplot.cpp b/tools/xmgrace/lammpsplot.cpp index 7badb5652b..848c53a091 100644 --- a/tools/xmgrace/lammpsplot.cpp +++ b/tools/xmgrace/lammpsplot.cpp @@ -29,7 +29,7 @@ public: }; -/* This function splits the sentence into array of strings seperated by " "*/ +/* This function splits the sentence into array of strings separated by " "*/ sentence split(const string& s) { sentence a; s_type i=0; -- GitLab From d0ec4272936212f404fd7fb78c76994003a1e51e Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sat, 14 Mar 2020 06:49:57 -0600 Subject: [PATCH 276/689] KIM.cmake: fix build with ninja --- cmake/Modules/Packages/KIM.cmake | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cmake/Modules/Packages/KIM.cmake b/cmake/Modules/Packages/KIM.cmake index a75e248097..cbb6aa22c9 100644 --- a/cmake/Modules/Packages/KIM.cmake +++ b/cmake/Modules/Packages/KIM.cmake @@ -34,9 +34,6 @@ if(PKG_KIM) endif() option(DOWNLOAD_KIM "Download KIM-API from OpenKIM instead of using an already installed one" ${DOWNLOAD_KIM_DEFAULT}) if(DOWNLOAD_KIM) - if(CMAKE_GENERATOR STREQUAL "Ninja") - message(FATAL_ERROR "Cannot build downloaded KIM-API library with Ninja build tool") - endif() message(STATUS "KIM-API download requested - we will build our own") include(CheckLanguage) include(ExternalProject) @@ -54,6 +51,7 @@ if(PKG_KIM) -DCMAKE_Fortran_COMPILER=${CMAKE_Fortran_COMPILER} -DCMAKE_INSTALL_PREFIX= -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + BUILD_BYPRODUCTS /${CMAKE_INSTALL_LIBDIR}/libkim-api${CMAKE_SHARED_LIBRARY_SUFFIX} ) ExternalProject_get_property(kim_build INSTALL_DIR) set(KIM-API_INCLUDE_DIRS ${INSTALL_DIR}/include/kim-api) -- GitLab From f9e2a2d1207db5af4b4574b50223fa0c2e188199 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sat, 14 Mar 2020 06:51:00 -0600 Subject: [PATCH 277/689] LATTE.cmake: fix build with ninja --- cmake/Modules/Packages/LATTE.cmake | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cmake/Modules/Packages/LATTE.cmake b/cmake/Modules/Packages/LATTE.cmake index 8bcda84cdc..7244cb151f 100644 --- a/cmake/Modules/Packages/LATTE.cmake +++ b/cmake/Modules/Packages/LATTE.cmake @@ -8,9 +8,6 @@ if(PKG_LATTE) endif() option(DOWNLOAD_LATTE "Download the LATTE library instead of using an already installed one" ${DOWNLOAD_LATTE_DEFAULT}) if(DOWNLOAD_LATTE) - if(CMAKE_GENERATOR STREQUAL "Ninja") - message(FATAL_ERROR "Cannot build downloaded LATTE library with Ninja build tool") - endif() message(STATUS "LATTE download requested - we will build our own") include(ExternalProject) ExternalProject_Add(latte_build @@ -21,6 +18,7 @@ if(PKG_LATTE) -DBLAS_LIBRARIES=${BLAS_LIBRARIES} -DLAPACK_LIBRARIES=${LAPACK_LIBRARIES} -DCMAKE_Fortran_COMPILER=${CMAKE_Fortran_COMPILER} -DCMAKE_Fortran_FLAGS=${CMAKE_Fortran_FLAGS} -DCMAKE_Fortran_FLAGS_${BTYPE}=${CMAKE_Fortran_FLAGS_${BTYPE}} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + BUILD_BYPRODUCTS /${CMAKE_INSTALL_LIBDIR}/liblatte.a ) ExternalProject_get_property(latte_build INSTALL_DIR) set(LATTE_LIBRARIES ${INSTALL_DIR}/${CMAKE_INSTALL_LIBDIR}/liblatte.a) -- GitLab From 9d3ca8795366c3f41d85df8100b2ff3d5a682729 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sat, 14 Mar 2020 06:52:06 -0600 Subject: [PATCH 278/689] MSCG.cmake: fix build with ninja --- cmake/Modules/Packages/MSCG.cmake | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cmake/Modules/Packages/MSCG.cmake b/cmake/Modules/Packages/MSCG.cmake index 99d98659ee..67db9ab251 100644 --- a/cmake/Modules/Packages/MSCG.cmake +++ b/cmake/Modules/Packages/MSCG.cmake @@ -8,9 +8,6 @@ if(PKG_MSCG) endif() option(DOWNLOAD_MSCG "Download MSCG library instead of using an already installed one)" ${DOWNLOAD_MSCG_DEFAULT}) if(DOWNLOAD_MSCG) - if(CMAKE_GENERATOR STREQUAL "Ninja") - message(FATAL_ERROR "Cannot build downloaded MSCG library with Ninja build tool") - endif() include(ExternalProject) if(NOT LAPACK_FOUND) set(EXTRA_MSCG_OPTS "-DLAPACK_LIBRARIES=${CMAKE_CURRENT_BINARY_DIR}/liblinalg.a") @@ -21,6 +18,7 @@ if(PKG_MSCG) SOURCE_SUBDIR src/CMake CMAKE_ARGS -DCMAKE_INSTALL_PREFIX= ${CMAKE_REQUEST_PIC} ${EXTRA_MSCG_OPTS} BUILD_COMMAND make mscg INSTALL_COMMAND "" + BUILD_BYPRODUCTS /libmscg.a ) ExternalProject_get_property(mscg_build BINARY_DIR) set(MSCG_LIBRARIES ${BINARY_DIR}/libmscg.a) -- GitLab From ad9415d2606d4d58aece6b52d0e58b9d2c0ec127 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sat, 14 Mar 2020 06:59:04 -0600 Subject: [PATCH 279/689] USER-PLUMED.cmake: fix build with ninja --- cmake/Modules/Packages/USER-PLUMED.cmake | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cmake/Modules/Packages/USER-PLUMED.cmake b/cmake/Modules/Packages/USER-PLUMED.cmake index e10176f9fd..426ae2df2a 100644 --- a/cmake/Modules/Packages/USER-PLUMED.cmake +++ b/cmake/Modules/Packages/USER-PLUMED.cmake @@ -29,9 +29,6 @@ if(PKG_USER-PLUMED) option(DOWNLOAD_PLUMED "Download Plumed package instead of using an already installed one" ${DOWNLOAD_PLUMED_DEFAULT}) if(DOWNLOAD_PLUMED) - if(CMAKE_GENERATOR STREQUAL "Ninja") - message(FATAL_ERROR "Cannot build downloaded Plumed library with Ninja build tool") - endif() if(BUILD_MPI) set(PLUMED_CONFIG_MPI "--enable-mpi") set(PLUMED_CONFIG_CC ${CMAKE_MPI_C_COMPILER}) @@ -47,6 +44,13 @@ if(PKG_USER-PLUMED) set(PLUMED_CONFIG_OMP "--disable-openmp") endif() message(STATUS "PLUMED download requested - we will build our own") + if(PLUMED_MODE STREQUAL "STATIC") + set(PLUMED_BUILD_BYPRODUCTS "/lib/libplumed.a") + elseif(PLUMED_MODE STREQUAL "SHARED") + set(PLUMED_BUILD_BYPRODUCTS "/lib/libplumed${CMAKE_SHARED_LIBRARY_SUFFIX};/lib/libplumedKernel${CMAKE_SHARED_LIBRARY_SUFFIX}") + elseif(PLUMED_MODE STREQUAL "RUNTIME") + set(PLUMED_BUILD_BYPRODUCTS "/lib/libplumedWrapper.a") + endif() include(ExternalProject) ExternalProject_Add(plumed_build URL https://github.com/plumed/plumed2/releases/download/v2.6.0/plumed-src-2.6.0.tgz @@ -59,6 +63,7 @@ if(PKG_USER-PLUMED) ${PLUMED_CONFIG_OMP} CXX=${PLUMED_CONFIG_CXX} CC=${PLUMED_CONFIG_CC} + BUILD_BYPRODUCTS ${PLUMED_BUILD_BYPRODUCTS} ) ExternalProject_get_property(plumed_build INSTALL_DIR) set(PLUMED_INSTALL_DIR ${INSTALL_DIR}) -- GitLab From d941130e6aef4bd6010d6d55d2fb3df11bca6772 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sat, 14 Mar 2020 07:04:58 -0600 Subject: [PATCH 280/689] USER-SCAFACOS.cmake: fix build with ninja --- cmake/Modules/Packages/USER-SCAFACOS.cmake | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/cmake/Modules/Packages/USER-SCAFACOS.cmake b/cmake/Modules/Packages/USER-SCAFACOS.cmake index 475f2585c8..e8f14eb403 100644 --- a/cmake/Modules/Packages/USER-SCAFACOS.cmake +++ b/cmake/Modules/Packages/USER-SCAFACOS.cmake @@ -13,9 +13,6 @@ if(PKG_USER-SCAFACOS) endif() option(DOWNLOAD_SCAFACOS "Download ScaFaCoS library instead of using an already installed one" ${DOWNLOAD_SCAFACOS_DEFAULT}) if(DOWNLOAD_SCAFACOS) - if(CMAKE_GENERATOR STREQUAL "Ninja") - message(FATAL_ERROR "Cannot build downloaded ScaFaCoS library with Ninja build tool") - endif() message(STATUS "ScaFaCoS download requested - we will build our own") include(ExternalProject) ExternalProject_Add(scafacos_build @@ -29,6 +26,22 @@ if(PKG_USER-SCAFACOS) CXX=${CMAKE_MPI_CXX_COMPILER} CC=${CMAKE_MPI_C_COMPILER} F77= + BUILD_BYPRODUCTS + /lib/libfcs.a + /lib/libfcs_direct.a + /lib/libfcs_ewald.a + /lib/libfcs_fmm.a + /lib/libfcs_p2nfft.a + /lib/libfcs_p3m.a + /lib/libfcs_near.a + /lib/libfcs_gridsort.a + /lib/libfcs_resort.a + /lib/libfcs_redist.a + /lib/libfcs_common.a + /lib/libfcs_pnfft.a + /lib/libfcs_pfft.a + /lib/libfcs_fftw3_mpi.a + /lib/libfcs_fftw3.a ) ExternalProject_get_property(scafacos_build INSTALL_DIR) set(SCAFACOS_BUILD_DIR ${INSTALL_DIR}) -- GitLab From 9cf1d375561f24ec0752e1f7b3160d3d376a638e Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sat, 14 Mar 2020 07:21:06 -0600 Subject: [PATCH 281/689] cmake: move fortran check for ninja in an include --- cmake/CMakeLists.txt | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 83b86a7b30..2fbc17dcf4 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -255,8 +255,9 @@ if(PKG_MSCG OR PKG_USER-ATC OR PKG_USER-AWPMD OR PKG_USER-QUIP OR PKG_LATTE) find_package(LAPACK) find_package(BLAS) if(NOT LAPACK_FOUND OR NOT BLAS_FOUND) - if(CMAKE_GENERATOR STREQUAL "Ninja") - status(FATAL_ERROR "Cannot build internal linear algebra library with Ninja build tool due to lack for Fortran support") + include(CheckIfNinjaSupportsFortran) + if(NOT CMAKE_GENERATOR_SUPPORT_FORTRAN) + status(FATAL_ERROR "Cannot build internal linear algebra library as CMake build tool lacks Fortran support") endif() enable_language(Fortran) file(GLOB LAPACK_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/linalg/[^.]*.[fF]) @@ -587,29 +588,14 @@ if(BUILD_TOOLS) add_executable(binary2txt ${LAMMPS_TOOLS_DIR}/binary2txt.cpp) install(TARGETS binary2txt DESTINATION ${CMAKE_INSTALL_BINDIR}) - # ninja-build<1.10 does not support fortran. thus we skip building this tool - if(CMAKE_GENERATOR STREQUAL "Ninja") - set(CMAKE_GENERATOR_SUPPORT_FORTRAN FALSE) - execute_process(COMMAND "${CMAKE_MAKE_PROGRAM}" --version - OUTPUT_VARIABLE NINJA_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE - RESULT_VARIABLE _Ninja_version_result - ) - if(_Ninja_version_result) - message(WARNING "Unable to determine ninja version: ${_Ninja_version_result}") - elseif(NINJA_VERSION VERSION_LESS "1.10") - message(WARNING "Ninja build tool too old, skipping building 'chain.x' due to lack of Fortran support, please install ninja-1.10 or newer") - else() - set(CMAKE_GENERATOR_SUPPORT_FORTRAN TRUE) - endif() - else() - set(CMAKE_GENERATOR_SUPPORT_FORTRAN TRUE) - endif() + include(CheckIfNinjaSupportsFortran) if(CMAKE_GENERATOR_SUPPORT_FORTRAN) enable_language(Fortran) add_executable(chain.x ${LAMMPS_TOOLS_DIR}/chain.f) target_link_libraries(chain.x ${CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES}) install(TARGETS chain.x DESTINATION ${CMAKE_INSTALL_BINDIR}) + else() + message(WARNING "CMake build doesn't support fortran, skipping building 'chain.x'") endif() enable_language(C) -- GitLab From 241f30fd53c9da05efbd4b320a3adaa44533e443 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 15 Mar 2020 13:34:38 -0600 Subject: [PATCH 282/689] added missing CheckIfNinjaSupportsFortran.cmake --- .../Modules/CheckIfNinjaSupportsFortran.cmake | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 cmake/Modules/CheckIfNinjaSupportsFortran.cmake diff --git a/cmake/Modules/CheckIfNinjaSupportsFortran.cmake b/cmake/Modules/CheckIfNinjaSupportsFortran.cmake new file mode 100644 index 0000000000..62d33036a5 --- /dev/null +++ b/cmake/Modules/CheckIfNinjaSupportsFortran.cmake @@ -0,0 +1,21 @@ +# ninja-build<1.10 does not support fortran. +if(CMAKE_GENERATOR STREQUAL "Ninja") + set(CMAKE_GENERATOR_SUPPORT_FORTRAN FALSE) + execute_process(COMMAND "${CMAKE_MAKE_PROGRAM}" --version + OUTPUT_VARIABLE NINJA_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE _Ninja_version_result + ) + if(_Ninja_version_result) + message(WARNING "Unable to determine ninja version: ${_Ninja_version_result}, assuming fortran isn't supported") + elseif(NINJA_VERSION VERSION_LESS "1.10") + message(WARNING "Ninja build tool too old, to compile Fortran code, please install ninja-1.10 or newer") + else() + set(CMAKE_GENERATOR_SUPPORT_FORTRAN TRUE) + endif() +else() + set(CMAKE_GENERATOR_SUPPORT_FORTRAN TRUE) + if(NOT CMAKE_GENERATOR STREQUAL "Unix Makefiles") + message(WARNING "Assuming fortran is supported for ${CMAKE_GENERATOR}") + endif() +endif() -- GitLab From 266a755938e98a8efadd3bbde03e6cc9a6b2140b Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 15 Mar 2020 13:45:47 -0600 Subject: [PATCH 283/689] CheckIfNinjaSupportsFortran.cmake -> CheckGeneratorSupport.cmake --- cmake/CMakeLists.txt | 4 ++-- ...NinjaSupportsFortran.cmake => CheckGeneratorSupport.cmake} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename cmake/Modules/{CheckIfNinjaSupportsFortran.cmake => CheckGeneratorSupport.cmake} (100%) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 2fbc17dcf4..3f3da81b68 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -255,7 +255,7 @@ if(PKG_MSCG OR PKG_USER-ATC OR PKG_USER-AWPMD OR PKG_USER-QUIP OR PKG_LATTE) find_package(LAPACK) find_package(BLAS) if(NOT LAPACK_FOUND OR NOT BLAS_FOUND) - include(CheckIfNinjaSupportsFortran) + include(CheckGeneratorSupport) if(NOT CMAKE_GENERATOR_SUPPORT_FORTRAN) status(FATAL_ERROR "Cannot build internal linear algebra library as CMake build tool lacks Fortran support") endif() @@ -588,7 +588,7 @@ if(BUILD_TOOLS) add_executable(binary2txt ${LAMMPS_TOOLS_DIR}/binary2txt.cpp) install(TARGETS binary2txt DESTINATION ${CMAKE_INSTALL_BINDIR}) - include(CheckIfNinjaSupportsFortran) + include(CheckGeneratorSupport) if(CMAKE_GENERATOR_SUPPORT_FORTRAN) enable_language(Fortran) add_executable(chain.x ${LAMMPS_TOOLS_DIR}/chain.f) diff --git a/cmake/Modules/CheckIfNinjaSupportsFortran.cmake b/cmake/Modules/CheckGeneratorSupport.cmake similarity index 100% rename from cmake/Modules/CheckIfNinjaSupportsFortran.cmake rename to cmake/Modules/CheckGeneratorSupport.cmake -- GitLab From f536451968f425c373d771f0d68498bd8e28b2d3 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 15 Mar 2020 13:46:11 -0600 Subject: [PATCH 284/689] cmake: add generator to summary --- cmake/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 3f3da81b68..16d18eb33c 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -687,6 +687,7 @@ feature_summary(DESCRIPTION "The following tools and libraries have been found a message(STATUS "<<< Build configuration >>> Build type ${CMAKE_BUILD_TYPE} Install path ${CMAKE_INSTALL_PREFIX} + Generator ${CMAKE_GENERATOR} using ${CMAKE_MAKE_PROGRAM} Compilers and Flags: C++ Compiler ${CMAKE_CXX_COMPILER} Type ${CMAKE_CXX_COMPILER_ID} -- GitLab From 0b6ab1d15a143b3a6ca96c2a7c66ee18e64aa0e6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 15 Mar 2020 17:47:30 -0400 Subject: [PATCH 285/689] need to forward some (more) cmake settings to external projects. simplify KIM handling of fortran support. --- cmake/Modules/Packages/KIM.cmake | 10 ++++------ cmake/Modules/Packages/LATTE.cmake | 1 + cmake/Modules/Packages/MSCG.cmake | 8 +++++++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/cmake/Modules/Packages/KIM.cmake b/cmake/Modules/Packages/KIM.cmake index cbb6aa22c9..bb68f8fef4 100644 --- a/cmake/Modules/Packages/KIM.cmake +++ b/cmake/Modules/Packages/KIM.cmake @@ -35,22 +35,20 @@ if(PKG_KIM) option(DOWNLOAD_KIM "Download KIM-API from OpenKIM instead of using an already installed one" ${DOWNLOAD_KIM_DEFAULT}) if(DOWNLOAD_KIM) message(STATUS "KIM-API download requested - we will build our own") - include(CheckLanguage) include(ExternalProject) enable_language(C) - check_language(Fortran) - if(NOT CMAKE_Fortran_COMPILER) - message(FATAL_ERROR "Compiling the KIM-API library requires a Fortran compiler") - endif() + enable_language(Fortran) ExternalProject_Add(kim_build URL https://s3.openkim.org/kim-api/kim-api-2.1.3.txz URL_MD5 6ee829a1bbba5f8b9874c88c4c4ebff8 BINARY_DIR build - CMAKE_ARGS -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} + CMAKE_ARGS ${CMAKE_REQUEST_PIC} + -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_Fortran_COMPILER=${CMAKE_Fortran_COMPILER} -DCMAKE_INSTALL_PREFIX= -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM} BUILD_BYPRODUCTS /${CMAKE_INSTALL_LIBDIR}/libkim-api${CMAKE_SHARED_LIBRARY_SUFFIX} ) ExternalProject_get_property(kim_build INSTALL_DIR) diff --git a/cmake/Modules/Packages/LATTE.cmake b/cmake/Modules/Packages/LATTE.cmake index 7244cb151f..bc89b00111 100644 --- a/cmake/Modules/Packages/LATTE.cmake +++ b/cmake/Modules/Packages/LATTE.cmake @@ -18,6 +18,7 @@ if(PKG_LATTE) -DBLAS_LIBRARIES=${BLAS_LIBRARIES} -DLAPACK_LIBRARIES=${LAPACK_LIBRARIES} -DCMAKE_Fortran_COMPILER=${CMAKE_Fortran_COMPILER} -DCMAKE_Fortran_FLAGS=${CMAKE_Fortran_FLAGS} -DCMAKE_Fortran_FLAGS_${BTYPE}=${CMAKE_Fortran_FLAGS_${BTYPE}} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM} BUILD_BYPRODUCTS /${CMAKE_INSTALL_LIBDIR}/liblatte.a ) ExternalProject_get_property(latte_build INSTALL_DIR) diff --git a/cmake/Modules/Packages/MSCG.cmake b/cmake/Modules/Packages/MSCG.cmake index 67db9ab251..3f27ef8bb0 100644 --- a/cmake/Modules/Packages/MSCG.cmake +++ b/cmake/Modules/Packages/MSCG.cmake @@ -16,7 +16,13 @@ if(PKG_MSCG) URL https://github.com/uchicago-voth/MSCG-release/archive/1.7.3.1.tar.gz URL_MD5 8c45e269ee13f60b303edd7823866a91 SOURCE_SUBDIR src/CMake - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX= ${CMAKE_REQUEST_PIC} ${EXTRA_MSCG_OPTS} + CMAKE_ARGS ${CMAKE_REQUEST_PIC} ${EXTRA_MSCG_OPTS} + -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} + -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} + -DCMAKE_Fortran_COMPILER=${CMAKE_Fortran_COMPILER} + -DCMAKE_INSTALL_PREFIX= + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM} BUILD_COMMAND make mscg INSTALL_COMMAND "" BUILD_BYPRODUCTS /libmscg.a ) -- GitLab From d25b73f76d84439b94961deaccfb00bc91b2e925 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 15 Mar 2020 18:36:57 -0400 Subject: [PATCH 286/689] also report fortran MPI libs, if configured --- cmake/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 16d18eb33c..9b3992da84 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -720,7 +720,7 @@ else() endif() message(STATUS "Link libraries: ${LAMMPS_LINK_LIBS}") if(BUILD_MPI) - message(STATUS "Using MPI with headers in ${MPI_CXX_INCLUDE_PATH} and ${MPI_CXX_LIBRARIES}") + message(STATUS "Using MPI with headers in ${MPI_CXX_INCLUDE_PATH} and these libraries: ${MPI_CXX_LIBRARIES};${MPI_Fortran_LIBRARIES}") endif() if(PKG_GPU) message(STATUS "GPU API: ${GPU_API}") -- GitLab From a4335904b67a6bd08ed8e1b25855cd5359252903 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 15 Mar 2020 18:37:39 -0400 Subject: [PATCH 287/689] need to recheck for MPI after enabling fortran to have MPI_Fortran_LIBRARIES set --- cmake/Modules/Packages/USER-SCAFACOS.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/Modules/Packages/USER-SCAFACOS.cmake b/cmake/Modules/Packages/USER-SCAFACOS.cmake index e8f14eb403..8bb9e63605 100644 --- a/cmake/Modules/Packages/USER-SCAFACOS.cmake +++ b/cmake/Modules/Packages/USER-SCAFACOS.cmake @@ -4,6 +4,7 @@ if(PKG_USER-SCAFACOS) find_package(GSL REQUIRED) find_package(PkgConfig QUIET) + find_package(MPI REQUIRED) set(DOWNLOAD_SCAFACOS_DEFAULT ON) if(PKG_CONFIG_FOUND) pkg_check_modules(SCAFACOS QUIET scafacos) -- GitLab From c0b39e654f4b84ff93dbae81c4897262e693413c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 15 Mar 2020 19:07:26 -0400 Subject: [PATCH 288/689] make MSCG library build compatible with using ninja --- cmake/Modules/Packages/MSCG.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Modules/Packages/MSCG.cmake b/cmake/Modules/Packages/MSCG.cmake index 3f27ef8bb0..8cbcf303d5 100644 --- a/cmake/Modules/Packages/MSCG.cmake +++ b/cmake/Modules/Packages/MSCG.cmake @@ -23,7 +23,7 @@ if(PKG_MSCG) -DCMAKE_INSTALL_PREFIX= -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM} - BUILD_COMMAND make mscg INSTALL_COMMAND "" + BUILD_COMMAND ${CMAKE_MAKE_PROGRAM} libmscg.a INSTALL_COMMAND "" BUILD_BYPRODUCTS /libmscg.a ) ExternalProject_get_property(mscg_build BINARY_DIR) -- GitLab From 0b293080c9be846ddc1a7898861d36278e8770d0 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 15 Mar 2020 19:51:04 -0600 Subject: [PATCH 289/689] MSCG.cmake: fix build (hopefully) --- cmake/Modules/Packages/MSCG.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/Modules/Packages/MSCG.cmake b/cmake/Modules/Packages/MSCG.cmake index 8cbcf303d5..b1cc6fad46 100644 --- a/cmake/Modules/Packages/MSCG.cmake +++ b/cmake/Modules/Packages/MSCG.cmake @@ -23,7 +23,8 @@ if(PKG_MSCG) -DCMAKE_INSTALL_PREFIX= -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM} - BUILD_COMMAND ${CMAKE_MAKE_PROGRAM} libmscg.a INSTALL_COMMAND "" + BUILD_COMMAND ${CMAKE_COMMAND} --build . --target mscg + INSTALL_COMMAND "" BUILD_BYPRODUCTS /libmscg.a ) ExternalProject_get_property(mscg_build BINARY_DIR) -- GitLab From 4cdb904e54bba747231481e78bb44ef45196698f Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 14 Mar 2020 08:38:14 -0400 Subject: [PATCH 290/689] next chunk of converted html files --- doc/src/Howto_viz.rst | 4 +- doc/src/atc_electron_integration.rst | 2 +- doc/src/atc_equilibrium_start.rst | 44 +++++++++++++++ doc/src/atc_extrinsic_exchange.rst | 45 ++++++++++++++++ doc/src/atc_filter_scale.rst | 44 +++++++++++++++ doc/src/atc_filter_type.rst | 43 +++++++++++++++ doc/src/atc_lumped_lambda_solve.rst | 41 ++++++++++++++ doc/src/atc_mask_direction.rst | 38 +++++++++++++ doc/src/atc_output.rst | 59 +++++++++++++++++++++ doc/src/atc_poisson_solver.rst | 45 ++++++++++++++++ doc/src/atc_time_filter.rst | 46 ++++++++++++++++ doc/src/fix_atc.rst | 18 +++---- doc/utils/sphinx-config/false_positives.txt | 3 ++ 13 files changed, 420 insertions(+), 12 deletions(-) create mode 100644 doc/src/atc_equilibrium_start.rst create mode 100644 doc/src/atc_extrinsic_exchange.rst create mode 100644 doc/src/atc_filter_scale.rst create mode 100644 doc/src/atc_filter_type.rst create mode 100644 doc/src/atc_lumped_lambda_solve.rst create mode 100644 doc/src/atc_mask_direction.rst create mode 100644 doc/src/atc_output.rst create mode 100644 doc/src/atc_poisson_solver.rst create mode 100644 doc/src/atc_time_filter.rst diff --git a/doc/src/Howto_viz.rst b/doc/src/Howto_viz.rst index 0ffdf08331..2eb009c185 100644 --- a/doc/src/Howto_viz.rst +++ b/doc/src/Howto_viz.rst @@ -19,7 +19,7 @@ A Python-based toolkit distributed by our group can read native LAMMPS dump files, including custom dump files with additional columns of user-specified atom information, and convert them to various formats or pipe them into visualization software directly. See the `Pizza.py WWW site `_ for details. Specifically, Pizza.py can convert -LAMMPS dump files into PDB, XYZ, `Ensight `_, and VTK formats. +LAMMPS dump files into PDB, XYZ, `EnSight `_, and VTK formats. Pizza.py can pipe LAMMPS dump files directly into the Raster3d and RasMol visualization programs. Pizza.py has tools that do interactive 3d OpenGL visualization and one that creates SVG images of dump file @@ -27,6 +27,6 @@ snapshots. .. _pizza: https://pizza.sandia.gov -.. _ensight: https://daac.hpc.mil/software/EnSight/ +.. _ensight: https://www.ansys.com/products/fluids/ansys-ensight .. _atomeye: http://li.mit.edu/Archive/Graphics/A/ diff --git a/doc/src/atc_electron_integration.rst b/doc/src/atc_electron_integration.rst index e3928a69fb..2f3fd9eee2 100644 --- a/doc/src/atc_electron_integration.rst +++ b/doc/src/atc_electron_integration.rst @@ -12,7 +12,7 @@ Syntax * AtC fixID = ID of :doc:`fix atc ` instance * extrinsic electron_integration = name of the AtC sub-command -* integration_type = *explicit* or *implicit* or *steadydescriptor* +* integration_type = *explicit* or *implicit* or *steady* * num_subcycle_steps = number of subcycle steps for the electron time integration (optional) diff --git a/doc/src/atc_equilibrium_start.rst b/doc/src/atc_equilibrium_start.rst new file mode 100644 index 0000000000..0068dc02c3 --- /dev/null +++ b/doc/src/atc_equilibrium_start.rst @@ -0,0 +1,44 @@ +.. index:: fix_modify AtC equilibrium_start + +fix_modify AtC equilibrium_start command +======================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify equilibrium_start + +* AtC fixID = ID of :doc:`fix atc ` instance +* equilibrium_start = name of the AtC sub-command +* *exponential* or *step* or *no_filter* = select type of filter + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC equilibrium_start on + +Description +""""""""""" + +Starts filtered calculations assuming they start in equilibrium, +i.e. perfect finite element force balance. + +Restrictions +"""""""""""" + +Only for use with these specific transfers: thermal, two_temperature + +Related AtC commands +"""""""""""""""""""" +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC filter ` +- :doc:`fix_modify AtC filter scale ` + +Default +""""""" + +None. diff --git a/doc/src/atc_extrinsic_exchange.rst b/doc/src/atc_extrinsic_exchange.rst new file mode 100644 index 0000000000..03d794115b --- /dev/null +++ b/doc/src/atc_extrinsic_exchange.rst @@ -0,0 +1,45 @@ +.. index:: fix_modify AtC extrinsic exchange + +fix_modify AtC extrinsic exchange command +========================================= + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify extrinsic exchange + +* AtC fixID = ID of :doc:`fix atc ` instance +* extrinsic exchange = name of the AtC sub-command +* *on* or *off* = set state of energy exchange + + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC extrinsic exchange on + +Description +""""""""""" + +Switches energy exchange between the MD system and the electron system +on or off + +Restrictions +"""""""""""" + +For use only with the two_temperature type of the AtC fix (see +:doc:`fix atc ` command) + +Related AtC commands +"""""""""""""""""""" + +- :ref:`fix_modify AtC command overview ` + +Default +""""""" + +*on* diff --git a/doc/src/atc_filter_scale.rst b/doc/src/atc_filter_scale.rst new file mode 100644 index 0000000000..ce62a589eb --- /dev/null +++ b/doc/src/atc_filter_scale.rst @@ -0,0 +1,44 @@ +.. index:: fix_modify AtC filter scale + +fix_modify AtC filter scale command +=================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify filter scale + +* AtC fixID = ID of :doc:`fix atc ` instance +* filter scale = name of the AtC sub-command +* scale = characteristic times scale of the filter + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC filter scale 10.0 + +Description +""""""""""" + +Sets the time scale for MD dynamics filter to construct a more +appropriate continuous field. + +Restrictions +"""""""""""" + +Only for use with these specific transfers: thermal, two_temperature + +Related AtC commands +"""""""""""""""""""" +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC filter ` +- :doc:`fix_modify AtC filter type ` + +Default +""""""" + +0.0 diff --git a/doc/src/atc_filter_type.rst b/doc/src/atc_filter_type.rst new file mode 100644 index 0000000000..5e2da80755 --- /dev/null +++ b/doc/src/atc_filter_type.rst @@ -0,0 +1,43 @@ +.. index:: fix_modify AtC filter type + +fix_modify AtC filter type command +=================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify filter type + +* AtC fixID = ID of :doc:`fix atc ` instance +* filter type = name of the AtC sub-command +* *exponential* or *step* or *no_filter* = select type of filter + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC filter type exponential + +Description +""""""""""" + +Specifies the type of time filter used. + +Restrictions +"""""""""""" + +Only for use with these specific transfers: thermal, two_temperature + +Related AtC commands +"""""""""""""""""""" +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC filter ` +- :doc:`fix_modify AtC filter scale ` + +Default +""""""" + +None. diff --git a/doc/src/atc_lumped_lambda_solve.rst b/doc/src/atc_lumped_lambda_solve.rst new file mode 100644 index 0000000000..e777116da5 --- /dev/null +++ b/doc/src/atc_lumped_lambda_solve.rst @@ -0,0 +1,41 @@ +.. index:: fix_modify AtC control lumped_lambda_solve + +fix_modify AtC control lumped_lambda_solve command +================================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify control lumped_lambda_solve + +* AtC fixID = ID of :doc:`fix atc ` instance +* control lumped_lambda_solve = name of the AtC sub-command +* *on* or *off* = Toggles state of lumped matrix + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC control lumped_lambda_solve on + +Description +""""""""""" + +Command select whether to use or not use lumped matrix for lambda solve. + +Restrictions +"""""""""""" + +None. + +Related AtC commands +"""""""""""""""""""" +- :ref:`fix_modify AtC command overview ` + +Default +""""""" + +off diff --git a/doc/src/atc_mask_direction.rst b/doc/src/atc_mask_direction.rst new file mode 100644 index 0000000000..ed5c605834 --- /dev/null +++ b/doc/src/atc_mask_direction.rst @@ -0,0 +1,38 @@ +.. index:: fix_modify AtC control mask_direction + +fix_modify AtC control mask_direction command +============================================= + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify control mask_direction + +* AtC fixID = ID of :doc:`fix atc ` instance +* control mask_direction = name of the AtC sub-command +* direction = select direction +* *on* or *off* = Toggles state + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC control mask_direction 0 on + +Description +""""""""""" + +Command to mask out certain dimensions from the atomic regulator + +Restrictions +"""""""""""" + +None. + +Related AtC commands +"""""""""""""""""""" +- :ref:`fix_modify AtC command overview ` + diff --git a/doc/src/atc_output.rst b/doc/src/atc_output.rst new file mode 100644 index 0000000000..699449b981 --- /dev/null +++ b/doc/src/atc_output.rst @@ -0,0 +1,59 @@ +.. index:: fix_modify AtC output + +fix_modify AtC output command +============================= + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify output [text|full_text|binary|vector_components|tensor_components] + fix_modify output index [step|time] + +* AtC fixID = ID of :doc:`fix atc ` instance +* *output* or *output index* = name of the AtC sub-command +* filename_prefix = prefix for data files (for *output*) +* frequency = frequency of output in time-steps (for *output*) +* optional keywords for *output*: + - text = creates text output of index, step and nodal variable values for unique nodes + - full_text = creates text output index, nodal id, step, nodal coordinates and nodal variable values for unique and image nodes + - binary = creates binary EnSight output + - vector_components = outputs vectors as scalar components + - tensor_components = outputs tensor as scalar components (for use with ParaView) +* *step* or *time* = index output by step or by time (for *output index*) + + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC output heatFE 100 + fix_modify AtC output hardyFE 1 text tensor_components + fix_modify AtC output hardyFE 10 text binary tensor_components + fix_modify AtC output index step + + +Description +""""""""""" + +Creates text and/or binary (EnSight, "gold" format) output of nodal/mesh +data which is transfer/physics specific. Output indexing by step or time +is possible. + +Restrictions +"""""""""""" + +None. + +Related AtC commands +"""""""""""""""""""" + +- :ref:`fix_modify AtC command overview ` +- :doc:`fix atc command ` + +Default +""""""" + +No default format. Output indexed by time. diff --git a/doc/src/atc_poisson_solver.rst b/doc/src/atc_poisson_solver.rst new file mode 100644 index 0000000000..d37f214b97 --- /dev/null +++ b/doc/src/atc_poisson_solver.rst @@ -0,0 +1,45 @@ +.. index:: fix_modify AtC poisson_solver + +fix_modify AtC poisson_solver command +===================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify poisson_solver mesh create + +* AtC fixID = ID of :doc:`fix atc ` instance +* poisson_solver = name of the AtC sub-command +* *nx* *ny* *nz* = number of elements in x, y, and z +* region-id = id of region to be meshed +* *f* or *p* = periodicity flags for x, y, and z + + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC poisson_solver mesh create 10 1 1 feRegion p p p + +Description +""""""""""" + +Creates a uniform mesh in a rectangular region. + +Restrictions +"""""""""""" + +Creates only uniform rectangular grids in rectangular regions. + +Related AtC commands +"""""""""""""""""""" + +- :ref:`fix_modify AtC command overview ` + +Default +""""""" + +None. diff --git a/doc/src/atc_time_filter.rst b/doc/src/atc_time_filter.rst new file mode 100644 index 0000000000..0a97c83259 --- /dev/null +++ b/doc/src/atc_time_filter.rst @@ -0,0 +1,46 @@ +.. index:: fix_modify AtC filter + +fix_modify AtC filter command +============================= + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify filter + +* AtC fixID = ID of :doc:`fix atc ` instance +* filter = name of the AtC sub-command +* *on* or *off* or *equilibrate* = Select state of filter + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC filter on + +Description +""""""""""" + +Filters the MD dynamics to construct a more appropriate continuous +field. Equilibrating first filters the time derivatives without changing +the dynamics to provide a better initial condition to the filtered +dynamics. + +Restrictions +"""""""""""" + +Only for use with these specific transfers: thermal, two_temperature + +Related AtC commands +"""""""""""""""""""" +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC filter scale ` +- :doc:`fix_modify AtC equilibrium_start ` + +Default +""""""" + +off diff --git a/doc/src/fix_atc.rst b/doc/src/fix_atc.rst index b2d1da9317..479adba548 100644 --- a/doc/src/fix_atc.rst +++ b/doc/src/fix_atc.rst @@ -184,18 +184,18 @@ conditions. * :doc:`fix_modify AtC control thermal ` * :doc:`fix_modify AtC control momentum ` * :doc:`fix_modify AtC control localized_lambda ` -* `fix_modify AtC control lumped_lambda_solve `_ -* `fix_modify AtC control mask_direction `_ control -* `fix_modify AtC filter `_ -* `fix_modify AtC filter scale `_ -* `fix_modify AtC filter type `_ -* `fix_modify AtC equilibrium_start `_ -* `fix_modify AtC extrinsic exchange `_ -* `fix_modify AtC poisson_solver `_ +* :doc:`fix_modify AtC control lumped_lambda_solve ` +* :doc:`fix_modify AtC control mask_direction ` +* :doc:`fix_modify AtC filter ` +* :doc:`fix_modify AtC filter scale ` +* :doc:`fix_modify AtC filter type ` +* :doc:`fix_modify AtC equilibrium_start ` +* :doc:`fix_modify AtC extrinsic exchange ` +* :doc:`fix_modify AtC poisson_solver ` *fix_modify* commands for output: -* `fix_modify AtC output `_ +* :doc:`fix_modify AtC output ` * `fix_modify AtC output nodeset `_ * `fix_modify AtC output elementset `_ * `fix_modify AtC output boundary_integral `_ diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index 0685c3582b..0837fbee9e 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -772,6 +772,7 @@ engrot engtrans engvib enobonds +EnSight enthalpy enums envoke @@ -2164,6 +2165,7 @@ parameterizations parameterize parameterized params +ParaView parmin Parrinello Partay @@ -2255,6 +2257,7 @@ pN png Podhorszki Poiseuille +poisson Polak polarizabilities polarizability -- GitLab From 05b273d73176a11bfb3911cb0b00e99ad33b43e2 Mon Sep 17 00:00:00 2001 From: Yaser Afshar Date: Mon, 16 Mar 2020 08:11:58 -0500 Subject: [PATCH 291/689] kim_property command A new KIM command to make it as easy as possible to write material properties computed in LAMMPS to standard KIM property instance format. --- src/KIM/kim_property.cpp | 489 +++++++++++++++++++++++++++++++++++++++ src/KIM/kim_property.h | 85 +++++++ 2 files changed, 574 insertions(+) create mode 100644 src/KIM/kim_property.cpp create mode 100644 src/KIM/kim_property.h diff --git a/src/KIM/kim_property.cpp b/src/KIM/kim_property.cpp new file mode 100644 index 0000000000..888aa4da0c --- /dev/null +++ b/src/KIM/kim_property.cpp @@ -0,0 +1,489 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Yaser Afshar (UMN) +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, see . + + Linking LAMMPS statically or dynamically with other modules is making a + combined work based on LAMMPS. Thus, the terms and conditions of the GNU + General Public License cover the whole combination. + + In addition, as a special exception, the copyright holders of LAMMPS give + you permission to combine LAMMPS with free software programs or libraries + that are released under the GNU LGPL and with code included in the standard + release of the "kim-api" under the CDDL (or modified versions of such code, + with unchanged license). You may copy and distribute such a system following + the terms of the GNU GPL for LAMMPS and the licenses of the other code + concerned, provided that you include the source code of that other code + when and as the GNU GPL requires distribution of source code. + + Note that people who make modified versions of LAMMPS are not obligated to + grant this special exception for their modified versions; it is their choice + whether to do so. The GNU General Public License gives permission to release + a modified version without this exception; this exception also makes it + possible to release a modified version which carries forward this exception. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Designed for use with the kim-api-2.1.0 (and newer) package +------------------------------------------------------------------------- */ + +#if LMP_PYTHON +#define PY_SSIZE_T_CLEAN +#include +#endif + +#include "kim_property.h" + +#include "comm.h" +#include "input.h" +#include "variable.h" +#include "utils.h" +#include "error.h" + +#include + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +kimProperty::kimProperty(LAMMPS *lmp) : Pointers(lmp) +{ +#if LMP_PYTHON +#if PY_MAJOR_VERSION != 3 + error->all(FLERR, "Invalid Python version.\n" + "The kim-property Python package requires Python " + "3 >= 3.6 support."); +#endif + // one-time initialization of Python interpreter + if (!Py_IsInitialized()) { + Py_Initialize(); + PyEval_InitThreads(); + } +#else + error->all(FLERR, "Error Python support missing! Compile with PYTHON " + "package installed!"); +#endif // LMP_PYTHON +} + +void kimProperty::command(int narg, char **arg) +{ +#if LMP_PYTHON +#if PY_MAJOR_VERSION == 3 + if (narg < 2) + error->all(FLERR, "Invalid `kim_property` command."); + + if (!(strcmp(arg[0], "create") == 0) && + !(strcmp(arg[0], "destroy") == 0) && + !(strcmp(arg[0], "modify") == 0) && + !(strcmp(arg[0], "remove") == 0) && + !(strcmp(arg[0], "dump") == 0)) { + std::string msg("Error incorrect arguments in kim_property command.\n"); + msg += "`kim_property create/destroy/modify/remove/dump` "; + msg += "is mandatory."; + error->all(FLERR, msg.c_str()); + } + + if (comm->me == 0) { + std::string msg; + msg = "#=== kim-property ===========================================\n"; + input->write_echo(msg.c_str()); + } + + // Get the kim_str ptr to the data associated with a kim_property_str + // variable + char *kim_str = + input->variable->retrieve(const_cast("kim_property_str")); + + char **kim_str_cmd = new char *[3]; + kim_str_cmd[0] = const_cast("kim_property_str"); + + PyGILState_STATE gstate = PyGILState_Ensure(); + + // kim_property module + PyObject *kim_property = NULL; + + // import kim_property + { + PyObject *obj = PyUnicode_FromString("kim_property"); + if (!obj) { + PyGILState_Release(gstate); + error->all(FLERR, "Error creating a `PyObject`!"); + } + + kim_property = PyImport_Import(obj); + if (!kim_property) { + PyGILState_Release(gstate); + error->all(FLERR, "Error unable to import Python `kim_property` module!" + "\nkim-property Python package can be installed " + "with pip:\n`pip install kim-property`\n" + "See the installation instructions at\n" + "https://github.com/openkim/kim-property#installing-kim-property\n") + "for detailed information."); + } + + // Decrementing of the reference count + Py_XDECREF(obj); + } + + // kim_property create 1 cohesive-potential-energy-cubic-crystal + if (strcmp(arg[0], "create") == 0) { + if (narg != 3) { + PyGILState_Release(gstate); + error->all(FLERR, "Error invalid `kim_property create` command."); + } + + int const ID = utils::inumeric(FLERR, arg[1], true, lmp); + + Py_ssize_t const nSize = (kim_str ? 3 : 2); + + // Python function + // This is the equivalent of the Python expression: + // kim_property.kim_property_create. + PyObject *pFunc = + PyObject_GetAttrString(kim_property, "kim_property_create"); + if (!pFunc) { + PyGILState_Release(gstate); + error->all(FLERR, "Error unable to get an attribute named " + "`kim_property_create` from a kim_property object!"); + } + + // Decrementing of the reference count + Py_XDECREF(kim_property); + + // create Python tuple of input arguments + PyObject *pArgs = PyTuple_New(nSize); + if (!pArgs) { + PyGILState_Release(gstate); + error->all(FLERR, "Error could not create Python function arguments."); + } + + // Python object to set the tuple + // Property ID + PyObject *pValue = PyLong_FromLong(ID); + PyTuple_SetItem(pArgs, 0, pValue); + + // Property name + pValue = PyUnicode_FromString(arg[2]); + PyTuple_SetItem(pArgs, 1, pValue); + + if (nSize == 3) { + pValue = PyUnicode_FromString(kim_str); + PyTuple_SetItem(pArgs, 2, pValue); + } + + // call the Python kim_property_create function + // error check with one() since only some procs may fail + pValue = PyObject_CallObject(pFunc, pArgs); + if (!pValue) { + PyErr_Print(); + PyGILState_Release(gstate); + error->one(FLERR, "Error Python `kim_property_create` function " + "evaluation failed!"); + } + + // Python function returned a string value + const char *pystr = PyUnicode_AsUTF8(pValue); + + kim_str_cmd[2] = const_cast(pystr); + + if (kim_str) { + input->variable->set_string(kim_str_cmd[0], kim_str_cmd[2]); + } else { + kim_str_cmd[1] = const_cast("string"); + input->variable->set(3, kim_str_cmd); + } + + Py_XDECREF(pArgs); + Py_XDECREF(pFunc); + Py_XDECREF(pValue); + } + else if (strcmp(arg[0], "destroy") == 0) { + if (narg != 2) { + PyGILState_Release(gstate); + error->all(FLERR, "Error invalid `kim_property destroy` command."); + } + + if (!kim_str) { + PyGILState_Release(gstate); + return; + } + + int const ID = utils::inumeric(FLERR, arg[1], true, lmp); + + // Python function + // This is the equivalent of the Python expression kim_property.kim_property_destroy + PyObject *pFunc = + PyObject_GetAttrString(kim_property, "kim_property_destroy"); + if (!pFunc) { + PyGILState_Release(gstate); + error->all(FLERR, "Error unable to get an attribute named " + "`kim_property_destroy` from a kim_property object!"); + } + + // Decrementing of the reference count + Py_XDECREF(kim_property); + + // create Python tuple of input arguments + PyObject *pArgs = PyTuple_New(2); + if (!pArgs) { + PyGILState_Release(gstate); + error->all(FLERR, "Error could not create Python function arguments."); + } + + // Python object to set the tuple + PyObject *pValue = PyUnicode_FromString(kim_str); + PyTuple_SetItem(pArgs, 0, pValue); + + pValue = PyLong_FromLong(ID); + PyTuple_SetItem(pArgs, 1, pValue); + + // call the Python kim_property_destroy function + // error check with one() since only some procs may fail + pValue = PyObject_CallObject(pFunc, pArgs); + if (!pValue) { + PyErr_Print(); + PyGILState_Release(gstate); + error->one(FLERR, "Error Python `kim_property_destroy` function " + "evaluation failed!"); + } + + // Python function returned a string value + const char *pystr = PyUnicode_AsUTF8(pValue); + + kim_str_cmd[2] = const_cast(pystr); + + input->variable->set_string(kim_str_cmd[0], kim_str_cmd[2]); + + Py_XDECREF(pArgs); + Py_XDECREF(pFunc); + Py_XDECREF(pValue); + } + else if (strcmp(arg[0], "modify") == 0) { + if (narg < 6) { + PyGILState_Release(gstate); + error->all(FLERR, "Error invalid `kim_property modify` command."); + } + + if (!kim_str) { + PyGILState_Release(gstate); + error->all(FLERR, "Error There is no property instance to modify " + "the content."); + } + + int const ID = utils::inumeric(FLERR, arg[1], true, lmp); + + // Python function + // This is the equivalent of the Python expression + // kim_property.kim_property_modify + PyObject *pFunc = + PyObject_GetAttrString(kim_property, "kim_property_modify"); + if (!pFunc) { + PyGILState_Release(gstate); + error->all(FLERR, "Error unable to get an attribute named " + "`kim_property_modify` from a kim_property object!"); + } + + // Decrementing of the reference count + Py_XDECREF(kim_property); + + // create Python tuple of input arguments + PyObject *pArgs = PyTuple_New(static_cast(narg)); + if (!pArgs) { + PyGILState_Release(gstate); + error->all(FLERR, "Error could not create Python function arguments."); + } + + // Python object to set the tuple + PyObject *pValue = PyUnicode_FromString(kim_str); + PyTuple_SetItem(pArgs, 0, pValue); + + pValue = PyLong_FromLong(ID); + PyTuple_SetItem(pArgs, 1, pValue); + + for (Py_ssize_t i = 2; i < static_cast(narg); ++i) { + pValue = PyUnicode_FromString(arg[i]); + PyTuple_SetItem(pArgs, i, pValue); + } + + // call the Python kim_property_modify function + // error check with one() since only some procs may fail + pValue = PyObject_CallObject(pFunc, pArgs); + if (!pValue) { + PyErr_Print(); + PyGILState_Release(gstate); + error->one(FLERR, "Error Python `kim_property_modify` function " + "evaluation failed!"); + } + + // Python function returned a string value + const char *pystr = PyUnicode_AsUTF8(pValue); + + kim_str_cmd[2] = const_cast(pystr); + + input->variable->set_string(kim_str_cmd[0], kim_str_cmd[2]); + + Py_XDECREF(pArgs); + Py_XDECREF(pFunc); + Py_XDECREF(pValue); + } + else if (strcmp(arg[0], "remove") == 0) { + if (narg < 4) { + PyGILState_Release(gstate); + error->all(FLERR, "Error invalid `kim_property remove` command."); + } + + if (!kim_str) { + PyGILState_Release(gstate); + error->all(FLERR, "Error There is no property instance to remove " + "the content."); + } + + int const ID = utils::inumeric(FLERR, arg[1], true, lmp); + + // Python function + // This is the equivalent of the Python expression + // kim_property.kim_property_remove + PyObject *pFunc = + PyObject_GetAttrString(kim_property, "kim_property_remove"); + if (!pFunc) { + PyGILState_Release(gstate); + error->all(FLERR, "Error unable to get an attribute named " + "`kim_property_remove` from a kim_property object!"); + } + + // Decrementing of the reference count + Py_XDECREF(kim_property); + + // create Python tuple of input arguments + PyObject *pArgs = PyTuple_New(static_cast(narg)); + if (!pArgs) { + PyGILState_Release(gstate); + error->all(FLERR, "Error could not create Python function arguments."); + } + + // Python object to set the tuple + PyObject *pValue = PyUnicode_FromString(kim_str); + PyTuple_SetItem(pArgs, 0, pValue); + + pValue = PyLong_FromLong(ID); + PyTuple_SetItem(pArgs, 1, pValue); + + for (Py_ssize_t i = 2; i < static_cast(narg); ++i) { + pValue = PyUnicode_FromString(arg[i]); + PyTuple_SetItem(pArgs, i, pValue); + } + + // call the Python kim_property_remove function + // error check with one() since only some procs may fail + pValue = PyObject_CallObject(pFunc, pArgs); + if (!pValue) { + PyErr_Print(); + PyGILState_Release(gstate); + error->one(FLERR, "Error Python `kim_property_remove` function " + "evaluation failed!"); + } + + // Python function returned a string value + const char *pystr = PyUnicode_AsUTF8(pValue); + + kim_str_cmd[2] = const_cast(pystr); + + input->variable->set_string(kim_str_cmd[0], kim_str_cmd[2]); + + Py_XDECREF(pArgs); + Py_XDECREF(pFunc); + Py_XDECREF(pValue); + } + else if (strcmp(arg[0], "dump") == 0) { + if (narg != 2) { + PyGILState_Release(gstate); + error->all(FLERR, "Error invalid `kim_property dump` command."); + } + + if (!kim_str) { + PyGILState_Release(gstate); + error->all(FLERR, "Error There is no property instance to dump " + "the content."); + } + + // Python function + // This is the equivalent of the Python expression + // kim_property.kim_property_dump + PyObject *pFunc = + PyObject_GetAttrString(kim_property, "kim_property_dump"); + if (!pFunc) { + PyGILState_Release(gstate); + error->all(FLERR, "Error unable to get an attribute named " + "`kim_property_dump` from a kim_property object!"); + } + + // Decrementing of the reference count + Py_XDECREF(kim_property); + + // create Python tuple of input arguments + PyObject *pArgs = PyTuple_New(2); + if (!pArgs) { + PyGILState_Release(gstate); + error->all(FLERR, "Could not create Python function arguments."); + } + + // Python object to set the tuple + PyObject *pValue = PyUnicode_FromString(kim_str); + PyTuple_SetItem(pArgs, 0, pValue); + + pValue = PyUnicode_FromString(arg[1]); + PyTuple_SetItem(pArgs, 1, pValue); + + if (comm->me == 0) { + // call the Python kim_property_dump function + // error check with one() since only some procs may fail + pValue = PyObject_CallObject(pFunc, pArgs); + if (!pValue) { + PyErr_Print(); + PyGILState_Release(gstate); + error->one(FLERR, "Error Python `kim_property_dump` function " + "evaluation failed!"); + } + } + + // Destroy the variable + kim_str_cmd[1] = const_cast("delete"); + input->variable->set(2, kim_str_cmd); + + Py_XDECREF(pArgs); + Py_XDECREF(pFunc); + Py_XDECREF(pValue); + } + + PyGILState_Release(gstate); + + delete[] kim_str_cmd; +#endif // PY_MAJOR_VERSION +#endif // LMP_PYTHON +} diff --git a/src/KIM/kim_property.h b/src/KIM/kim_property.h new file mode 100644 index 0000000000..ff5faa6781 --- /dev/null +++ b/src/KIM/kim_property.h @@ -0,0 +1,85 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Yaser Afshar (UMN) +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, see . + + Linking LAMMPS statically or dynamically with other modules is making a + combined work based on LAMMPS. Thus, the terms and conditions of the GNU + General Public License cover the whole combination. + + In addition, as a special exception, the copyright holders of LAMMPS give + you permission to combine LAMMPS with free software programs or libraries + that are released under the GNU LGPL and with code included in the standard + release of the "kim-api" under the CDDL (or modified versions of such code, + with unchanged license). You may copy and distribute such a system following + the terms of the GNU GPL for LAMMPS and the licenses of the other code + concerned, provided that you include the source code of that other code + when and as the GNU GPL requires distribution of source code. + + Note that people who make modified versions of LAMMPS are not obligated to + grant this special exception for their modified versions; it is their choice + whether to do so. The GNU General Public License gives permission to release + a modified version without this exception; this exception also makes it + possible to release a modified version which carries forward this exception. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Designed for use with the kim-api-2.1.0 (and newer) package +------------------------------------------------------------------------- */ + +#ifdef COMMAND_CLASS + +CommandStyle(kim_property, kimProperty) + +#else + +#ifndef LMP_KIM_PROPERTY_H +#define LMP_KIM_PROPERTY_H + +#include "pointers.h" + +namespace LAMMPS_NS +{ + +class kimProperty : protected Pointers +{ +public: + kimProperty(class LAMMPS *lmp); + + void command(int, char **); +}; + +} // namespace LAMMPS_NS + +#endif // LMP_KIM_PROPERTY_H +#endif // COMMAND_CLASS + +/* ERROR/WARNING messages: + +*/ -- GitLab From dc373dbdeb23b2dd1fd23cd3900dd034915da008 Mon Sep 17 00:00:00 2001 From: Yaser Afshar Date: Mon, 16 Mar 2020 08:15:59 -0500 Subject: [PATCH 292/689] updating the kim_commands doc --- doc/src/kim_commands.rst | 550 +++++++++++++++++++++++++++++++++++---- 1 file changed, 503 insertions(+), 47 deletions(-) diff --git a/doc/src/kim_commands.rst b/doc/src/kim_commands.rst index c710ddfe5d..aca2529ec7 100644 --- a/doc/src/kim_commands.rst +++ b/doc/src/kim_commands.rst @@ -1,16 +1,19 @@ -.. index:: kim_init, kim_interactions, kim_query, kim_param +.. index:: kim_init, kim_interactions, kim_query, kim_param, kim_property -kim_init command -================= +:ref:`kim_init` command +========================================= -kim_interactions command -========================= +:ref:`kim_interactions` command +========================================================= -kim_query command -================== +:ref:`kim_query` command +=========================================== -kim_param command -================== +:ref:`kim_param` command +=========================================== + +:ref:`kim_property` command +================================================= Syntax """""" @@ -22,6 +25,11 @@ Syntax kim_query variable formatarg query_function queryargs kim_param get param_name index_range variables formatarg kim_param set param_name index_range values + kim_property create instance_id property_id + kim_property modify instance_id key key_name key_name_key key_name_value + kim_property remove instance_id key key_name + kim_property destroy instance_id + kim_property dump file .. _formatarg_options: @@ -41,13 +49,19 @@ Syntax on the prefix specified in *variable* and a number appended to indicate which element in the list of values is in the variable. *explicit* = returns the values separately in one more more variable names - provided as arguments that precede *formatarg*\ . [default for *kim_param*] + provided as arguments that preceed *formatarg*\ . [default for *kim_param*] * query_function = name of the OpenKIM web API query function to be used * queryargs = a series of *keyword=value* pairs that represent the web query; supported keywords depend on the query function * param_name = name of a KIM portable model parameter * index_range = KIM portable model parameter index range (an integer for a single element, or pair of integers separated by a colon for a range of elements) * values = new value(s) to replace the current value(s) of a KIM portable model parameter +* instance_id = a positive integer identifying the KIM property instance +* property_id = identifier of a `KIM Property Definition `_, which can be (1) a property short name, (2) the full unique ID of the property (including the contributor and date), (3) a file name corresponding to a local property definition file +* key_name = one of the keys belonging to the specified KIM property definition +* key_name_key = a key belonging to a key-value pair (standardized in the `KIM Properties Framework `__) +* key_name_value = value to be associated with a key_name_key in a key-value pair +* file = name of a file to write the currently defined set of KIM property instances to Examples """""""" @@ -64,6 +78,15 @@ Examples kim_query a0 get_lattice_constant_cubic crystal=["fcc"] species=["Al"] units=["angstrom"] kim_param get gamma 1 varGamma kim_param set gamma 1 3.0 + kim_property create 1 atomic-mass + kim_property modify 1 key mass source-value 26.98154 + kim_property modify 1 key species source-value Al + kim_property remove 1 key species + kim_property destroy 1 + kim_property dump results.edn + + +.. _kim_description: Description """"""""""" @@ -157,11 +180,10 @@ See the `current list of KIM PMs and SMs archived in OpenKIM `_ to -learn how to install a pre-build binary of the OpenKIM Repository of Models. +See `Obtaining KIM Models `_ to +learn how to install a pre-built binary of the OpenKIM Repository of Models. .. note:: - It is also possible to locally install IMs not archived in OpenKIM, in which case their names do not have to conform to the KIM ID format. @@ -169,15 +191,17 @@ Using OpenKIM IMs with LAMMPS ----------------------------- Two commands are employed when using OpenKIM IMs, one to select the -IM and perform necessary initialization (*kim_init*), and the second +IM and perform necessary initialization (\ *kim_init*\ ), and the second to set up the IM for use by executing any necessary LAMMPS commands -(*kim_interactions*). Both are required. +(\ *kim_interactions*\ ). Both are required. See the *examples/kim* directory for example input scripts that use KIM PMs and KIM SMs. +.. _kim_init command: + OpenKIM IM Initialization (*kim_init*) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The *kim_init* mode command must be issued **before** the simulation box is created (normally at the top of the file). @@ -219,7 +243,7 @@ either match the required units of the IM or the IM must be able to adjust its units to match. (The latter is only possible with some KIM PMs; SMs can never adjust their units.) If a match is possible, the LAMMPS :doc:`units ` command is called to set the units to -*user_units*. If the match fails, the simulation is terminated with +*user_units*\ . If the match fails, the simulation is terminated with an error. Here is an example of a LAMMPS script to compute the cohesive energy @@ -324,8 +348,10 @@ be done to convert the box and all atomic positions to the correct units: all appropriate places in the input script. It is up to the user to do this correctly. +.. _kim_interactions command: + OpenKIM IM Execution (*kim_interactions*) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The second and final step in using an OpenKIM IM is to execute the *kim_interactions* command. This command must be preceded by a *kim_init* @@ -399,12 +425,17 @@ the *kim_interactions* command executes the following LAMMPS input commands: pair_coeff * * ffield.reax.rdx C H N O fix reaxqeq all qeq/reax 1 0.0 10.0 1.0e-6 param.qeq -Note that the files *lmp_control*, *ffield.reax.rdx* and *param.qeq* -are specific to the Strachan et al. (2003) ReaxFF parameterization -and are archived as part of the SM package in OpenKIM. -Note also that parameters like cutoff radii and charge tolerances, -which have an effect on IM predictions, are also included in the -SM definition ensuring reproducibility. +.. note:: + + The files *lmp_control*, *ffield.reax.rdx* and *param.qeq* + are specific to the Strachan et al. (2003) ReaxFF parameterization + and are archived as part of the SM package in OpenKIM. + +.. note:: + + Parameters like cutoff radii and charge tolerances, + which have an effect on IM predictions, are also included in the + SM definition ensuring reproducibility. .. note:: @@ -414,8 +445,10 @@ SM definition ensuring reproducibility. bond_coeff, fixes related to charge equilibration, etc.) should normally not appear in the input script. +.. _kim_query command: + Using OpenKIM Web Queries in LAMMPS (*kim_query*) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The *kim_query* command performs a web query to retrieve the predictions of an IM set by *kim_init* for material properties archived in @@ -427,6 +460,7 @@ of an IM set by *kim_init* for material properties archived in The syntax for the *kim_query* command is as follows: + .. code-block:: LAMMPS kim_query variable formatarg query_function queryargs @@ -442,7 +476,7 @@ individual variables of the form *prefix_I*, where *prefix* is set to the *kim_query* *variable* argument and *I* ranges from 1 to the number of returned values. The number and order of the returned values is determined by the type of query performed. (Note that the "explicit" setting of -*formatarg* is not supported by *kim_query*.) +*formatarg* is not supported by *kim_query*\ .) .. note:: @@ -452,7 +486,7 @@ by the type of query performed. (Note that the "explicit" setting of cases will generate an error. The second required argument *query_function* is the name of the -query function to be called (e.g. *get_lattice_constant_cubic*). +query function to be called (e.g. *get_lattice_constant_cubic*\ ). All following :doc:`arguments ` are parameters handed over to the web query in the format *keyword=value*\ , where *value* is always an array of one or more comma-separated items in brackets. @@ -466,7 +500,7 @@ is available on the OpenKIM webpage at All query functions require the *model* keyword, which identifies the IM whose predictions are being queried. This keyword is automatically generated by *kim_query* based on the IM set in *kim_init* and must not - be specified as an argument to *kim_query*. + be specified as an argument to *kim_query*\ . .. note:: @@ -475,11 +509,11 @@ is available on the OpenKIM webpage at used to compute this property. In cases where there are multiple methods in OpenKIM for computing a property, a *method* keyword can be provided to select the method of choice. See the - `query documentation `_ - to see which methods are available for a given *query function*\ . + `query documentation `_ + to see which methods are available for a given *query_function*\ . *kim_query* Usage Examples and Further Clarifications -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The data obtained by *kim_query* commands can be used as part of the setup or analysis phases of LAMMPS simulations. Some examples are given below. @@ -502,10 +536,12 @@ crystal. By using *kim_query*, the user is saved the trouble and possible error of tracking this value down, or of having to perform an energy minimization to find the equilibrium lattice constant. -Note that in *unit_conversion_mode* the results obtained from a -*kim_query* would need to be converted to the appropriate units system. -For example, in the above script, the lattice command would need to be -changed to: "lattice fcc ${a0}\*${_u_distance}". +.. note:: + + In *unit_conversion_mode* the results obtained from a + *kim_query* would need to be converted to the appropriate units system. + For example, in the above script, the lattice command would need to be + changed to: "lattice fcc ${a0}*${_u_distance}". **Define an equilibrium hcp crystal** @@ -524,7 +560,7 @@ changed to: "lattice fcc ${a0}\*${_u_distance}". In this case the *kim_query* returns two arguments (since the hexagonal close packed (hcp) structure has two independent lattice constants). The *formatarg* keyword "split" places the two values into -the variables *latconst_1* and *latconst_2*. (These variables are +the variables *latconst_1* and *latconst_2*\ . (These variables are created if they do not already exist.) For convenience the variables *a0* and *c0* are created in order to make the remainder of the input script more readable. @@ -555,9 +591,9 @@ potential. If no tolerance is passed a default value is used. If multiple results are returned (indicating that the tolerance is too large), *kim_query* will return an error. See the - `query documentation `_ + `query documentation `_ to see which numerical arguments and tolerances are available for a - given *query function*\ . + given *query_function*\ . **Compute defect formation energy** @@ -586,8 +622,10 @@ ideal fcc cohesive energy of the atoms in the system obtained from from these programs are queried is tracked. No other information about the nature of the query or its source is recorded. +.. _kim_param command: + Accessing KIM Model Parameters from LAMMPS (*kim_param*) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ All IMs are functional forms containing a set of parameters. The values of these parameters are typically @@ -620,7 +658,7 @@ for details). .. note:: - The *kim_param get/set* commands must be preceded by *kim_init*. + The *kim_param get/set* commands must be preceded by *kim_init*\ . The *kim_param set* command must additionally be preceded by a *kim_interactions* command (or alternatively by a *pair_style kim* and *pair_coeff* commands). The *kim_param set* command may be used wherever a *pair_coeff* command may occur. @@ -674,13 +712,13 @@ Multiple parameters can be retrieved with a single call to *kim_param get* by repeating the argument list following *get*\ . For a *set* operation, the *values* argument contains the new value(s) -for the element(s) of the parameter specified by *index_range*. For the case +for the element(s) of the parameter specified by *index_range*\ . For the case where multiple values are being set, *values* contains a set of values separated by spaces. Multiple parameters can be set with a single call to *kim_param set* by repeating the argument list following *set*\ . *kim_param* Usage Examples and Further Clarifications -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Examples of getting and setting KIM PM parameters with further clarifications are provided below. @@ -722,7 +760,7 @@ determined by the *formatarg* argument. In this case, *formatarg* is not specified and therefore the default "explicit" mode is used. (The behavior would be the same if the word -*explicit* were added after *LAM_TeSe*.) Elements 7, 8 and 9 of parameter +*explicit* were added after *LAM_TeSe*\ .) Elements 7, 8 and 9 of parameter lambda retrieved by the *get* operation are placed in the LAMMPS variables *LAM_TeTe*, *LAM_TeZn* and *LAM_TeSe*, respectively. @@ -765,7 +803,7 @@ contains the current value of lambda. In this case, the "split" mode of *formatarg* is used. The three values retrieved by the *get* operation are stored in -the three LAMMPS variables *LAM_15*, *LAM_16* and *LAM_17*. +the three LAMMPS variables *LAM_15*, *LAM_16* and *LAM_17*\ . The provided name "LAM" is used as prefix and the location in the lambda array is appended to create the variable names. @@ -797,7 +835,7 @@ potential, while *NEW_GAMMA* will contain the value 2.6. **Setting multiple scalar parameters with a single call** -.. parsed-literal:: +.. code-block:: LAMMPS kim_init SW_ZhouWardMartin_2013_CdTeZnSeHgS__MO_503261197030_002 metal ... @@ -824,6 +862,421 @@ In this case, elements 2 through 6 of the parameter *sigma* are set to the values 2.35214, 2.23869, 2.04516, 2.43269 and 1.80415 in order. +.. _kim_property command: + +Writing material properties computed in LAMMPS to standard KIM property instance format (*kim_property*) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As explained :ref:`above`, +The OpenKIM system includes a collection of Tests (material property calculation codes), +Models (interatomic potentials), Predictions, and Reference Data (DFT or experiments). +Specifically, a KIM Test is a computation that when coupled with a KIM Model generates +the prediction of that model for a specific material property rigorously defined +by a KIM Property Definition (see the +`KIM Properties Framework `__ +for further details). A prediction of a material property for a given model is a specific +numerical realization of a property definition, referred to as a "Property +Instance." The objective of the *kim_property* command is to make it easy to +output material properties in a standardized, machine readable, format that can be easily +ingested by other programs. +Additionally, it aims to make it as easy as possible to convert a LAMMPS script that computes a +material property into a KIM Test that can then be uploaded to `openkim.org `_ + +A developer interested in creating a KIM Test using a LAMMPS script should +first determine whether a property definition that applies to their calculation +already exists in OpenKIM by searching the `properties page +`_. If none exists, it is possible to use a +locally defined property definition contained in a file until it can be +uploaded to the official repository (see below). Once one or more applicable +property definitions have been identified, the *kim_property create*, +*kim_property modify*, *kim_property remove*, and *kim_property destroy*, +commands provide an interface to create, set, modify, remove, and destroy +instances of them within a LAMMPS script. Their general syntax is as follows: + +.. code-block:: LAMMPS + + kim_property create instance_id property_id + kim_property modify instance_id key key_name key_name_key key_name_value + kim_property remove instance_id key key_name + kim_property destroy instance_id + kim_property dump file + +Here, *instance_id* is a positive integer used to uniquely identify each +property instance; (note that the results file can contain multiple property +instances). A property_id is an identifier of a +`KIM Property Definition `_, +which can be (1) a property short name, (2) the full unique ID of the property +(including the contributor and date), (3) a file name corresponding to a local +property definition file. Examples of each of these cases are shown below: + +.. code-block:: LAMMPS + + kim_property create 1 atomic-mass + kim_property create 2 cohesive-energy-relation-cubic-crystal + +.. code-block:: LAMMPS + + kim_property create 1 tag:brunnels@noreply.openkim.org,2016-05-11:property/atomic-mass + kim_property create 2 tag:staff@noreply.openkim.org,2014-04-15:property/cohesive-energy-relation-cubic-crystal + +.. code-block:: LAMMPS + + kim_property create 1 new-property.edn + kim_property create 2 /home/mary/marys-kim-properties/dissociation-energy.edn + +In the last example, "new-property.edn" and "/home/mary/marys-kim-properties/dissociation-energy.edn" are the +names of files that contain user-defined (local) property definitions. + +A KIM property instance takes the form of a "map," i.e. a set of key-value +pairs akin to Perl's hash, Python's dictionary, or Java's Hashtable. It +consists of a set of property key names, each of which is referred to here by +the *key_name* argument, that are defined as part of the relevant KIM Property +Definition and include only lowercase alphanumeric characters and dashes. The +value paired with each property key is itself a map whose possible keys are +defined as part of the `KIM Properties Framework +`__; these keys are +referred to by the *key_name_key* argument and their associated values by the +*key_name_value* argument. These values may either be scalars or arrays, +as stipulated in the property definition. + +.. note:: + + Each map assigned to a *key_name* must contain the *key_name_key* + "source-value" and an associated *key_name_value* of the appropriate + type (as defined in the relevant KIM Property Definition). For keys that are + defined as having physical units, the + "source-unit" *key_name_key* must also be given a string value recognized + by `GNU units `_. + +Once a *kim_property create* command has been given to instantiate a property +instance, maps associated with the property's keys can be edited using the +*kim_property modify* command. In using this command, the special keyword +"key" should be given, followed by the property key name and the key-value pair +in the map associated with the key that is to be set. For example, the +`atomic-mass `_ +property definition consists of two property keys named "mass" and "species." +An instance of this property could be created like so: + +.. code-block:: LAMMPS + + kim_property create 1 atomic-mass + kim_property modify 1 key species source-value Al + kim_property modify 1 key mass source-value 26.98154 + kim_property modify 1 key mass source-unit amu + +or, equivalently, + +.. code-block:: LAMMPS + + kim_property create 1 atomic-mass + kim_property modify 1 key species source-value Al & + key mass source-value 26.98154 & + source-unit amu + +*kim_property* Usage Examples and Further Clarifications +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +**Create** + +.. code-block:: LAMMPS + + kim_property create instance_id property_id + +The *kim_property create* command takes as input a property instance ID and the +property definition name, and creates an initial empty property instance data +structure. For example, + +.. code-block:: LAMMPS + + kim_property create 1 atomic-mass + kim_property create 2 cohesive-energy-relation-cubic-crystal + +creates an empty property instance of the "atomic-mass" property definition +with instance ID 1 and an empty instance of the +"cohesive-energy-relation-cubic-crystal" property with ID 2. A list of +published property definitions in OpenKIM can be found on the `properties page +`_. + +One can also provide the name of a file in the current working directory or the +path of a file containing a valid property definition. For example, + +.. code-block:: LAMMPS + + kim_property create 1 new-property.edn + +where "new-property.edn" refers to a file name containing a new property +definition that does not exist in OpenKIM. + +If the *property_id* given cannot be found in OpenKIM and no file of this name +containing a valid property definition can be found, this command will produce +an error with an appropriate message. Calling *kim_property create* with the +same instance ID multiple times will also produce an error. + +**Modify** + +.. code-block:: LAMMPS + + kim_property modify instance_id key key_name key_name_key key_name_value + +The *kim_property modify* command incrementally builds the property instance +by receiving property definition keys along with associated arguments. Each +*key_name* is associated with a map containing one or more key-value pairs (in +the form of *key_name_key*-*key_name_value* pairs). For example, + +.. code-block:: LAMMPS + + kim_property modify 1 key species source-value Al + kim_property modify 1 key mass source-value 26.98154 + kim_property modify 1 key mass source-unit amu + +where the special keyword "key" is followed by a *key_name* ("species" or +"mass" in the above) and one or more key-value pairs. These key-value pairs +may continue until either another "key" keyword is given or the end of the +command line is reached. Thus, the above could equivalently be written as + +.. code-block:: LAMMPS + + kim_property modify 1 key species source-value Al & + key mass source-value 26.98154 & + key mass source-unit amu + +As an example of modifying multiple key-value pairs belonging to the map of a +single property key, the following command modifies the map of the +"cohesive-potential-energy" property key to contain the key "source-unit" which +is assigned a value of "eV" and the key "digits" which is assigned a value of +5: + +.. code-block:: LAMMPS + + kim_property modify 2 key cohesive-potential-energy source-unit eV digits 5 + +.. note:: + + The relevant data types of the values in the map are handled + automatically based on the specification of the key in the + KIM Property Definition. In the example above, + this means that the value "eV" will automatically be interpreted as a string + while the value 5 will be interpreted as an integer. + +The values contained in maps can either be scalars, as in all of the examples +above, or arrays depending on which is stipulated in the corresponding Property +Definition. For one-dimensional arrays, a single one-based index must be +supplied that indicates which element of the array is to be modified. For +multidimensional arrays, multiple indices must be given depending on the +dimensionality of the array. + +.. note:: + + All array indexing used by *kim_property modify* is one-based, i.e. the + indices are enumerated 1, 2, 3, ... + +.. note:: + + The dimensionality of arrays are defined in the the corresponding Property + Definition. The extent of each dimension of an array can either be a + specific finite number or indefinite and determined at run time. If + an array has a fixed extent, attempting to modify an out-of-range index will + fail with an error message. + +For example, the "species" property key of the +`cohesive-energy-relation-cubic-crystal +`_ +property is a one-dimensional array that can contain any number of entries +based on the number of atoms in the unit cell of a given cubic crystal. To +assign an array containing the string "Al" four times to the "source-value" key +of the "species" property key, we can do so by issuing: + +.. code-block:: LAMMPS + + kim_property modify 2 key species source-value 1 Al + kim_property modify 2 key species source-value 2 Al + kim_property modify 2 key species source-value 3 Al + kim_property modify 2 key species source-value 4 Al + +.. note:: + + No declaration of the number of elements in this array was given; + *kim_property modify* will automatically handle memory management to allow + an arbitrary number of elements to be added to the array. + +.. note:: + + In the event that *kim_property modify* is used to set the value of an + array index without having set the values of all lesser indices, they will + be assigned default values based on the data type associated with the key in + the map: + + .. table_from_list:: + :columns: 2 + + * Data type + * Default value + * int + * 0 + * float + * 0.0 + * string + * \"\" + * file + * \"\" + + For example, doing the following: + + .. code-block:: LAMMPS + + kim_property create 2 cohesive-energy-relation-cubic-crystal + kim_property modify 2 key species source-value 4 Al + + will result in the "source-value" key in the map for the property key + "species" being assigned the array ["", "", "", "Al"]. + +For convenience, the index argument provided may refer to an inclusive range of +indices by specifying two integers separated by a colon (the first integer must +be less than or equal to the second integer, and no whitespace should be +included). Thus, the snippet above could equivalently be written: + +.. code-block:: LAMMPS + + kim_property modify 2 key species source-value 1:4 Al Al Al Al + +Calling this command with a non-positive index, e.g. +``kim_property modify 2 key species source-value 0 Al``, or an incorrect +number of input arguments, e.g. +``kim_property modify 2 key species source-value 1:4 Al Al``, will result in an +error. + +As an example of modifying multidimensional arrays, consider the "basis-atoms" +key in the `cohesive-energy-relation-cubic-crystal +`_ +property definition. This is a two-dimensional array containing the fractional +coordinates of atoms in the unit cell of the cubic crystal. In the case of, +e.g. a conventional fcc unit cell, the "source-value" key in the map associated +with this key should be assigned the following value: + +.. code-block:: LAMMPS + + [[0.0, 0.0, 0.0], + [0.5, 0.5, 0.0], + [0.5, 0.0, 0.5], + [0.0, 0.5, 0.5]] + +While each of the twelve components could be set individually, we can instead set +each row at a time using colon notation: + +.. code-block:: LAMMPS + + kim_property modify 2 key basis-atom-coordinates source-value 1 1:3 0.0 0.0 0.0 + kim_property modify 2 key basis-atom-coordinates source-value 2 1:3 0.5 0.5 0.0 + kim_property modify 2 key basis-atom-coordinates source-value 3 1:3 0.5 0.0 0.5 + kim_property modify 2 key basis-atom-coordinates source-value 4 1:3 0.0 0.5 0.5 + +Where the first index given refers to a row and the second index refers to a +column. We could, instead, choose to set each column at a time like so: + +.. code-block:: LAMMPS + + kim_property modify 2 key basis-atom-coordinates source-value 1:4 1 0.0 0.5 0.5 0.0 & + key basis-atom-coordinates source-value 1:4 2 0.0 0.5 0.0 0.5 & + key basis-atom-coordinates source-value 1:4 3 0.0 0.0 0.5 0.5 + +.. note:: + + Multiple calls of *kim_property modify* made for the same instance ID + can be combined into a single invocation, meaning the following are + both valid: + + .. code-block:: LAMMPS + + kim_property modify 2 key basis-atom-coordinates source-value 1 1:3 0.0 0.0 0.0 & + key basis-atom-coordinates source-value 2 1:3 0.5 0.5 0.0 & + key basis-atom-coordinates source-value 3 1:3 0.5 0.0 0.5 & + key basis-atom-coordinates source-value 4 1:3 0.0 0.5 0.5 + + .. code-block:: LAMMPS + + kim_property modify 2 key short-name source-value 1 fcc & + key species source-value 1:4 Al Al Al Al & + key a source-value 1:5 3.9149 4.0000 4.032 4.0817 4.1602 & + source-unit angstrom & + digits 5 & + key basis-atom-coordinates source-value 1 1:3 0.0 0.0 0.0 & + key basis-atom-coordinates source-value 2 1:3 0.5 0.5 0.0 & + key basis-atom-coordinates source-value 3 1:3 0.5 0.0 0.5 & + key basis-atom-coordinates source-value 4 1:3 0.0 0.5 0.5 + +.. note:: + + For multidimensional arrays, only one colon-separated range is allowed + in the index listing. Therefore, + + .. code-block:: LAMMPS + + kim_property modify 2 key basis-atom-coordinates 1 1:3 0.0 0.0 0.0 + + is valid but + + .. code-block:: LAMMPS + + kim_property modify 2 key basis-atom-coordinates 1:2 1:3 0.0 0.0 0.0 0.0 0.0 0.0 + + is not. + +.. note:: + + After one sets a value in a map with the *kim_property modify* command, + additional calls will overwrite the previous value. + +**Remove** + +.. code-block:: LAMMPS + + kim_property remove instance_id key key_name + +The *kim_property remove* command can be used to remove a property key from a +property instance. For example, + +.. code-block:: LAMMPS + + kim_property remove 2 key basis-atom-coordinates + +**Destroy** + +.. code-block:: LAMMPS + + kim_property destroy instance_id + +The *kim_property destroy* command deletes a previously created property +instance ID. For example, + +.. code-block:: LAMMPS + + kim_property destroy 2 + +.. note:: + + If this command is called with an instance ID that does not exist, no + error is raised. + +**Dump** + +The *kim_property dump* command can be used to write the content of all +currently defined property instances to a file: + +.. code-block:: LAMMPS + + kim_property dump file + +For example, + +.. code-block:: LAMMPS + + kim_property dump results.edn + +.. note:: + + Issuing the *kim_property dump* command clears all existing property + instances from memory. + Citation of OpenKIM IMs ----------------------- @@ -847,8 +1300,11 @@ LAMMPS is built with that package. A requirement for the KIM package, is the KIM API library that must be downloaded from the `OpenKIM website `_ and installed before LAMMPS is compiled. When installing LAMMPS from binary, the kim-api package -is a dependency that is automatically downloaded and installed. See the KIM -section of the :doc:`Packages details ` for details. +is a dependency that is automatically downloaded and installed. The *kim_query* +command requires the *libcurl* library to be installed. The *kim_property* +command requires *Python* 3.6 or later and the *kim-property* python package to +be installed. See the KIM section of the :doc:`Packages details ` +for details. Furthermore, when using *kim_commands* to run KIM SMs, any packages required by the native potential being used or other commands or fixes that it invokes -- GitLab From f203258ad59c6d6462e11c3907d17d398dd339df Mon Sep 17 00:00:00 2001 From: Yaser Afshar Date: Mon, 16 Mar 2020 08:17:27 -0500 Subject: [PATCH 293/689] updating the Build_extras, KIM package --- doc/src/Build_extras.rst | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/doc/src/Build_extras.rst b/doc/src/Build_extras.rst index 4589015e35..45c876d84a 100644 --- a/doc/src/Build_extras.rst +++ b/doc/src/Build_extras.rst @@ -189,13 +189,27 @@ KIM package --------------------- To build with this package, the KIM library with API v2 must be downloaded -and built on your system. It must include the KIM models that you want to -use with LAMMPS. If you want to use the :doc:`kim_query ` +and built on your system. It must include the KIM models that you want to +use with LAMMPS. + +If you would like to use the :doc:`kim_query ` command, you also need to have libcurl installed with the matching development headers and the curl-config tool. -See the `Obtaining KIM Models `_ -web page to +If you would like to use the :doc:`kim_property ` +command, you need to build LAMMPS with the Python 3.6 or later package +installed. See the :doc:`Python ` doc page for more info on building +LAMMPS with the version of Python on your system. +After successfully building LAMMPS with Python, you need to +install the kim-property Python package, which can be easily done using +*pip* as ``pip install kim-property``, or from the *conda-forge* channel as +``conda install kim-property`` if LAMMPS is built in Conda. More detailed +information is available at: +`kim-property installation `_. + +In addition to installing the KIM API, it is also necessary to install the +library of KIM models (interatomic potentials). +See `Obtaining KIM Models `_ to learn how to install a pre-build binary of the OpenKIM Repository of Models. See the list of all KIM models here: https://openkim.org/browse/models -- GitLab From cfc9fe7e39a451109b4f32a47fd1d11dd082e0ae Mon Sep 17 00:00:00 2001 From: Yaser Afshar Date: Mon, 16 Mar 2020 08:18:19 -0500 Subject: [PATCH 294/689] updating the Commands_all, adding kim_property command --- doc/src/Commands_all.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/src/Commands_all.rst b/doc/src/Commands_all.rst index 36ae112527..92c0ba107a 100644 --- a/doc/src/Commands_all.rst +++ b/doc/src/Commands_all.rst @@ -70,6 +70,7 @@ An alphabetic list of all general LAMMPS commands. * :doc:`kim_init ` * :doc:`kim_interactions ` * :doc:`kim_param ` + * :doc:`kim_property ` * :doc:`kim_query ` * :doc:`kspace_modify ` * :doc:`kspace_style ` -- GitLab From 2d3423a49309830e6969f5870248e4bc01f3e0e9 Mon Sep 17 00:00:00 2001 From: Yaser Afshar Date: Mon, 16 Mar 2020 08:19:13 -0500 Subject: [PATCH 295/689] updating the Packages_details, KIM package --- doc/src/Packages_details.rst | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/doc/src/Packages_details.rst b/doc/src/Packages_details.rst index e20c2886ed..8251c5301e 100644 --- a/doc/src/Packages_details.rst +++ b/doc/src/Packages_details.rst @@ -365,12 +365,17 @@ KIM package This package contains a set of commands that serve as a wrapper on the `Open Knowledgebase of Interatomic Models (OpenKIM) `_ -repository of interatomic models (IMs) -enabling compatible ones to be used in LAMMPS simulations. -This includes :doc:`kim_init and kim_interactions ` -commands to select, initialize and instantiate the IM, and a -:doc:`kim_query ` command to perform web queries -for material property predictions of OpenKIM IMs. +repository of interatomic models (IMs) enabling compatible ones to be used in +LAMMPS simulations. + +This includes :doc:`kim_init `, and +:doc:`kim_interactions ` commands to select, initialize and +instantiate the IM, a :doc:`kim_query ` command to perform web +queries for material property predictions of OpenKIM IMs, a +:doc:`kim_param ` command to access KIM Model Parameters from +LAMMPS, and a :doc:`kim_property ` command to write material +properties computed in LAMMPS to standard KIM property instance format. + Support for KIM IMs that conform to the `KIM Application Programming Interface (API) `_ is provided by the :doc:`pair_style kim ` command. @@ -392,13 +397,16 @@ The KIM project is led by Ellad Tadmor and Ryan Elliott (U Minnesota) and is funded by the `National Science Foundation `_. **Authors:** Ryan Elliott (U Minnesota) is the main developer for the KIM -API and the *pair_style kim* command. Axel Kohlmeyer (Temple U) and -Ellad Tadmor (U Minnesota) contributed to the :doc:`kim_commands ` -interface in close collaboration with Ryan Elliott. +API and the *pair_style kim* command. Yaser Afshar (U Minnesota), +Axel Kohlmeyer (Temple U), Ellad Tadmor (U Minnesota), and +Daniel Karls (U Minnesota) contributed to the +:doc:`kim_commands ` interface in close collaboration with +Ryan Elliott. **Install:** -This package has :ref:`specific installation instructions ` on the :doc:`Build extras ` doc page. +This package has :ref:`specific installation instructions ` on the +:doc:`Build extras ` doc page. **Supporting info:** -- GitLab From 3da1e127bf82049d220ae2f6cfe21f9837b3977e Mon Sep 17 00:00:00 2001 From: Yaser Afshar Date: Mon, 16 Mar 2020 08:42:11 -0500 Subject: [PATCH 296/689] updating the false_positives with names causing warning --- doc/utils/sphinx-config/false_positives.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index 264c3fab50..4110682e6c 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -714,6 +714,7 @@ edgeIDs edihed edim edip +edn edpd eDPD edu @@ -1087,6 +1088,7 @@ Harting Hartree Hartrees Hasan +Hashtable Haswell Haugk Hayoun @@ -1344,6 +1346,7 @@ Kai Kalia Kamberaj Kapfer +Karls Karlsruhe Karniadakis Karplus @@ -1630,6 +1633,8 @@ Marroquin Marsaglia Marseille Martyna +mary +marys Masaglia Mashayak Massimilliano @@ -3135,6 +3140,7 @@ Westview wget Whelan whitesmoke +whitespace Wi Wicaksono Wijk @@ -3201,6 +3207,7 @@ xzhou yaff YAFF Yamada +Yaser Yazdani Ybar ybox -- GitLab From b692da3b01ee680300e24bf32647fd34d1cc20cb Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2020 00:57:30 -0400 Subject: [PATCH 297/689] include building tools in "most" preset --- cmake/presets/most.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/presets/most.cmake b/cmake/presets/most.cmake index b2c53bd41d..2f5b517526 100644 --- a/cmake/presets/most.cmake +++ b/cmake/presets/most.cmake @@ -13,3 +13,5 @@ set(ALL_PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL foreach(PKG ${ALL_PACKAGES}) set(PKG_${PKG} ON CACHE BOOL "" FORCE) endforeach() + +set(BUILD_TOOLS ON CACHE BOOL "" FORCE) -- GitLab From 2c282b693e60db6c0d4e2e915f2007feffe529bb Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2020 12:33:23 -0400 Subject: [PATCH 298/689] flag two more subroutines can trigger the variable tracking message and slow down compilation --- src/KSPACE/pppm_disp.cpp | 2 +- src/MANYBODY/pair_bop.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/KSPACE/pppm_disp.cpp b/src/KSPACE/pppm_disp.cpp index 0bb81f125e..5cfacd644d 100644 --- a/src/KSPACE/pppm_disp.cpp +++ b/src/KSPACE/pppm_disp.cpp @@ -1659,7 +1659,7 @@ int PPPMDisp::check_convergence(double** A,double** Q,double** A0, allocate memory that depends on # of K-vectors and order ------------------------------------------------------------------------- */ -void PPPMDisp::allocate() +void _noopt PPPMDisp::allocate() { int (*procneigh)[2] = comm->procneigh; diff --git a/src/MANYBODY/pair_bop.cpp b/src/MANYBODY/pair_bop.cpp index 2763c561d6..10ab1d7080 100644 --- a/src/MANYBODY/pair_bop.cpp +++ b/src/MANYBODY/pair_bop.cpp @@ -5017,7 +5017,7 @@ double PairBOP::PiBo(int itmp, int jtmp) /* ---------------------------------------------------------------------- */ -void PairBOP::read_table(char *filename) +void _noopt PairBOP::read_table(char *filename) { int i,j,k,n,m; int buf1,pass; -- GitLab From 5779731da34c844e5f77298782e0db374898ca08 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2020 13:04:38 -0400 Subject: [PATCH 299/689] provide cmbuild wrapper script for cmake. document it and add some improvements to CMake build docs --- doc/src/Build_cmake.rst | 34 +++++++++------- doc/src/Tools.rst | 90 ++++++++++++++++++++++++++++++++--------- tools/README | 45 +++++++++++---------- tools/cmake/cmbuild | 69 +++++++++++++++++++++++++++++++ 4 files changed, 183 insertions(+), 55 deletions(-) create mode 100755 tools/cmake/cmbuild diff --git a/doc/src/Build_cmake.rst b/doc/src/Build_cmake.rst index c41136c0a5..206fd05253 100644 --- a/doc/src/Build_cmake.rst +++ b/doc/src/Build_cmake.rst @@ -22,27 +22,31 @@ Makefile(s). Example: cd lammps # change to the LAMMPS distribution directory mkdir build; cd build # create a new directory (folder) for build cmake [options ...] ../cmake # configuration with (command-line) cmake - make # compilation + make # compilation (or use "cmbuild" from "tools/cmake") -The cmake command will detect available features, enable selected +The ``cmake`` command will detect available features, enable selected packages and options, and will generate the build environment. By default this build environment will be created for "Unix Makefiles" on most platforms and particularly on Linux. However, alternate build tools (e.g. Ninja) and project files for Integrated Development Environments (IDEs) like Eclipse, CodeBlocks, or Kate can be generated, too. This is -selected via the "-G" command line flag. For the rest of the documentation +selected via the ``-G`` command line flag. For the rest of the documentation we will assume that the build environment is generated for makefiles -and thus the make command will be used to compile and link LAMMPS as -indicated above, producing (by default) an executable called "lmp" and -a library called "liblammps.a" in the "build" folder. When generating +and thus the ``make`` command will be used to compile and link LAMMPS as +indicated above, producing (by default) an executable called ``lmp`` and +a library called ``liblammps.a`` in the ``build`` folder. When generating a build environment for the "Ninja" build tool, the build command would -be "ninja" instead of "make". +be ``ninja`` instead of ``make``. Or you may copy the ``cmbuild`` script +from the :ref:`tools/cmake folder ` somewhere in your path and use that, +as it will indirectly call CMake with the configured tool. This is +particularly, if you configured the build folder with a build tool +in a non-standard location or name using ``-D CMAKE_MAKE_PROGRAM=``. If your machine has multiple CPU cores (most do these days), using a -command like "make -jN" (with N being the number of available local +command like ``make -j N`` (with N being the number of available local CPU cores) can be much faster. If you plan to do development on LAMMPS or need to re-compile LAMMPS repeatedly, installation of the -ccache (= Compiler Cache) software may speed up repeated compilation +``ccache`` (= Compiler Cache) software may speed up repeated compilation even more. After compilation, you may optionally install the LAMMPS executable into @@ -60,9 +64,11 @@ to ${HOME}/.local ---------- +.. _cmake_build: + There are 3 variants of the CMake command itself: a command-line version -(*cmake* or *cmake3*), a text mode UI version (*ccmake* or *ccmake3*), -and a graphical GUI version (*cmake-gui*). You can use any of them +(``cmake`` or ``cmake3``), a text mode UI version (``ccmake`` or ``ccmake3``), +and a graphical GUI version (``cmake-gui``). You can use any of them interchangeably to configure and create the LAMMPS build environment. On Linux all the versions produce a Makefile as their output by default. See more details on each below. @@ -75,7 +81,7 @@ the :doc:`Build ` doc page. You must perform the CMake build system generation and compilation in a new directory you create. It can be anywhere on your local machine. In these Build pages we assume that you are building in a directory -called "lammps/build". You can perform separate builds independently +called ``lammps/build``. You can perform separate builds independently with different options, so long as you perform each of them in a separate directory you create. All the auxiliary files created by one build process (executable, object files, log files, etc) are stored in @@ -84,10 +90,10 @@ this directory or sub-directories within it that CMake creates. .. note:: To perform a CMake build, no packages can be installed or a build - been previously attempted in the LAMMPS src directory by using "make" + been previously attempted in the LAMMPS src directory by using ``make`` commands to :doc:`perform a conventional LAMMPS build `. CMake detects if this is the case and generates an error, telling you - to type "make no-all purge" in the src directory to un-install all + to type ``make no-all purge`` in the src directory to un-install all packages. The purge removes all the \*.h files auto-generated by make. diff --git a/doc/src/Tools.rst b/doc/src/Tools.rst index 6137b1aa6f..080b87b310 100644 --- a/doc/src/Tools.rst +++ b/doc/src/Tools.rst @@ -40,33 +40,61 @@ own sub-directories with their own Makefiles and/or README files. Pre-processing tools ==================== -+-----------------------------+------------------------+----------------------+----------------------------------+----------------------------------+-----------------------------+ -| :ref:`amber2lmp ` | :ref:`ch2lmp ` | :ref:`chain ` | :ref:`createatoms ` | :ref:`drude ` | :ref:`eam database ` | -+-----------------------------+------------------------+----------------------+----------------------------------+----------------------------------+-----------------------------+ -| :ref:`eam generate ` | :ref:`eff ` | :ref:`ipp ` | :ref:`micelle2d ` | :ref:`moltemplate ` | :ref:`msi2lmp ` | -+-----------------------------+------------------------+----------------------+----------------------------------+----------------------------------+-----------------------------+ -| :ref:`polybond ` | | | | | | -+-----------------------------+------------------------+----------------------+----------------------------------+----------------------------------+-----------------------------+ +.. table_from_list:: + :columns: 6 + + * :ref:`amber2lmp ` + * :ref:`ch2lmp ` + * :ref:`chain ` + * :ref:`createatoms ` + * :ref:`drude ` + * :ref:`eam database ` + * :ref:`eam generate ` + * :ref:`eff ` + * :ref:`ipp ` + * :ref:`micelle2d ` + * :ref:`moltemplate ` + * :ref:`msi2lmp ` + * :ref:`polybond ` + Post-processing tools ===================== -+--------------------------+----------------------------+------------------------+--------------------------+-------------------------------+-----------------------------+ -| :ref:`amber2lmp ` | :ref:`binary2txt ` | :ref:`ch2lmp ` | :ref:`colvars ` | :ref:`eff ` | :ref:`fep ` | -+--------------------------+----------------------------+------------------------+--------------------------+-------------------------------+-----------------------------+ -| :ref:`lmp2arc ` | :ref:`lmp2cfg ` | :ref:`matlab ` | :ref:`phonon ` | :ref:`pymol_asphere ` | :ref:`python ` | -+--------------------------+----------------------------+------------------------+--------------------------+-------------------------------+-----------------------------+ -| :ref:`reax ` | :ref:`replica ` | :ref:`smd ` | :ref:`spin ` | :ref:`xmgrace ` | | -+--------------------------+----------------------------+------------------------+--------------------------+-------------------------------+-----------------------------+ +.. table_from_list:: + :columns: 6 + + * :ref:`amber2lmp ` + * :ref:`binary2txt ` + * :ref:`ch2lmp ` + * :ref:`colvars ` + * :ref:`eff ` + * :ref:`fep ` + * :ref:`lmp2arc ` + * :ref:`lmp2cfg ` + * :ref:`matlab ` + * :ref:`phonon ` + * :ref:`pymol_asphere ` + * :ref:`python ` + * :ref:`reax ` + * :ref:`replica ` + * :ref:`smd ` + * :ref:`spin ` + * :ref:`xmgrace ` Miscellaneous tools =================== -+--------------------------+----------------------+-------------------+--------------------+---------------------------------------+ -| :ref:`doxygen ` | :ref:`emacs ` | :ref:`i-pi ` | :ref:`kate ` | :ref:`singularity ` | -+--------------------------+----------------------+-------------------+--------------------+---------------------------------------+ -| :ref:`vim ` | | | | | -+--------------------------+----------------------+-------------------+--------------------+---------------------------------------+ +.. table_from_list:: + :columns: 6 + + * :ref:`CMake ` + * :ref:`doxygen ` + * :ref:`emacs ` + * :ref:`i-pi ` + * :ref:`kate ` + * :ref:`singularity ` + * :ref:`vim ` ---------- @@ -157,6 +185,30 @@ See the def.chain or def.chain.ab files in the tools directory for examples of definition files. This tool was used to create the system for the :doc:`chain benchmark `. +---------- + +.. _cmake: + +CMake tools +----------- + +The ``cmbuild`` script is a wrapper around using ``cmake --build +--target`` and allows compiling LAMMPS in a :ref:`CMake build folder +` with a make-like syntax regardless of the actual build +tool and the specific name of the program used (e.g. ``ninja-v1.10`` or +``gmake``) when using ``-D CMAKE_MAKE_PROGRAM=``. + +.. parsed-literal:: + + Usage: cmbuild [-v] [-h] [-C ] [-j ] [ [] ...] + + Options: + -h print this message + -j allow processing of NUM concurrent tasks + -C DIRECTORY execute build in folder DIRECTORY + -v produce verbose output + + ---------- .. _colvars: diff --git a/tools/README b/tools/README index b20e82c53e..2a6f28caf0 100644 --- a/tools/README +++ b/tools/README @@ -12,36 +12,37 @@ at. These are the included tools: -amber2lmp python scripts for using AMBER to setup LAMMPS input -binary2txt convert a LAMMPS dump file from binary to ASCII text -ch2lmp convert CHARMM files to LAMMPS input -chain create a data file of bead-spring chains -colvars post-process output of the fix colvars command -createatoms generate lattices of atoms within a geometry +amber2lmp python scripts for using AMBER to setup LAMMPS input +binary2txt convert a LAMMPS dump file from binary to ASCII text +ch2lmp convert CHARMM files to LAMMPS input +chain create a data file of bead-spring chains +cmake tools and scripts for use with CMake +colvars post-process output of the fix colvars command +createatoms generate lattices of atoms within a geometry drude create Drude core/electron atom pairs in a data file -eam_database one tool to generate EAM alloy potential files -eam_generate 2nd tool to generate EAM alloy potential files -eff scripts for working with the eFF (electron force field) -emacs add-ons to EMACS editor for editing LAMMPS input scripts -fep scripts for free-energy perturbation with USER-FEP pkg +eam_database one tool to generate EAM alloy potential files +eam_generate 2nd tool to generate EAM alloy potential files +eff scripts for working with the eFF (electron force field) +emacs add-ons to EMACS editor for editing LAMMPS input scripts +fep scripts for free-energy perturbation with USER-FEP pkg i-pi Python wrapper for performing path-integral MD (PIMD) -ipp input pre-processor Perl tool for creating input scripts +ipp input pre-processor Perl tool for creating input scripts kate add-ons to Kate editor for editing LAMMPS input scripts -lmp2arc convert LAMMPS output to Accelrys Insight format -lmp2cfg convert LAMMPS output to CFG files for AtomEye viz -matlab MatLab scripts for post-processing LAMMPS output -micelle2d create a data file of small lipid chains in solvent +lmp2arc convert LAMMPS output to Accelrys Insight format +lmp2cfg convert LAMMPS output to CFG files for AtomEye viz +matlab MatLab scripts for post-processing LAMMPS output +micelle2d create a data file of small lipid chains in solvent moltemplate Instructions for installing the Moltemplate builder program -msi2lmp use Accelrys Insight code to setup LAMMPS input +msi2lmp use Accelrys Insight code to setup LAMMPS input phonon post-process output of the fix phonon command polybond Python tool for programmable polymer bonding -pymol_asphere convert LAMMPS output of ellipsoids to PyMol format -python Python scripts for post-processing LAMMPS output -reax Tools for analyzing output of ReaxFF simulations -replica tool to reorder LAMMPS replica trajectories according to temperature +pymol_asphere convert LAMMPS output of ellipsoids to PyMol format +python Python scripts for post-processing LAMMPS output +reax Tools for analyzing output of ReaxFF simulations +replica tool to reorder LAMMPS replica trajectories according to temperature smd convert Smooth Mach Dynamics triangles to VTK spin perform a cubic polynomial interpolation of a GNEB MEP -vim add-ons to VIM editor for editing LAMMPS input scripts +vim add-ons to VIM editor for editing LAMMPS input scripts xmgrace a collection of scripts to generate xmgrace plots For tools that are single C, C++, or Fortran files, a Makefile for diff --git a/tools/cmake/cmbuild b/tools/cmake/cmbuild new file mode 100755 index 0000000000..f9c5223048 --- /dev/null +++ b/tools/cmake/cmbuild @@ -0,0 +1,69 @@ +#!/bin/bash +# make like wrapper around "cmake --build" +# (c) 2020 Axel Kohlmeyer +# This file is in the public domain + +WORKDIR="${PWD}" +PARAMS="" +MYARGS="" + +usage() +{ + echo "Usage: cmbuild [-v] [-h] [-C ] [-j ] [ [] ...]" >&2 +} + +help() +{ + usage + cat >&2 < allow processing of NUM concurrent tasks + -C DIRECTORY execute build in folder DIRECTORY + -v produce verbose output +EOF +} + +while (( "$#" )); do + case "$1" in + -C) + WORKDIR="$2" + shift 2 + ;; + -v) + MYARGS="${MYARGS} -v" + shift + ;; + -h) + help + exit 2 + ;; + -j) + MYARGS="${MYARGS} -j $2" + shift 2 + ;; + --) + shift + break + ;; + -*) + echo "Error: Unsupported flag $1" >&2 + echo + usage + exit 1 + ;; + *) + PARAMS="${PARAMS} $1" + shift + ;; + esac +done + +if [ ! -f "${WORKDIR}/CMakeCache.txt" ] ; then + echo "Must execute in a CMake build directory or use -C flag to select one" >&2 + exit 3 +fi + +eval set -- "${PARAMS} $@" +exec cmake --build "${WORKDIR}" ${MYARGS} --target "$@" -- GitLab From f893f4f8c7ebb27595d3309dedbf528799fdfce8 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2020 14:48:20 -0400 Subject: [PATCH 300/689] set host specific optimizations in CMAKE_TUNE_FLAGS, so they can be conveniently overridden --- cmake/CMakeLists.txt | 32 +++++++++++-------------- cmake/Modules/Packages/USER-INTEL.cmake | 5 ---- doc/src/Build_basics.rst | 7 ++++++ 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 9b3992da84..18c6068a13 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -53,11 +53,18 @@ include(CheckIncludeFileCXX) if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Intel") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -restrict") + if (NOT CMAKE_TUNE_FLAGS) + if(CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.3 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.4) + set(CMAKE_TUNE_FLAGS "-xCOMMON-AVX512") + else() + set(CMAKE_TUNE_FLAGS "-xHost") + endif() + endif() endif() if(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") - if(NOT ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")) - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math -ftree-vectorize -fexpensive-optimizations") + if(NOT CMAKE_TUNE_FLAGS) + set (CMAKE_TUNE_FLAGS "-ffast-math -march=native") endif() endif() @@ -70,22 +77,7 @@ if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") option(ENABLE_COVERAGE "Enable code coverage" OFF) mark_as_advanced(ENABLE_COVERAGE) if(ENABLE_COVERAGE) - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage") - endif() - option(ENABLE_SANITIZE_ADDRESS "Enable address sanitizer" OFF) - mark_as_advanced(ENABLE_SANITIZE_ADDRESS) - if(ENABLE_SANITIZE_ADDRESS) - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") - endif() - option(ENABLE_SANITIZE_UNDEFINED "Enable undefined behavior sanitizer" OFF) - mark_as_advanced(ENABLE_SANITIZE_UNDEFINED) - if(ENABLE_SANITIZE_UNDEFINED) - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined") - endif() - option(ENABLE_SANITIZE_THREAD "Enable thread sanitizer" OFF) - mark_as_advanced(ENABLE_SANITIZE_THREAD) - if(ENABLE_SANITIZE_THREAD) - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread") + set (CMAKE_TUNE_FLAGS "--coverage") endif() endif() @@ -347,6 +339,10 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") list(APPEND LAMMPS_LINK_LIBS -lwsock32 -lpsapi) endif() +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_TUNE_FLAGS}") +if(CMAKE_Fortran_FLAGS) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${CMAKE_TUNE_FLAGS}") +endif() ######################################################################## # Basic system tests (standard libraries, headers, functions, types) # ######################################################################## diff --git a/cmake/Modules/Packages/USER-INTEL.cmake b/cmake/Modules/Packages/USER-INTEL.cmake index 3c0cc7ba24..d0941a0a12 100644 --- a/cmake/Modules/Packages/USER-INTEL.cmake +++ b/cmake/Modules/Packages/USER-INTEL.cmake @@ -74,11 +74,6 @@ if(PKG_USER-INTEL) add_definitions(-DLMP_INTEL_OFFLOAD) else() if(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") - if(CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.3 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.4) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -xCOMMON-AVX512") - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -xHost") - endif() include(CheckCXXCompilerFlag) foreach(_FLAG -O2 -fp-model fast=2 -no-prec-div -qoverride-limits -qopt-zmm-usage=high -qno-offload -fno-alias -ansi-alias -restrict) check_cxx_compiler_flag("${__FLAG}" COMPILER_SUPPORTS${_FLAG}) diff --git a/doc/src/Build_basics.rst b/doc/src/Build_basics.rst index 51c3fd871d..7349b3a7ea 100644 --- a/doc/src/Build_basics.rst +++ b/doc/src/Build_basics.rst @@ -213,6 +213,13 @@ A few example command lines are: For compiling with the Clang/LLVM compilers a special CMake preset is included that can be loaded with `-C ../cmake/presets/clang.cmake`. +In addition you can set ``CMAKE_TUNE_FLAGS`` to specifically add compiler +flags to tune for optimal performance on given hosts. By default these are +initialized to some compiler specific flags, where known, to optimize the +LAMMPS executable with optimizations and instructions available on the host +where LAMMPS is compiled. For example, for Intel compilers this would be +``-xHost`` and for GNU compilers this would be ``-march=native``. + .. note:: When the cmake command completes, it prints a summary to the screen -- GitLab From 6f6855e831b92d27e9ecf4f64952516a676ec832 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2020 15:57:33 -0400 Subject: [PATCH 301/689] do not advertise multiple targets in cmbuild wrapper --- doc/src/Tools.rst | 2 +- tools/cmake/cmbuild | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/src/Tools.rst b/doc/src/Tools.rst index 080b87b310..8feb2afefa 100644 --- a/doc/src/Tools.rst +++ b/doc/src/Tools.rst @@ -200,7 +200,7 @@ tool and the specific name of the program used (e.g. ``ninja-v1.10`` or .. parsed-literal:: - Usage: cmbuild [-v] [-h] [-C ] [-j ] [ [] ...] + Usage: cmbuild [-v] [-h] [-C ] [-j ] [] Options: -h print this message diff --git a/tools/cmake/cmbuild b/tools/cmake/cmbuild index f9c5223048..f9e0f87390 100755 --- a/tools/cmake/cmbuild +++ b/tools/cmake/cmbuild @@ -9,7 +9,7 @@ MYARGS="" usage() { - echo "Usage: cmbuild [-v] [-h] [-C ] [-j ] [ [] ...]" >&2 + echo "Usage: cmbuild [-v] [-h] [-C ] [-j ] []" >&2 } help() -- GitLab From a7d2847140835283503d3bd75fe56488dc16c8b3 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2020 16:43:34 -0400 Subject: [PATCH 302/689] parse image flags only for valid numbers and requize imz == 0 for 2d-systems --- src/atom.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/atom.cpp b/src/atom.cpp index 1396eb596c..26fb6cc304 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -973,12 +973,19 @@ void Atom::data_atoms(int n, char *buf, tagint id_offset, tagint mol_offset, error->all(FLERR,"Incorrect atom format in data file"); } - if (imageflag) - imagedata = ((imageint) (atoi(values[iptr]) + IMGMAX) & IMGMASK) | - (((imageint) (atoi(values[iptr+1]) + IMGMAX) & IMGMASK) << IMGBITS) | - (((imageint) (atoi(values[iptr+2]) + IMGMAX) & IMGMASK) << IMG2BITS); - else imagedata = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; + int imx = 0; + int imy = 0; + int imz = 0; + if (imageflag) { + imx = utils::inumeric(FLERR,values[iptr],true,lmp); + imy = utils::inumeric(FLERR,values[iptr+1],true,lmp); + imz = utils::inumeric(FLERR,values[iptr+2],true,lmp); + if ((domain->dimension == 2) && (imz != 0)) + error->one(FLERR,"Z-direction image flag must be 0 for 2d-systems"); + } + imagedata = ((imageint) (imx + IMGMAX) & IMGMASK) | + (((imageint) (imy + IMGMAX) & IMGMASK) << IMGBITS) | + (((imageint) (imz + IMGMAX) & IMGMASK) << IMG2BITS); xdata[0] = atof(values[xptr]); xdata[1] = atof(values[xptr+1]); -- GitLab From dae2bce6b0e1a44bf6febf27258b09fac7bb1d99 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2020 16:53:22 -0400 Subject: [PATCH 303/689] we can use error->all() and also check the coordinate conversion for valid data --- src/atom.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/atom.cpp b/src/atom.cpp index 26fb6cc304..f2ee14291a 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -977,19 +977,19 @@ void Atom::data_atoms(int n, char *buf, tagint id_offset, tagint mol_offset, int imy = 0; int imz = 0; if (imageflag) { - imx = utils::inumeric(FLERR,values[iptr],true,lmp); - imy = utils::inumeric(FLERR,values[iptr+1],true,lmp); - imz = utils::inumeric(FLERR,values[iptr+2],true,lmp); + imx = utils::inumeric(FLERR,values[iptr],false,lmp); + imy = utils::inumeric(FLERR,values[iptr+1],false,lmp); + imz = utils::inumeric(FLERR,values[iptr+2],false,lmp); if ((domain->dimension == 2) && (imz != 0)) - error->one(FLERR,"Z-direction image flag must be 0 for 2d-systems"); + error->all(FLERR,"Z-direction image flag must be 0 for 2d-systems"); } imagedata = ((imageint) (imx + IMGMAX) & IMGMASK) | (((imageint) (imy + IMGMAX) & IMGMASK) << IMGBITS) | (((imageint) (imz + IMGMAX) & IMGMASK) << IMG2BITS); - xdata[0] = atof(values[xptr]); - xdata[1] = atof(values[xptr+1]); - xdata[2] = atof(values[xptr+2]); + xdata[0] = utils::numeric(FLERR,values[xptr],false,lmp); + xdata[1] = utils::numeric(FLERR,values[xptr+1],false,lmp); + xdata[2] = utils::numeric(FLERR,values[xptr+2],false,lmp); if (shiftflag) { xdata[0] += shift[0]; xdata[1] += shift[1]; -- GitLab From f1e03aefc6503423993ddcd329df6944ccbb7c64 Mon Sep 17 00:00:00 2001 From: Yaser Afshar Date: Tue, 17 Mar 2020 16:07:22 -0500 Subject: [PATCH 304/689] updating the pair potential docs, adding reference to OpenKIM --- doc/src/pair_adp.rst | 6 ++++-- doc/src/pair_eam.rst | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/doc/src/pair_adp.rst b/doc/src/pair_adp.rst index 6c4796fb85..bbfd98f677 100644 --- a/doc/src/pair_adp.rst +++ b/doc/src/pair_adp.rst @@ -56,8 +56,10 @@ command to specify them. * The NIST WWW site at http://www.ctcms.nist.gov/potentials. Note that ADP potentials obtained from NIST must be converted into the extended DYNAMO *setfl* format discussed below. -* The OpenKIM Project at https://openkim.org/browse/models/by-type provides - ADP potentials that can be used directly in LAMMPS with the :doc:`kim_commands interface `. +* The OpenKIM Project at + `https://openkim.org/browse/models/by-type `_ + provides ADP potentials that can be used directly in LAMMPS with the + :doc:`kim_commands ` interface. ---------- diff --git a/doc/src/pair_eam.rst b/doc/src/pair_eam.rst index 4710f8a9a1..7384a4d54c 100644 --- a/doc/src/pair_eam.rst +++ b/doc/src/pair_eam.rst @@ -149,6 +149,7 @@ potentials stored in DYNAMO or other formats: http://www.ctcms.nist.gov/potentials http://cst-www.nrl.navy.mil/ccm6/ap http://enpub.fulton.asu.edu/cms/potentials/main/main.htm + https://openkim.org These potentials should be usable with LAMMPS, though the alternate formats would need to be converted to the DYNAMO format used by LAMMPS @@ -156,6 +157,11 @@ and described on this page. The NIST site is maintained by Chandler Becker (cbecker at nist.gov) who is good resource for info on interatomic potentials and file formats. +The OpenKIM Project at +`https://openkim.org/browse/models/by-type `_ +provides EAM potentials that can be used directly in LAMMPS with the +:doc:`kim_commands ` interface. + ---------- For style *eam*\ , potential values are read from a file that is in the -- GitLab From 66f730b8958cf9193ac956a340118e4ecf551c48 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2020 18:53:10 -0400 Subject: [PATCH 305/689] setting const on return value has no effect --- src/USER-MEAMC/meam.h | 2 +- src/USER-MEAMC/meam_setup_done.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/USER-MEAMC/meam.h b/src/USER-MEAMC/meam.h index 719e1af6f0..b4f8fd341b 100644 --- a/src/USER-MEAMC/meam.h +++ b/src/USER-MEAMC/meam.h @@ -214,7 +214,7 @@ protected: void alloyparams(); void compute_pair_meam(); double phi_meam(double, int, int); - const double phi_meam_series(const double scrn, const int Z1, const int Z2, const int a, const int b, const double r, const double arat); + double phi_meam_series(const double scrn, const int Z1, const int Z2, const int a, const int b, const double r, const double arat); void compute_reference_density(); void get_tavref(double*, double*, double*, double*, double*, double*, double, double, double, double, double, double, double, int, int, lattice_t); diff --git a/src/USER-MEAMC/meam_setup_done.cpp b/src/USER-MEAMC/meam_setup_done.cpp index 8dfebe8ed5..acc1036c97 100644 --- a/src/USER-MEAMC/meam_setup_done.cpp +++ b/src/USER-MEAMC/meam_setup_done.cpp @@ -519,7 +519,7 @@ MEAM::phi_meam(double r, int a, int b) // To avoid nan values of phir due to rapid decrease of b2nn^n or/and // argument of phi_meam, i.e. r*arat^n, in some cases (3NN dia with low Cmin value) // -const double +double MEAM::phi_meam_series(const double scrn, const int Z1, const int Z2, const int a, const int b, const double r, const double arat) { double phi_sum = 0.0; -- GitLab From 1d8e9ca0141985bd1ec5ff507844e83d77f79de8 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2020 18:53:28 -0400 Subject: [PATCH 306/689] include gcc sanitizer libraries --- tools/singularity/centos8.def | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/singularity/centos8.def b/tools/singularity/centos8.def index b48979cab1..e0a14c4156 100644 --- a/tools/singularity/centos8.def +++ b/tools/singularity/centos8.def @@ -2,12 +2,12 @@ BootStrap: docker From: centos:8 %post - dnf -y install epel-release dnf-utils + dnf -y install epel-release dnf-utils dnf config-manager --set-enabled PowerTools dnf -y update - dnf -y install vim-enhanced ccache gcc-c++ gcc-gfortran clang gdb make cmake patch which file git libpng-devel libjpeg-devel openmpi-devel mpich-devel fftw-devel voro++-devel gsl-devel enchant platform-python-devel python3-virtualenv valgrind openblas ninja-build eigen3-devel + dnf -y install vim-enhanced ccache gcc-c++ gcc-gfortran clang gdb make cmake patch which file git libpng-devel libjpeg-devel openmpi-devel mpich-devel fftw-devel voro++-devel gsl-devel enchant platform-python-devel python3-virtualenv valgrind openblas ninja-build eigen3-devel libubsan libasan libtsan #No match for argument: valgrind-openmpi %labels - Author akohlmey + Author akohlmey -- GitLab From c1268bd1ec6ab721510bb652cd333b0dd369096b Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2020 18:55:05 -0400 Subject: [PATCH 307/689] remove dead code --- src/USER-MEAMC/meam_setup_done.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/USER-MEAMC/meam_setup_done.cpp b/src/USER-MEAMC/meam_setup_done.cpp index acc1036c97..1cefc7e758 100644 --- a/src/USER-MEAMC/meam_setup_done.cpp +++ b/src/USER-MEAMC/meam_setup_done.cpp @@ -163,11 +163,10 @@ MEAM::alloyparams(void) void MEAM::compute_pair_meam(void) { - - double r, b2nn, phi_val; + double r; int j, a, b, nv2; double astar, frac, phizbl; - int n, Z1, Z2; + int Z1, Z2; double arat, rarat, scrn, scrn2; double phiaa, phibb /*unused:,phitmp*/; double C, s111, s112, s221, S11, S22; @@ -320,7 +319,7 @@ MEAM::phi_meam(double r, int a, int b) double Eu; double arat, scrn, scrn2; int Z12, errorflag; - int n, Z1nn, Z2nn; + int Z1nn, Z2nn; lattice_t latta /*unused:,lattb*/; double rho_bkgd1, rho_bkgd2; double b11s, b22s; -- GitLab From 4a5125f4501cd1880f9b5386b43da7102bc16c86 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2020 19:16:02 -0400 Subject: [PATCH 308/689] make behavior of CMAKE_TUNE_FLAGS more consistent and allow to turn it off --- cmake/CMakeLists.txt | 28 +++++++++++++++------------- doc/src/Build_basics.rst | 3 ++- doc/src/Build_development.rst | 35 ++++++++++++++++++++++++----------- 3 files changed, 41 insertions(+), 25 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 18c6068a13..62829c44b6 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -51,33 +51,34 @@ check_for_autogen_files(${LAMMPS_SOURCE_DIR}) include(CheckCCompilerFlag) include(CheckIncludeFileCXX) +# set required compiler flags and compiler/CPU arch specific optimizations if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Intel") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -restrict") - if (NOT CMAKE_TUNE_FLAGS) - if(CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.3 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.4) - set(CMAKE_TUNE_FLAGS "-xCOMMON-AVX512") - else() - set(CMAKE_TUNE_FLAGS "-xHost") - endif() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -restrict") + if(CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.3 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.4) + set(CMAKE_TUNE_DEFAULT "-xCOMMON-AVX512") + else() + set(CMAKE_TUNE_DEFAULT "-xHost") endif() endif() if(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") - if(NOT CMAKE_TUNE_FLAGS) - set (CMAKE_TUNE_FLAGS "-ffast-math -march=native") - endif() + set(CMAKE_TUNE_DEFAULT "-ffast-math -march=native") +endif() + +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") + set(CMAKE_TUNE_DEFAULT "-ffast-math -march=native") endif() # we require C++11 set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) -# GNU compiler features +# GNU compiler specific features for testing if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") - option(ENABLE_COVERAGE "Enable code coverage" OFF) + option(ENABLE_COVERAGE "Enable collecting code coverage data" OFF) mark_as_advanced(ENABLE_COVERAGE) if(ENABLE_COVERAGE) - set (CMAKE_TUNE_FLAGS "--coverage") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage") endif() endif() @@ -339,6 +340,7 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") list(APPEND LAMMPS_LINK_LIBS -lwsock32 -lpsapi) endif() +set(CMAKE_TUNE_FLAGS "${CMAKE_TUNE_DEFAULT}" CACHE STRING "Compiler specific optimization or instrumentation") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_TUNE_FLAGS}") if(CMAKE_Fortran_FLAGS) set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${CMAKE_TUNE_FLAGS}") diff --git a/doc/src/Build_basics.rst b/doc/src/Build_basics.rst index 7349b3a7ea..8ad48b0810 100644 --- a/doc/src/Build_basics.rst +++ b/doc/src/Build_basics.rst @@ -218,7 +218,8 @@ flags to tune for optimal performance on given hosts. By default these are initialized to some compiler specific flags, where known, to optimize the LAMMPS executable with optimizations and instructions available on the host where LAMMPS is compiled. For example, for Intel compilers this would be -``-xHost`` and for GNU compilers this would be ``-march=native``. +``-xHost`` and for GNU compilers this would be ``-march=native``. To turn +these flags off, set ``-D CMAKE_TUNE_FLAGS=``. .. note:: diff --git a/doc/src/Build_development.rst b/doc/src/Build_development.rst index 722f436063..598153e3f0 100644 --- a/doc/src/Build_development.rst +++ b/doc/src/Build_development.rst @@ -2,7 +2,7 @@ Development build options (CMake only) ====================================== The CMake build of LAMMPS has a few extra options which are useful during -development, testing or debugging. +development, testing or debugging. ---------- @@ -25,6 +25,12 @@ Another way of doing this without reconfiguration is calling make with variable make VERBOSE=1 +Or when using the :ref:`"cmbuild" wrapper script `: + +.. code-block:: bash + + cmbuild -v + ---------- .. _sanitizer: @@ -32,20 +38,27 @@ Another way of doing this without reconfiguration is calling make with variable Address, Undefined Behavior, and Thread Sanitizer Support ------------------------------------------------------------------------- -Compilers such as GCC and Clang support generating binaries which use different -sanitizers to detect problems in code during run-time. They can detect `memory leaks `_, -code that runs into `undefined behavior `_ of the -language and `data races `_ in threaded code. +Compilers such as GCC and Clang support generating instrumented binaries +which use different sanitizer libraries to detect problems in code +during run-time. They can detect issues like: + + - `memory leaks `_ + - `undefined behavior `_ + - `data races `_ -The following settings allow you enable these features if your compiler supports -it. Please note that they come with a performance hit. However, they are -usually faster than using tools like Valgrind. +Please note that this kind of instrumentation usually comes with a small +performance hit (much less than using tools like `Valgrind `_). +The to enable these features additional compiler flags need to be added +to the compilation and linking stages. This is most easily done through +setting the ``CMAKE_TUNE_FLAGS`` variable during configuration. Examples: .. code-block:: bash - -D ENABLE_SANITIZE_ADDRESS=value # enable Address Sanitizer, value = no (default) or yes - -D ENABLE_SANITIZE_UNDEFINED=value # enable Undefined Behaviour Sanitizer, value = no (default) or yes - -D ENABLE_SANITIZE_THREAD=value # enable Thread Sanitizer, value = no (default) or yes + -D CMAKE_TUNE_FLAGS=-fsanitize=address # enable address sanitizer / memory leak checker + -D CMAKE_TUNE_FLAGS=-fsanitize=undefined # enable undefined behaviour sanitizer + -D CMAKE_TUNE_FLAGS=-fsanitize=thread # enable thread sanitizer + +.. _valgrind: https://valgrind.org ---------- -- GitLab From da0acd27902d4631529cf2b610beba9696433e19 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2020 19:28:30 -0400 Subject: [PATCH 309/689] update spelling false positives --- doc/utils/sphinx-config/false_positives.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index 264c3fab50..31fa0a5edf 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -2553,8 +2553,7 @@ Salles sandia Sandia sandybrown -Sanitizer -sanitizers +sanitizer Sanyal sc scafacos -- GitLab From e000c46c8c5a4f01027ce80e3343a80c0ddf08cc Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2020 20:29:18 -0400 Subject: [PATCH 310/689] correct spelling --- lib/kokkos/containers/src/Kokkos_Vector.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/kokkos/containers/src/Kokkos_Vector.hpp b/lib/kokkos/containers/src/Kokkos_Vector.hpp index fb71f476c6..a44d1f58b5 100644 --- a/lib/kokkos/containers/src/Kokkos_Vector.hpp +++ b/lib/kokkos/containers/src/Kokkos_Vector.hpp @@ -110,7 +110,7 @@ public: void assign (size_t n, const Scalar& val) { - /* Resize if necessary (behaviour of std:vector) */ + /* Resize if necessary (behavior of std:vector) */ if(n>span()) DV::resize(size_t (n*_extra_storage)); @@ -177,7 +177,7 @@ public: const_reference back() const {return DV::h_view(_size - 1);} - /* std::algorithms witch work originally with iterators, here they are implemented as member functions */ + /* std::algorithms which work originally with iterators, here they are implemented as member functions */ size_t lower_bound (const size_t& start, -- GitLab From 7f53cbc1a03c6e7ef7c75642291b9b6761f8603f Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2020 20:33:37 -0400 Subject: [PATCH 311/689] fix grammar issue --- lib/poems/poemstree.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/poems/poemstree.h b/lib/poems/poemstree.h index d330fdad26..70750d4019 100644 --- a/lib/poems/poemstree.h +++ b/lib/poems/poemstree.h @@ -575,8 +575,8 @@ TreeNode *Tree::CopyTree(TreeNode *t) } -// us the postorder scanning algorithm to traverse the nodes in -// the tree and delete each node as the visit operation +// use the postorder scanning algorithm to traverse the nodes in +// the tree and delete each node at the visit operation void Tree::DeleteTree(TreeNode *t) { if (t != NULL) { -- GitLab From 0e764a3a48e8a1687055554b01a7b85edb4ac38f Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2020 20:37:33 -0400 Subject: [PATCH 312/689] correct spelling correction --- src/SRD/fix_srd.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SRD/fix_srd.cpp b/src/SRD/fix_srd.cpp index cb193356d8..c57975ad4c 100644 --- a/src/SRD/fix_srd.cpp +++ b/src/SRD/fix_srd.cpp @@ -454,7 +454,7 @@ void FixSRD::setup(int /*vflag*/) setup_search_stencil(); } else nbins2 = 0; - // perform first binding of SRD and big particles and walls + // perform first binning of SRD and big particles and walls // set reneighflag to turn off SRD rotation // don't do SRD rotation in setup, only during timestepping -- GitLab From 9ebd1e4572e2f84bd952ccee9a0836266325798c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2020 20:41:49 -0400 Subject: [PATCH 313/689] convert british spelling to american --- src/compute_cna_atom.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compute_cna_atom.cpp b/src/compute_cna_atom.cpp index c11f4016b5..5f0f047958 100644 --- a/src/compute_cna_atom.cpp +++ b/src/compute_cna_atom.cpp @@ -142,7 +142,7 @@ void ComputeCNAAtom::compute_peratom() numneigh = list->numneigh; firstneigh = list->firstneigh; - // find the neighbours of each atom within cutoff using full neighbor list + // find the neighbors of each atom within cutoff using full neighbor list // nearest[] = atom indices of nearest neighbors, up to MAXNEAR // do this for all atoms, not just compute group // since CNA calculation requires neighbors of neighbors -- GitLab From 5109b7f1b173f686df1e762536598838e224199c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2020 20:45:52 -0400 Subject: [PATCH 314/689] correct incorrect spelling correction --- tools/polybond/lmpsdata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/polybond/lmpsdata.py b/tools/polybond/lmpsdata.py index 338090ed34..49e0d32544 100644 --- a/tools/polybond/lmpsdata.py +++ b/tools/polybond/lmpsdata.py @@ -3,7 +3,7 @@ # lmpsdata.py # # For reading, writing and manipulating lammps data files -# For calculation of certain proprieties using lammps data files +# For calculation of certain properties using lammps data files # For creating VMD input text files using lammps data files # All x,y,z calculations assume the information includes image flags -- GitLab From d8a948d9b75bc21cb174e85a91070438a20416db Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2020 21:13:03 -0400 Subject: [PATCH 315/689] correct spelling --- doc/src/kim_commands.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/kim_commands.rst b/doc/src/kim_commands.rst index aca2529ec7..99f7efffd5 100644 --- a/doc/src/kim_commands.rst +++ b/doc/src/kim_commands.rst @@ -49,7 +49,7 @@ Syntax on the prefix specified in *variable* and a number appended to indicate which element in the list of values is in the variable. *explicit* = returns the values separately in one more more variable names - provided as arguments that preceed *formatarg*\ . [default for *kim_param*] + provided as arguments that precede *formatarg*\ . [default for *kim_param*] * query_function = name of the OpenKIM web API query function to be used * queryargs = a series of *keyword=value* pairs that represent the web query; supported keywords depend on the query function -- GitLab From 5992bd24e7c900d9d899d37e84ea306042dc43dd Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 18 Mar 2020 00:27:14 -0400 Subject: [PATCH 316/689] some more converted atc fix_modify docs --- doc/src/atc_mesh_output.rst | 47 +++++++++++++++++++++++ doc/src/atc_output.rst | 2 + doc/src/atc_output_boundary_integral.rst | 47 +++++++++++++++++++++++ doc/src/atc_output_contour_integral.rst | 48 +++++++++++++++++++++++ doc/src/atc_output_nodeset.rst | 49 ++++++++++++++++++++++++ doc/src/atc_output_volume_integral.rst | 47 +++++++++++++++++++++++ doc/src/atc_read_restart.rst | 48 +++++++++++++++++++++++ doc/src/atc_write_restart.rst | 47 +++++++++++++++++++++++ doc/src/fix_atc.rst | 18 ++++----- 9 files changed, 344 insertions(+), 9 deletions(-) create mode 100644 doc/src/atc_mesh_output.rst create mode 100644 doc/src/atc_output_boundary_integral.rst create mode 100644 doc/src/atc_output_contour_integral.rst create mode 100644 doc/src/atc_output_nodeset.rst create mode 100644 doc/src/atc_output_volume_integral.rst create mode 100644 doc/src/atc_read_restart.rst create mode 100644 doc/src/atc_write_restart.rst diff --git a/doc/src/atc_mesh_output.rst b/doc/src/atc_mesh_output.rst new file mode 100644 index 0000000000..63756df98e --- /dev/null +++ b/doc/src/atc_mesh_output.rst @@ -0,0 +1,47 @@ +.. index:: fix_modify AtC mesh output + +fix_modify AtC mesh output command +================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify mesh output + +* AtC fixID = ID of :doc:`fix atc ` instance +* mesh output = name of the AtC sub-command +* file_prefix = prefix of various generated output files + + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC mesh output meshData + + +Description +""""""""""" + +Command to output mesh and associated data: nodesets, facesets, and +elementsets. This data is only output once upon initialization since +currently the mesh is static. Creates binary (EnSight, "gold" format) +output of mesh data. + +Restrictions +"""""""""""" + +None. + +Related AtC commands +"""""""""""""""""""" + +- :ref:`fix_modify AtC command overview ` + +Default +""""""" + +None. diff --git a/doc/src/atc_output.rst b/doc/src/atc_output.rst index 699449b981..3fb1491be1 100644 --- a/doc/src/atc_output.rst +++ b/doc/src/atc_output.rst @@ -16,11 +16,13 @@ Syntax * filename_prefix = prefix for data files (for *output*) * frequency = frequency of output in time-steps (for *output*) * optional keywords for *output*: + - text = creates text output of index, step and nodal variable values for unique nodes - full_text = creates text output index, nodal id, step, nodal coordinates and nodal variable values for unique and image nodes - binary = creates binary EnSight output - vector_components = outputs vectors as scalar components - tensor_components = outputs tensor as scalar components (for use with ParaView) + * *step* or *time* = index output by step or by time (for *output index*) diff --git a/doc/src/atc_output_boundary_integral.rst b/doc/src/atc_output_boundary_integral.rst new file mode 100644 index 0000000000..71a3e03ac2 --- /dev/null +++ b/doc/src/atc_output_boundary_integral.rst @@ -0,0 +1,47 @@ +.. index:: fix_modify AtC output boundary_integral + +fix_modify AtC output boundary_integral command +=============================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify output boundary_integral faceset [name] + +* AtC fixID = ID of :doc:`fix atc ` instance +* output boundary_integral = name of the AtC sub-command +* fieldname = name of hardy field +* faceset = required keyword +* name= name of faceset + + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC output boundary_integral stress faceset loop1 + + +Description +""""""""""" + +Calculates a surface integral of the given field dotted with the outward +normal of the faces and puts output in the "GLOBALS" file. + +Restrictions +"""""""""""" + +Must be used with the hardy/field type of :doc:`fix atc ` + +Related AtC commands +"""""""""""""""""""" + +- :ref:`fix_modify AtC command overview ` + +Default +""""""" + +None. diff --git a/doc/src/atc_output_contour_integral.rst b/doc/src/atc_output_contour_integral.rst new file mode 100644 index 0000000000..24678ef6cc --- /dev/null +++ b/doc/src/atc_output_contour_integral.rst @@ -0,0 +1,48 @@ +.. index:: fix_modify AtC output contour_integral + +fix_modify AtC output contour_integral command +============================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify output contour_integral faceset [axis [x|y|z]] + +* AtC fixID = ID of :doc:`fix atc ` instance +* output contour_integral = name of the AtC sub-command +* fieldname = name of hardy field +* faceset = required keyword +* name = name of faceset +* *axis x* or *axis y* or *axis z* = (optional) + + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC output contour_integral stress faceset loop1 + + +Description +""""""""""" + +Calculates a surface integral of the given field dotted with the outward +normal of the faces and puts output in the "GLOBALS" file. + +Restrictions +"""""""""""" + +Must be used with the hardy/field type of :doc:`fix atc ` + +Related AtC commands +"""""""""""""""""""" + +- :ref:`fix_modify AtC command overview ` + +Default +""""""" + +None. diff --git a/doc/src/atc_output_nodeset.rst b/doc/src/atc_output_nodeset.rst new file mode 100644 index 0000000000..eb12a2344e --- /dev/null +++ b/doc/src/atc_output_nodeset.rst @@ -0,0 +1,49 @@ +.. index:: fix_modify AtC output nodeset + +fix_modify AtC output nodeset command +===================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify output nodeset + +* AtC fixID = ID of :doc:`fix atc ` instance +* output nodeset = name of the AtC sub-command +* nodeset_name= name of nodeset to be operated on +* operation = *sum* + + * *sum* = creates nodal sum over nodes in specified nodeset + + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC output nodeset nset1 sum + + +Description +""""""""""" + +Performs operation over the nodes belonging to specified nodeset and +outputs resulting variable values to GLOBALS file. + +Restrictions +"""""""""""" + +None. + +Related AtC commands +"""""""""""""""""""" + +- :ref:`fix_modify AtC command overview ` +- :doc:`fix atc command ` + +Default +""""""" + +None. diff --git a/doc/src/atc_output_volume_integral.rst b/doc/src/atc_output_volume_integral.rst new file mode 100644 index 0000000000..464d43cbce --- /dev/null +++ b/doc/src/atc_output_volume_integral.rst @@ -0,0 +1,47 @@ +.. index:: fix_modify AtC output volume_integral + +fix_modify AtC output volume_integral command +============================================= + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify output volume_integral + +* AtC fixID = ID of :doc:`fix atc ` instance +* output volume_integral = name of the AtC sub-command +* elementset_name= name of elementset to be integrated over +* fieldname = name of field to integrate + + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC output volume_integral eset1 mass_density + + +Description +""""""""""" + +Performs volume integration of specified field over elementset and +outputs resulting variable values to GLOBALS file. + +Restrictions +"""""""""""" + +None. + +Related AtC commands +"""""""""""""""""""" + +- :ref:`fix_modify AtC command overview ` +- :doc:`fix atc command ` + +Default +""""""" + +None. diff --git a/doc/src/atc_read_restart.rst b/doc/src/atc_read_restart.rst new file mode 100644 index 0000000000..11ba4519a4 --- /dev/null +++ b/doc/src/atc_read_restart.rst @@ -0,0 +1,48 @@ +.. index:: fix_modify AtC read_restart + +fix_modify AtC read_restart command +=================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify read_restart + +* AtC fixID = ID of :doc:`fix atc ` instance +* read_restart = name of the AtC sub-command +* file_name = name of AtC restart file + + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC read_restart restart.mydata.AtC + + +Description +""""""""""" + +Reads the current state of the AtC fields from a named text-based restart file. + +Restrictions +"""""""""""" + +The restart file only contains fields and their time derivatives. The +reference positions of the atoms and the commands that initialize the +fix are not saved e.g. an identical mesh containing the same atoms will +have to be recreated. + +Related AtC commands +"""""""""""""""""""" + +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC write_restart ` + +Default +""""""" + +None. diff --git a/doc/src/atc_write_restart.rst b/doc/src/atc_write_restart.rst new file mode 100644 index 0000000000..e4f19dea10 --- /dev/null +++ b/doc/src/atc_write_restart.rst @@ -0,0 +1,47 @@ +.. index:: fix_modify AtC write_restart + +fix_modify AtC write_restart command +==================================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify write_restart + +* AtC fixID = ID of :doc:`fix atc ` instance +* write_restart = name of the AtC sub-command +* file_name = name of AtC restart file + + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC write_restart restart.mydata.AtC + + +Description +""""""""""" + +Dumps the current state of the fields to a named text-based restart +file. This done when the command is invoked and not repeated, unlike +the otherwise similar LAMMPS command. + +Restrictions +"""""""""""" + +None. + +Related AtC commands +"""""""""""""""""""" + +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC read_restart ` + +Default +""""""" + +None. diff --git a/doc/src/fix_atc.rst b/doc/src/fix_atc.rst index 479adba548..cffbab3fc1 100644 --- a/doc/src/fix_atc.rst +++ b/doc/src/fix_atc.rst @@ -18,8 +18,8 @@ Syntax *thermal* = thermal coupling with fields: temperature *two_temperature* = electron-phonon coupling with field: temperature and electron_temperature - *hardy* = on-the-fly post-processing using kernel localization functions (see "related" section for possible fields) - *field* = on-the-fly post-processing using mesh-based localization functions (see "related" section for possible fields) + *hardy* = on-the-fly post-processing using kernel localization functions + *field* = on-the-fly post-processing using mesh-based localization functions * parameter_file = name of the file with material parameters. Note: Neither hardy nor field requires a parameter file @@ -196,13 +196,13 @@ conditions. *fix_modify* commands for output: * :doc:`fix_modify AtC output ` -* `fix_modify AtC output nodeset `_ -* `fix_modify AtC output elementset `_ -* `fix_modify AtC output boundary_integral `_ -* `fix_modify AtC output contour_integral `_ -* `fix_modify AtC mesh output `_ -* `fix_modify AtC write_restart `_ -* `fix_modify AtC read_restart `_ +* :doc:`fix_modify AtC output nodeset ` +* :doc:`fix_modify AtC output volume_integral ` +* :doc:`fix_modify AtC output boundary_integral ` +* :doc:`fix_modify AtC output contour_integral ` +* :doc:`fix_modify AtC mesh output ` +* :doc:`fix_modify AtC write_restart ` +* :doc:`fix_modify AtC read_restart ` *fix_modify* commands for post-processing: -- GitLab From f1679cd58c1ea8383032b7b8b7bf3681999cb5f8 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 18 Mar 2020 06:37:51 -0400 Subject: [PATCH 317/689] update false positives --- doc/utils/sphinx-config/false_positives.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index 0837fbee9e..0449c0707b 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -747,6 +747,7 @@ electronegativity Eleftheriou ElementN elementset +elementsets elif Elj Ellad @@ -850,6 +851,7 @@ exy ey ez faceset +facesets factorizable factorizations Fahrenberger @@ -890,6 +892,7 @@ fhg Fi Fichthorn Fickian +fieldname figshare Fij filelink @@ -1988,6 +1991,7 @@ nocite nocoeff nodeless nodeset +nodesets Noehring noforce Noid -- GitLab From 38b1bf9ba5d6271e00d65dae9969b622c867d9d2 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 18 Mar 2020 07:01:06 -0400 Subject: [PATCH 318/689] add links to ctypes, ipython, and jupyter --- doc/src/Build_link.rst | 4 +++- doc/src/Howto_pylammps.rst | 34 +++++++++++++++++++--------------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/doc/src/Build_link.rst b/doc/src/Build_link.rst index 64c890d8ec..b18dc49e38 100644 --- a/doc/src/Build_link.rst +++ b/doc/src/Build_link.rst @@ -240,9 +240,11 @@ C-style interface, provided in src/library.cpp and src/library.h. See the :doc:`Python library ` doc page for a description of the Python interface to LAMMPS, which wraps the C-style -interface from a shared library through the ctypes python module. +interface from a shared library through the `ctypes python module `_. See the sample codes in examples/COUPLE/simple for examples of C++ and C and Fortran codes that invoke LAMMPS through its library interface. Other examples in the COUPLE directory use coupling ideas discussed on the :doc:`Howto couple ` doc page. + +.. _ctypes: https://docs.python.org/3/library/ctypes.html diff --git a/doc/src/Howto_pylammps.rst b/doc/src/Howto_pylammps.rst index e1694e2062..96d9acd994 100644 --- a/doc/src/Howto_pylammps.rst +++ b/doc/src/Howto_pylammps.rst @@ -6,19 +6,23 @@ PyLammps Tutorial Overview -------- -PyLammps is a Python wrapper class which can be created on its own or -use an existing lammps Python object. It creates a simpler, -Python-like interface to common LAMMPS functionality, in contrast to -the lammps.py wrapper on the C-style LAMMPS library interface which is -written using Python ctypes. The lammps.py wrapper is discussed on -the :doc:`Python library ` doc page. - -Unlike the flat ctypes interface, PyLammps exposes a discoverable API. -It no longer requires knowledge of the underlying C++ code -implementation. Finally, the IPyLammps wrapper builds on top of -PyLammps and adds some additional features for IPython integration -into IPython notebooks, e.g. for embedded visualization output from -dump/image. +``PyLammps`` is a Python wrapper class for LAMMPS which can be created +on its own or use an existing lammps Python object. It creates a simpler, +more "pythonic" interface to common LAMMPS functionality, in contrast to +the ``lammps.py`` wrapper for the C-style LAMMPS library interface which +is written using `Python ctypes `_. The ``lammps.py`` wrapper +is discussed on the :doc:`Python library ` doc page. + +Unlike the flat ``ctypes`` interface, PyLammps exposes a discoverable +API. It no longer requires knowledge of the underlying C++ code +implementation. Finally, the ``IPyLammps`` wrapper builds on top of +``PyLammps`` and adds some additional features for +`IPython integration `_ into `Jupyter notebooks `_, +e.g. for embedded visualization output from :doc:`dump style image `. + +.. _ctypes: https://docs.python.org/3/library/ctypes.html +.. _ipython: https://ipython.org/ +.. _jupyter: https://jupyter.org/ Comparison of lammps and PyLammps interfaces ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +30,7 @@ Comparison of lammps and PyLammps interfaces lammps.lammps """"""""""""" -* uses C-Types +* uses ``ctypes`` * direct memory access to native C++ data * provides functions to send and receive data to LAMMPS * requires knowledge of how LAMMPS internally works (C pointers, etc) @@ -34,7 +38,7 @@ lammps.lammps lammps.PyLammps """"""""""""""" -* higher-level abstraction built on top of original C-Types interface +* higher-level abstraction built on top of original ctypes interface * manipulation of Python objects * communication with LAMMPS is hidden from API user * shorter, more concise Python -- GitLab From 280d5cc6ae56be58dc49dfa159ba281d39b282ae Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 18 Mar 2020 07:02:34 -0400 Subject: [PATCH 319/689] replace "xxxn't" with "xxx not" --- doc/src/Errors_common.rst | 6 +++--- doc/src/Errors_messages.rst | 30 +++++++++++++++--------------- doc/src/Howto_github.rst | 2 +- doc/src/Modify_overview.rst | 2 +- doc/src/Python_shlib.rst | 2 +- doc/src/compute_adf.rst | 2 +- doc/src/compute_rdf.rst | 2 +- doc/src/create_atoms.rst | 2 +- doc/src/dump.rst | 2 +- doc/src/dump_modify.rst | 2 +- doc/src/fix_atom_swap.rst | 2 +- doc/src/fix_ehex.rst | 2 +- doc/src/fix_heat.rst | 2 +- doc/src/fix_spring.rst | 2 +- doc/src/if.rst | 2 +- doc/src/molecule.rst | 2 +- doc/src/neigh_modify.rst | 2 +- doc/src/package.rst | 2 +- doc/src/pair_agni.rst | 2 +- doc/src/pair_airebo.rst | 2 +- doc/src/pair_comb.rst | 2 +- doc/src/pair_drip.rst | 2 +- doc/src/pair_edip.rst | 2 +- doc/src/pair_gw.rst | 2 +- doc/src/pair_lcbop.rst | 2 +- doc/src/pair_reaxc.rst | 4 ++-- doc/src/pair_sw.rst | 2 +- doc/src/pair_tersoff.rst | 2 +- doc/src/pair_tersoff_mod.rst | 2 +- doc/src/pair_tersoff_zbl.rst | 2 +- doc/src/pair_vashishta.rst | 2 +- doc/src/read_data.rst | 2 +- doc/src/read_restart.rst | 2 +- doc/src/rerun.rst | 2 +- 34 files changed, 51 insertions(+), 51 deletions(-) diff --git a/doc/src/Errors_common.rst b/doc/src/Errors_common.rst index 603952a29d..34567db385 100644 --- a/doc/src/Errors_common.rst +++ b/doc/src/Errors_common.rst @@ -38,7 +38,7 @@ input script command that it was processing. Of course, LAMMPS cannot figure out your physics or numerical mistakes, like choosing too big a timestep, specifying erroneous force field coefficients, or putting 2 atoms on top of each other! If you run into errors that LAMMPS -doesn't catch that you think it should flag, please send an email to +does not catch that you think it should flag, please send an email to the `developers `_. If you get an error message about an invalid command in your input @@ -96,13 +96,13 @@ cases: LAMMPS runs in the available memory a processor allows to be allocated. Most reasonable MD runs are compute limited, not memory -limited, so this shouldn't be a bottleneck on most platforms. Almost +limited, so this should not be a bottleneck on most platforms. Almost all large memory allocations in the code are done via C-style malloc's which will generate an error message if you run out of memory. Smaller chunks of memory are allocated via C++ "new" statements. If you are unlucky you could run out of memory just when one of these small requests is made, in which case the code will crash or hang (in -parallel), since LAMMPS doesn't trap on those errors. +parallel), since LAMMPS does not trap on those errors. Illegal arithmetic can cause LAMMPS to run slow or crash. This is typically due to invalid physics and numerics that your simulation is diff --git a/doc/src/Errors_messages.rst b/doc/src/Errors_messages.rst index 82c9d0bd78..7ef4886acc 100644 --- a/doc/src/Errors_messages.rst +++ b/doc/src/Errors_messages.rst @@ -2174,7 +2174,7 @@ Doc page with :doc:`WARNING messages ` The command is accessing a vector added by the fix property/atom command, that does not exist. -*Compute property/atom for atom property that isn't allocated* +*Compute property/atom for atom property that is not allocated* Self-explanatory. *Compute property/atom integer vector does not exist* @@ -2191,7 +2191,7 @@ Doc page with :doc:`WARNING messages ` *Compute property/local does not (yet) work with atom_style template* Self-explanatory. -*Compute property/local for property that isn't allocated* +*Compute property/local for property that is not allocated* Self-explanatory. *Compute rdf requires a pair style be defined* @@ -3091,7 +3091,7 @@ Doc page with :doc:`WARNING messages ` *Dump_modify region ID does not exist* Self-explanatory. -*Dumping an atom property that isn't allocated* +*Dumping an atom property that is not allocated* The chosen atom style does not define the per-atom quantity being dumped. @@ -3117,7 +3117,7 @@ Doc page with :doc:`WARNING messages ` *Energy was not tallied on needed timestep* You are using a thermo keyword that requires potentials to - have tallied energy, but they didn't on this timestep. See the + have tallied energy, but they did not on this timestep. See the variable doc page for ideas on how to make this work. *Epsilon or sigma reference not set by pair style in PPPMDisp* @@ -4125,7 +4125,7 @@ Doc page with :doc:`WARNING messages ` Fixes that calculate global or local quantities cannot be used with fix store/state. -*Fix store/state for atom property that isn't allocated* +*Fix store/state for atom property that is not allocated* Self-explanatory. *Fix store/state variable is not atom-style variable* @@ -4719,7 +4719,7 @@ Doc page with :doc:`WARNING messages ` *Invalid LAMMPS restart file* The file does not appear to be a LAMMPS restart file since - it doesn't contain the correct magic string at the beginning. + it does not contain the correct magic string at the beginning. *Invalid Masses section in molecule file* Self-explanatory. @@ -6392,7 +6392,7 @@ keyword to allow for additional bonds to be formed *Pair hybrid sub-style does not support single call* You are attempting to invoke a single() call on a pair style - that doesn't support it. + that does not support it. *Pair hybrid sub-style is not used* No pair_coeff command used a sub-style specified in the pair_style @@ -6866,7 +6866,7 @@ keyword to allow for additional bonds to be formed *Per-atom energy was not tallied on needed timestep* You are using a thermo keyword that requires potentials to - have tallied energy, but they didn't on this timestep. See the + have tallied energy, but they did not on this timestep. See the variable doc page for ideas on how to make this work. *Per-atom fix in equal-style variable formula* @@ -6874,7 +6874,7 @@ keyword to allow for additional bonds to be formed *Per-atom virial was not tallied on needed timestep* You are using a thermo keyword that requires potentials to have - tallied the virial, but they didn't on this timestep. See the + tallied the virial, but they did not on this timestep. See the variable doc page for ideas on how to make this work. *Per-processor system is too big* @@ -7035,7 +7035,7 @@ keyword to allow for additional bonds to be formed It cannot be larger than the size of atom IDs, e.g. the maximum 32-bit integer. -*Read dump of atom property that isn't allocated* +*Read dump of atom property that is not allocated* Self-explanatory. *Read rerun dump file timestep > specified stop* @@ -7196,7 +7196,7 @@ keyword to allow for additional bonds to be formed creates one large file for all processors. *Restart file byte ordering is not recognized* - The file does not appear to be a LAMMPS restart file since it doesn't + The file does not appear to be a LAMMPS restart file since it does not contain a recognized byte-ordering flag at the beginning. *Restart file byte ordering is swapped* @@ -7666,7 +7666,7 @@ keyword to allow for additional bonds to be formed Keywords that refer to time (such as cpu, elapsed) do not make sense in between runs. -*Threshhold for an atom property that isn't allocated* +*Threshhold for an atom property that is not allocated* A dump threshold has been requested on a quantity that is not defined by the atom style used in this simulation. @@ -8320,7 +8320,7 @@ keyword to allow for additional bonds to be formed *Variable name must be alphanumeric or underscore characters* Self-explanatory. -*Variable uses atom property that isn't allocated* +*Variable uses atom property that is not allocated* Self-explanatory. *Velocity command before simulation box is defined* @@ -8361,7 +8361,7 @@ keyword to allow for additional bonds to be formed *Virial was not tallied on needed timestep* You are using a thermo keyword that requires potentials to - have tallied the virial, but they didn't on this timestep. See the + have tallied the virial, but they did not on this timestep. See the variable doc page for ideas on how to make this work. *Voro++ error: narea and neigh have a different size* @@ -8388,7 +8388,7 @@ keyword to allow for additional bonds to be formed This is because LAMMPS does not compute the Lennard-Jones interactions with these particles for efficiency reasons. -*World variable count doesn't match # of partitions* +*World variable count does not match # of partitions* A world-style variable must specify a number of values equal to the number of processor partitions. diff --git a/doc/src/Howto_github.rst b/doc/src/Howto_github.rst index 55db356589..795af96e0a 100644 --- a/doc/src/Howto_github.rst +++ b/doc/src/Howto_github.rst @@ -360,7 +360,7 @@ It looks something like this: .. image:: JPG/tutorial_reverse_pull_request.png :align: center -For some reason, the highlighted button didn't work in my case, but I +For some reason, the highlighted button did not work in my case, but I can go to my own repository and merge the pull request from there: .. image:: JPG/tutorial_reverse_pull_request2.png diff --git a/doc/src/Modify_overview.rst b/doc/src/Modify_overview.rst index 2deceae7db..3ec05c4ddd 100644 --- a/doc/src/Modify_overview.rst +++ b/doc/src/Modify_overview.rst @@ -22,7 +22,7 @@ src directory and re-building LAMMPS. The advantage of C++ and its object-orientation is that all the code and variables needed to define the new feature are in the 2 files you -write, and thus shouldn't make the rest of LAMMPS more complex or +write, and thus should not make the rest of LAMMPS more complex or cause side-effect bugs. Here is a concrete example. Suppose you write 2 files pair_foo.cpp diff --git a/doc/src/Python_shlib.rst b/doc/src/Python_shlib.rst index bd1d559359..0c86362e12 100644 --- a/doc/src/Python_shlib.rst +++ b/doc/src/Python_shlib.rst @@ -66,7 +66,7 @@ CMAKE_INSTALL_PREFIX. make install This will also install the Python module into your virtualenv. Since virtualenv -doesn't change your LD_LIBRARY_PATH, you still need to add its lib64 folder to +does not change your LD_LIBRARY_PATH, you still need to add its lib64 folder to it, which contains the installed liblammps.so. .. code-block:: bash diff --git a/doc/src/compute_adf.rst b/doc/src/compute_adf.rst index c0d754d883..a9375fa038 100644 --- a/doc/src/compute_adf.rst +++ b/doc/src/compute_adf.rst @@ -209,7 +209,7 @@ atoms further away than that distance. If you want an ADF for larger distances, you can use the :doc:`rerun ` command to post-process a dump file and set the cutoff for the potential to be longer in the rerun script. Note that in the rerun context, the force cutoff is -arbitrary, since you aren't running dynamics and thus are not changing +arbitrary, since you are not running dynamics and thus are not changing your model. Related commands diff --git a/doc/src/compute_rdf.rst b/doc/src/compute_rdf.rst index 5f426ffb51..0aedfe09aa 100644 --- a/doc/src/compute_rdf.rst +++ b/doc/src/compute_rdf.rst @@ -180,7 +180,7 @@ atoms further away than that distance. If you want an RDF for larger distances, you can use the :doc:`rerun ` command to post-process a dump file and set the cutoff for the potential to be longer in the rerun script. Note that in the rerun context, the force cutoff is -arbitrary, since you aren't running dynamics and thus are not changing +arbitrary, since you are not running dynamics and thus are not changing your model. The definition of g(r) used by LAMMPS is only appropriate for characterizing atoms that are uniformly distributed throughout the simulation cell. In such cases, the coordination number is still diff --git a/doc/src/create_atoms.rst b/doc/src/create_atoms.rst index 2e0b079e09..b58489f868 100644 --- a/doc/src/create_atoms.rst +++ b/doc/src/create_atoms.rst @@ -200,7 +200,7 @@ not overlap, regardless of their relative orientations. optional keywords allowed by the :doc:`create_box ` command for extra bonds (angles,etc) or extra special neighbors. This is because by default, the :doc:`create_box ` command sets up a - non-molecular system which doesn't allow molecules to be added. + non-molecular system which does not allow molecules to be added. ---------- diff --git a/doc/src/dump.rst b/doc/src/dump.rst index c842d5fafe..36a20defb6 100644 --- a/doc/src/dump.rst +++ b/doc/src/dump.rst @@ -286,7 +286,7 @@ Style *custom* allows you to specify a list of atom attributes to be written to the dump file for each atom. Possible attributes are listed above and will appear in the order specified. You cannot specify a quantity that is not defined for a particular simulation - -such as *q* for atom style *bond*\ , since that atom style doesn't +such as *q* for atom style *bond*\ , since that atom style does not assign charges. Dumps occur at the very end of a timestep, so atom attributes will include effects due to fixes that are applied during the timestep. An explanation of the possible dump custom attributes diff --git a/doc/src/dump_modify.rst b/doc/src/dump_modify.rst index 5f7f42b4be..75fff9d444 100644 --- a/doc/src/dump_modify.rst +++ b/doc/src/dump_modify.rst @@ -520,7 +520,7 @@ includes an initial snapshot with the reference position of all atoms. Note that only computes with a *refresh* option will work with dump_modify refresh. See individual compute doc pages for details. Currently, only compute displace/atom supports this option. Others -may be added at some point. If you use a compute that doesn't support +may be added at some point. If you use a compute that does not support refresh operations, LAMMPS will not complain; dump_modify refresh will simply do nothing. diff --git a/doc/src/fix_atom_swap.rst b/doc/src/fix_atom_swap.rst index a87fdadf83..2ad289e91e 100644 --- a/doc/src/fix_atom_swap.rst +++ b/doc/src/fix_atom_swap.rst @@ -108,7 +108,7 @@ non-zero molecule ID, but does not check for this at the time of swapping. If not using *semi-grand* this fix checks to ensure all atoms of the -given types have the same atomic charge. LAMMPS doesn't enforce this +given types have the same atomic charge. LAMMPS does not enforce this in general, but it is needed for this fix to simplify the swapping procedure. Successful swaps will swap the atom type and charge of the swapped atoms. Conversely, when using *semi-grand*\ , it is assumed that all the atom diff --git a/doc/src/fix_ehex.rst b/doc/src/fix_ehex.rst index 4e2ea3a73d..10622c8b3e 100644 --- a/doc/src/fix_ehex.rst +++ b/doc/src/fix_ehex.rst @@ -109,7 +109,7 @@ found in reference "(Wirnsberger)"#_Wirnsberger. This fix is different from a thermostat such as :doc:`fix nvt ` or :doc:`fix temp/rescale ` in that energy is -added/subtracted continually. Thus if there isn't another mechanism +added/subtracted continually. Thus if there is not another mechanism in place to counterbalance this effect, the entire system will heat or cool continuously. diff --git a/doc/src/fix_heat.rst b/doc/src/fix_heat.rst index 3412daf63c..82a2b6e7f8 100644 --- a/doc/src/fix_heat.rst +++ b/doc/src/fix_heat.rst @@ -96,7 +96,7 @@ with optional time-dependence as well. Fix heat is different from a thermostat such as :doc:`fix nvt ` or :doc:`fix temp/rescale ` in that energy is -added/subtracted continually. Thus if there isn't another mechanism +added/subtracted continually. Thus if there is not another mechanism in place to counterbalance this effect, the entire system will heat or cool continuously. You can use multiple heat fixes so that the net energy change is 0.0 or use :doc:`fix viscous ` to drain diff --git a/doc/src/fix_spring.rst b/doc/src/fix_spring.rst index b337a4e048..518b4d2302 100644 --- a/doc/src/fix_spring.rst +++ b/doc/src/fix_spring.rst @@ -45,7 +45,7 @@ Apply a spring force to a group of atoms or between two groups of atoms. This is useful for applying an umbrella force to a small molecule or lightly tethering a large group of atoms (e.g. all the solvent or a large molecule) to the center of the simulation box so -that it doesn't wander away over the course of a long simulation. It +that it does not wander away over the course of a long simulation. It can also be used to hold the centers of mass of two groups of atoms at a given distance or orientation with respect to each other. diff --git a/doc/src/if.rst b/doc/src/if.rst index fff561bd77..96a0eca42e 100644 --- a/doc/src/if.rst +++ b/doc/src/if.rst @@ -53,7 +53,7 @@ until one is found to be true, in which case its commands (f1, f2, ..., fN) are executed. If no Boolean expression is TRUE, then the commands associated with the else keyword, namely (e1, e2, ..., eN), are executed. The elif and else keywords and their associated -commands are optional. If they aren't specified and the initial +commands are optional. If they are not specified and the initial Boolean expression is FALSE, then no commands are executed. The syntax for Boolean expressions is described below. diff --git a/doc/src/molecule.rst b/doc/src/molecule.rst index 32e6d846ae..0411f28cef 100644 --- a/doc/src/molecule.rst +++ b/doc/src/molecule.rst @@ -123,7 +123,7 @@ a description of the file. Then lines are read one at a time. Lines can have a trailing comment starting with '#' that is ignored. If the line is blank (only white-space after comment is deleted), it is skipped. If the line contains a header keyword, the corresponding -value(s) is read from the line. If it doesn't contain a header +value(s) is read from the line. If it does not contain a header keyword, the line begins the body of the file. The body of the file contains zero or more sections. The first line diff --git a/doc/src/neigh_modify.rst b/doc/src/neigh_modify.rst index 74b4572b95..2618953dd7 100644 --- a/doc/src/neigh_modify.rst +++ b/doc/src/neigh_modify.rst @@ -177,7 +177,7 @@ atom can have. LAMMPS can crash without an error message if the number of neighbors for a single particle is larger than the *page* setting, which means it is much, much larger than the *one* setting. This is - because LAMMPS doesn't error check these limits for every pairwise + because LAMMPS does not error check these limits for every pairwise interaction (too costly), but only after all the particle's neighbors have been found. This problem usually means something is very wrong with the way you have setup your problem (particle spacing, cutoff diff --git a/doc/src/package.rst b/doc/src/package.rst index 609216206d..a6a2353087 100644 --- a/doc/src/package.rst +++ b/doc/src/package.rst @@ -444,7 +444,7 @@ CPUs (i.e. the Kokkos CUDA back end is not enabled). A value of *full* uses a full neighbor lists and is the default when running on GPUs. This performs twice as much computation as the *half* option, however that is often a win because it is thread-safe and -doesn't require atomic operations in the calculation of pair forces. For +does not require atomic operations in the calculation of pair forces. For that reason, *full* is the default setting for GPUs. However, when running on CPUs, a *half* neighbor list is the default because it are often faster, just as it is for non-accelerated pair styles. Similarly, diff --git a/doc/src/pair_agni.rst b/doc/src/pair_agni.rst index 2023e655f4..e5a17658cf 100644 --- a/doc/src/pair_agni.rst +++ b/doc/src/pair_agni.rst @@ -119,7 +119,7 @@ The AGNI force field files provided with LAMMPS (see the potentials directory) are parameterized for metal :doc:`units `. You can use the AGNI potential with any LAMMPS units, but you would need to create your own AGNI potential file with coefficients listed in the -appropriate units if your simulation doesn't use "metal" units. +appropriate units if your simulation does not use "metal" units. Related commands """""""""""""""" diff --git a/doc/src/pair_airebo.rst b/doc/src/pair_airebo.rst index d7fc9a9c07..b6d1af2a79 100644 --- a/doc/src/pair_airebo.rst +++ b/doc/src/pair_airebo.rst @@ -246,7 +246,7 @@ The CH.airebo and CH.airebo-m potential files provided with LAMMPS You can use the AIREBO, AIREBO-M or REBO potential with any LAMMPS units, but you would need to create your own AIREBO or AIREBO-M potential file with coefficients listed in the appropriate units, if your simulation -doesn't use "metal" units. +does not use "metal" units. Related commands """""""""""""""" diff --git a/doc/src/pair_comb.rst b/doc/src/pair_comb.rst index a03bc3fffe..247f539ab5 100644 --- a/doc/src/pair_comb.rst +++ b/doc/src/pair_comb.rst @@ -196,7 +196,7 @@ with LAMMPS (see the potentials directory) are parameterized for metal :doc:`units `. You can use the COMB potential with any LAMMPS units, but you would need to create your own COMB potential file with coefficients listed in the appropriate units if your simulation -doesn't use "metal" units. +does not use "metal" units. Related commands """""""""""""""" diff --git a/doc/src/pair_drip.rst b/doc/src/pair_drip.rst index 1fa193777a..25a51c4de8 100644 --- a/doc/src/pair_drip.rst +++ b/doc/src/pair_drip.rst @@ -127,7 +127,7 @@ The *C.drip* parameter file provided with LAMMPS (see the "potentials" directory) is parameterized for metal :doc:`units `. You can use the DRIP potential with any LAMMPS units, but you would need to create your own custom parameter file with coefficients listed in the appropriate units, if your -simulation doesn't use "metal" units. +simulation does not use "metal" units. Related commands """""""""""""""" diff --git a/doc/src/pair_edip.rst b/doc/src/pair_edip.rst index 02f779bebf..5561e30919 100644 --- a/doc/src/pair_edip.rst +++ b/doc/src/pair_edip.rst @@ -174,7 +174,7 @@ The EDIP potential files provided with LAMMPS (see the potentials directory) are parameterized for metal :doc:`units `. You can use the EDIP potential with any LAMMPS units, but you would need to create your own EDIP potential file with coefficients listed in the -appropriate units if your simulation doesn't use "metal" units. +appropriate units if your simulation does not use "metal" units. Related commands """""""""""""""" diff --git a/doc/src/pair_gw.rst b/doc/src/pair_gw.rst index d2d1283618..7564252459 100644 --- a/doc/src/pair_gw.rst +++ b/doc/src/pair_gw.rst @@ -111,7 +111,7 @@ The Gao-Weber potential files provided with LAMMPS (see the potentials directory) are parameterized for metal :doc:`units `. You can use the GW potential with any LAMMPS units, but you would need to create your own GW potential file with coefficients listed in the -appropriate units if your simulation doesn't use "metal" units. +appropriate units if your simulation does not use "metal" units. Related commands """""""""""""""" diff --git a/doc/src/pair_lcbop.rst b/doc/src/pair_lcbop.rst index 4eb7a345ee..ef26556c69 100644 --- a/doc/src/pair_lcbop.rst +++ b/doc/src/pair_lcbop.rst @@ -84,7 +84,7 @@ The C.lcbop potential file provided with LAMMPS (see the potentials directory) is parameterized for metal :doc:`units `. You can use the LCBOP potential with any LAMMPS units, but you would need to create your own LCBOP potential file with coefficients listed in the -appropriate units if your simulation doesn't use "metal" units. +appropriate units if your simulation does not use "metal" units. Related commands """""""""""""""" diff --git a/doc/src/pair_reaxc.rst b/doc/src/pair_reaxc.rst index e40fbe60c1..1481b0bf4f 100644 --- a/doc/src/pair_reaxc.rst +++ b/doc/src/pair_reaxc.rst @@ -149,7 +149,7 @@ drops to zero. Optional keywords *safezone* and *mincap* are used for allocating reax/c arrays. Increasing these values can avoid memory problems, such as segmentation faults and bondchk failed errors, that could -occur under certain conditions. These keywords aren't used by the +occur under certain conditions. These keywords are not used by the Kokkos version, which instead uses a more robust memory allocation scheme that checks if the sizes of the arrays have been exceeded and automatically allocates more memory. @@ -341,7 +341,7 @@ The ReaxFF potential files provided with LAMMPS in the potentials directory are parameterized for real :doc:`units `. You can use the ReaxFF potential with any LAMMPS units, but you would need to create your own potential file with coefficients listed in the -appropriate units if your simulation doesn't use "real" units. +appropriate units if your simulation does not use "real" units. Related commands """""""""""""""" diff --git a/doc/src/pair_sw.rst b/doc/src/pair_sw.rst index f7999c720a..b4fddc6867 100644 --- a/doc/src/pair_sw.rst +++ b/doc/src/pair_sw.rst @@ -222,7 +222,7 @@ The Stillinger-Weber potential files provided with LAMMPS (see the potentials directory) are parameterized for metal :doc:`units `. You can use the SW potential with any LAMMPS units, but you would need to create your own SW potential file with coefficients listed in the -appropriate units if your simulation doesn't use "metal" units. +appropriate units if your simulation does not use "metal" units. Related commands """""""""""""""" diff --git a/doc/src/pair_tersoff.rst b/doc/src/pair_tersoff.rst index 7881c8ee70..050b1367f3 100644 --- a/doc/src/pair_tersoff.rst +++ b/doc/src/pair_tersoff.rst @@ -271,7 +271,7 @@ The Tersoff potential files provided with LAMMPS (see the potentials directory) are parameterized for metal :doc:`units `. You can use the Tersoff potential with any LAMMPS units, but you would need to create your own Tersoff potential file with coefficients listed in the -appropriate units if your simulation doesn't use "metal" units. +appropriate units if your simulation does not use "metal" units. Related commands """""""""""""""" diff --git a/doc/src/pair_tersoff_mod.rst b/doc/src/pair_tersoff_mod.rst index 3d5bdbdaee..1761a0b9fb 100644 --- a/doc/src/pair_tersoff_mod.rst +++ b/doc/src/pair_tersoff_mod.rst @@ -209,7 +209,7 @@ The Tersoff/MOD potential files provided with LAMMPS (see the potentials directory) are parameterized for metal :doc:`units `. You can use the Tersoff/MOD potential with any LAMMPS units, but you would need to create your own Tersoff/MOD potential file with coefficients listed in the -appropriate units if your simulation doesn't use "metal" units. +appropriate units if your simulation does not use "metal" units. Related commands """""""""""""""" diff --git a/doc/src/pair_tersoff_zbl.rst b/doc/src/pair_tersoff_zbl.rst index fe86ef2cbb..57dc3db51e 100644 --- a/doc/src/pair_tersoff_zbl.rst +++ b/doc/src/pair_tersoff_zbl.rst @@ -286,7 +286,7 @@ The Tersoff/ZBL potential files provided with LAMMPS (see the potentials directory) are parameterized for metal :doc:`units `. You can use the Tersoff potential with any LAMMPS units, but you would need to create your own Tersoff potential file with coefficients -listed in the appropriate units if your simulation doesn't use "metal" +listed in the appropriate units if your simulation does not use "metal" units. Related commands diff --git a/doc/src/pair_vashishta.rst b/doc/src/pair_vashishta.rst index 044709d65d..6fc5cfe015 100644 --- a/doc/src/pair_vashishta.rst +++ b/doc/src/pair_vashishta.rst @@ -245,7 +245,7 @@ The Vashishta potential files provided with LAMMPS (see the potentials directory) are parameterized for metal :doc:`units `. You can use the Vashishta potential with any LAMMPS units, but you would need to create your own potential file with coefficients listed in the -appropriate units if your simulation doesn't use "metal" units. +appropriate units if your simulation does not use "metal" units. Related commands """""""""""""""" diff --git a/doc/src/read_data.rst b/doc/src/read_data.rst index 2714cee4c1..642f930b9d 100644 --- a/doc/src/read_data.rst +++ b/doc/src/read_data.rst @@ -227,7 +227,7 @@ description of the file. Then lines are read one at a time. Lines can have a trailing comment starting with '#' that is ignored. If the line is blank (only white-space after comment is deleted), it is skipped. If the line contains a header keyword, the corresponding -value(s) is read from the line. If it doesn't contain a header +value(s) is read from the line. If it does not contain a header keyword, the line begins the body of the file. The body of the file contains zero or more sections. The first line diff --git a/doc/src/read_restart.rst b/doc/src/read_restart.rst index ef77cef1af..90cc426b0d 100644 --- a/doc/src/read_restart.rst +++ b/doc/src/read_restart.rst @@ -92,7 +92,7 @@ value. The file with the largest timestep value is read in. Thus, this effectively means, read the latest restart file. It's useful if you want your script to continue a run from where it left off. See the :doc:`run ` command and its "upto" option for how to specify -the run command so it doesn't need to be changed either. +the run command so it does not need to be changed either. If a "%" character appears in the restart filename, LAMMPS expects a set of multiple files to exist. The :doc:`restart ` and diff --git a/doc/src/rerun.rst b/doc/src/rerun.rst index 8463fd774b..16b036b449 100644 --- a/doc/src/rerun.rst +++ b/doc/src/rerun.rst @@ -55,7 +55,7 @@ initial simulation produced the dump file: * Compute the energy and forces of snapshots using a different potential. * Calculate one or more diagnostic quantities on the snapshots that - weren't computed in the initial run. These can also be computed with + were not computed in the initial run. These can also be computed with settings not used in the initial run, e.g. computing an RDF via the :doc:`compute rdf ` command with a longer cutoff than was used initially. -- GitLab From 1db253823944631d6a571aeb874e25c7553c90e2 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 18 Mar 2020 07:02:49 -0400 Subject: [PATCH 320/689] use "command" instead of "cmd" --- doc/src/shell.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/src/shell.rst b/doc/src/shell.rst index a7646a74d2..4eb2652c1a 100644 --- a/doc/src/shell.rst +++ b/doc/src/shell.rst @@ -8,9 +8,9 @@ Syntax .. parsed-literal:: - shell cmd args + shell command args -* cmd = *cd* or *mkdir* or *mv* or *rm* or *rmdir* or *putenv* or arbitrary command +* command = *cd* or *mkdir* or *mv* or *rm* or *rmdir* or *putenv* or arbitrary command .. parsed-literal:: @@ -62,30 +62,30 @@ With the exception of *cd*\ , all commands, including ones invoked via a system() call, are executed by only a single processor, so that files/directories are not being manipulated by multiple processors. -The *cd* cmd executes the Unix "cd" command to change the working +The *cd* command executes the Unix "cd" command to change the working directory. All subsequent LAMMPS commands that read/write files will use the new directory. All processors execute this command. -The *mkdir* cmd executes the Unix "mkdir" command to create one or +The *mkdir* command executes the Unix "mkdir" command to create one or more directories. -The *mv* cmd executes the Unix "mv" command to rename a file and/or +The *mv* command executes the Unix "mv" command to rename a file and/or move it to a new directory. -The *rm* cmd executes the Unix "rm" command to remove one or more +The *rm* command executes the Unix "rm" command to remove one or more files. -The *rmdir* cmd executes the Unix "rmdir" command to remove one or +The *rmdir* command executes the Unix "rmdir" command to remove one or more directories. A directory must be empty to be successfully removed. -The *putenv* cmd defines or updates an environment variable directly. +The *putenv* command defines or updates an environment variable directly. Since this command does not pass through the shell, no shell variable expansion or globbing is performed, only the usual substitution for LAMMPS variables defined with the :doc:`variable ` command is performed. The resulting string is then used literally. -Any other cmd is passed as-is to the shell along with its arguments as +Any other command is passed as-is to the shell along with its arguments as one string, invoked by the C-library system() call. For example, these lines in your input script: -- GitLab From 6054f29933d38926e0078db3b1bd2160466bfb26 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 18 Mar 2020 07:03:32 -0400 Subject: [PATCH 321/689] update false positives --- doc/utils/sphinx-config/false_positives.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index 0449c0707b..5639be11ea 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -260,6 +260,8 @@ Bogaerts Bogusz Bohrs Boltzman +BondAngle +BondBond bondchk bondmax bondtype @@ -391,6 +393,7 @@ cmake CMake cmap Cmax +cmd cmdlist Cmin cmm @@ -486,6 +489,7 @@ cstring cstyle csvr Ctypes +ctypes cuda Cuda CUDA @@ -2345,6 +2349,7 @@ pymbar pymodule pymol pypar +pythonic Pyy pz Pz -- GitLab From ca1e1e2dff39e767aeb9cabdffa4d1422bdbdd94 Mon Sep 17 00:00:00 2001 From: Eisuke Kawashima Date: Wed, 18 Mar 2020 22:01:19 +0900 Subject: [PATCH 322/689] Convert British spelling to American --- doc/src/Build_development.rst | 2 +- .../oxDNA2/unique_bp/generate_unique.py | 10 ++-- examples/USER/manifold/diffusion/plot_msd.gpl | 2 +- python/examples/pylammps/montecarlo/mc.ipynb | 4 +- src/RIGID/fix_rattle.cpp | 2 +- src/RIGID/fix_shake.cpp | 2 +- src/USER-MANIFOLD/README | 4 +- src/USER-MANIFOLD/fix_manifoldforce.h | 2 +- src/USER-MANIFOLD/fix_nve_manifold_rattle.cpp | 2 +- src/USER-MANIFOLD/fix_nve_manifold_rattle.h | 2 +- src/USER-MANIFOLD/fix_nvt_manifold_rattle.cpp | 2 +- src/USER-MANIFOLD/fix_nvt_manifold_rattle.h | 2 +- src/USER-MANIFOLD/manifold_factory.cpp | 2 +- src/USER-MANIFOLD/manifold_factory.h | 2 +- src/USER-QUIP/pair_quip.cpp | 4 +- tools/amber2lmp/amber2lammps.py | 2 +- tools/amber2lmp/dump2trj.py | 2 +- tools/amber2lmp/dump2trj99.py | 2 +- tools/i-pi/ipi/engine/atoms.py | 4 +- tools/i-pi/ipi/engine/barostats.py | 2 +- tools/i-pi/ipi/engine/beads.py | 2 +- tools/i-pi/ipi/engine/cell.py | 2 +- tools/i-pi/ipi/engine/ensembles.py | 10 ++-- tools/i-pi/ipi/engine/forces.py | 4 +- tools/i-pi/ipi/engine/initializer.py | 2 +- tools/i-pi/ipi/engine/outputs.py | 2 +- tools/i-pi/ipi/engine/properties.py | 4 +- tools/i-pi/ipi/engine/simulation.py | 4 +- tools/i-pi/ipi/engine/thermostats.py | 48 +++++++++---------- tools/i-pi/ipi/inputs/atoms.py | 2 +- tools/i-pi/ipi/inputs/beads.py | 2 +- tools/i-pi/ipi/inputs/prng.py | 4 +- tools/i-pi/ipi/inputs/thermostats.py | 2 +- tools/i-pi/ipi/interfaces/sockets.py | 8 ++-- tools/i-pi/ipi/utils/depend.py | 8 ++-- tools/i-pi/ipi/utils/inputvalue.py | 18 +++---- tools/i-pi/ipi/utils/io/io_xml.py | 4 +- tools/i-pi/ipi/utils/prng.py | 8 ++-- tools/polybond/lmpsdata.py | 2 +- tools/replica/reorder_remd_traj.py | 2 +- 40 files changed, 97 insertions(+), 97 deletions(-) diff --git a/doc/src/Build_development.rst b/doc/src/Build_development.rst index 722f436063..4954fb522b 100644 --- a/doc/src/Build_development.rst +++ b/doc/src/Build_development.rst @@ -44,7 +44,7 @@ usually faster than using tools like Valgrind. .. code-block:: bash -D ENABLE_SANITIZE_ADDRESS=value # enable Address Sanitizer, value = no (default) or yes - -D ENABLE_SANITIZE_UNDEFINED=value # enable Undefined Behaviour Sanitizer, value = no (default) or yes + -D ENABLE_SANITIZE_UNDEFINED=value # enable Undefined Behavior Sanitizer, value = no (default) or yes -D ENABLE_SANITIZE_THREAD=value # enable Thread Sanitizer, value = no (default) or yes ---------- diff --git a/examples/USER/cgdna/examples/oxDNA2/unique_bp/generate_unique.py b/examples/USER/cgdna/examples/oxDNA2/unique_bp/generate_unique.py index 0760d24a0b..131f51e9b4 100644 --- a/examples/USER/cgdna/examples/oxDNA2/unique_bp/generate_unique.py +++ b/examples/USER/cgdna/examples/oxDNA2/unique_bp/generate_unique.py @@ -373,7 +373,7 @@ def generate_strand(bp, sequence=None, start_pos=np.array([0, 0, 0]), \ # if not provided switch off random orientation if perp is None or perp is False: v1 = np.random.random_sample(3) - # comment in to suppress randomised base vector + # comment in to suppress randomized base vector v1 = [1,0,0] v1 -= dir * (np.dot(dir, v1)) v1 /= np.sqrt(sum(v1*v1)) @@ -644,12 +644,12 @@ def read_strands(filename): # generate random position of the first nucleotide com = box_offset + np.random.random_sample(3) * box - # comment out to randomise + # comment out to randomize com = [0,0,0] # generate the random direction of the helix axis = np.random.random_sample(3) - # comment out to randomise + # comment out to randomize axis = [0,0,1] axis /= np.sqrt(np.dot(axis, axis)) @@ -702,12 +702,12 @@ def read_strands(filename): # generate random position of the first nucleotide com = box_offset + np.random.random_sample(3) * box - # comment out to randomise + # comment out to randomize com = [-30,0,0] # generate the random direction of the helix axis = np.random.random_sample(3) - # comment out to randomise + # comment out to randomize axis = [0,0,1] axis /= np.sqrt(np.dot(axis, axis)) diff --git a/examples/USER/manifold/diffusion/plot_msd.gpl b/examples/USER/manifold/diffusion/plot_msd.gpl index dbc87eee07..4694343ad4 100644 --- a/examples/USER/manifold/diffusion/plot_msd.gpl +++ b/examples/USER/manifold/diffusion/plot_msd.gpl @@ -47,7 +47,7 @@ set object 1 rectangle from graph 0,0 to graph 1,1 fillcolor rgb "white" behind unset key set grid front -set title 'Short time behaviour' offset 0,-0.8 +set title 'Short time behavior' offset 0,-0.8 set ylabel '' set xrange[0:10] set yrange[0:40] diff --git a/python/examples/pylammps/montecarlo/mc.ipynb b/python/examples/pylammps/montecarlo/mc.ipynb index 8509845a3d..0275171bdd 100644 --- a/python/examples/pylammps/montecarlo/mc.ipynb +++ b/python/examples/pylammps/montecarlo/mc.ipynb @@ -822,7 +822,7 @@ "}\n", "\n", "mpl.figure.prototype._key_event_extra = function(event, name) {\n", - " // Handle any extra behaviour associated with a key event\n", + " // Handle any extra behavior associated with a key event\n", "}\n", "\n", "mpl.figure.prototype.key_event = function(event, name) {\n", @@ -1053,7 +1053,7 @@ "mpl.find_output_cell = function(html_output) {\n", " // Return the cell and output element which can be found *uniquely* in the notebook.\n", " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", + " // IPython event is triggered only after the cells have been serialized, which for\n", " // our purposes (turning an active figure into a static one), is too late.\n", " var cells = IPython.notebook.get_cells();\n", " var ncells = cells.length;\n", diff --git a/src/RIGID/fix_rattle.cpp b/src/RIGID/fix_rattle.cpp index 93bf610e94..ff31ab9755 100644 --- a/src/RIGID/fix_rattle.cpp +++ b/src/RIGID/fix_rattle.cpp @@ -119,7 +119,7 @@ int FixRattle::setmask() void FixRattle::init() { - // initialise SHAKE first + // initialize SHAKE first FixShake::init(); diff --git a/src/RIGID/fix_shake.cpp b/src/RIGID/fix_shake.cpp index 3342f02194..b1ce975005 100644 --- a/src/RIGID/fix_shake.cpp +++ b/src/RIGID/fix_shake.cpp @@ -3059,7 +3059,7 @@ void FixShake::correct_velocities() {} void FixShake::correct_coordinates(int vflag) { // save current forces and velocities so that you - // initialise them to zero such that FixShake::unconstrained_coordinate_update has no effect + // initialize them to zero such that FixShake::unconstrained_coordinate_update has no effect for (int j=0; jall(FLERR,"Incorrect args for pair coefficients"); // Initialise potential - // First call initialises potential via the fortran code in memory, and returns the necessary size - // of quip_potential. This behaviour is invoked by setting n_potential_quip to 0. + // First call initializes potential via the fortran code in memory, and returns the necessary size + // of quip_potential. This behavior is invoked by setting n_potential_quip to 0. n_quip_potential = 0; quip_potential = new int[0]; quip_lammps_potential_initialise(quip_potential,&n_quip_potential,&cutoff,quip_file,&n_quip_file,quip_string,&n_quip_string); diff --git a/tools/amber2lmp/amber2lammps.py b/tools/amber2lmp/amber2lammps.py index cb0820f96c..5a2d17c53b 100644 --- a/tools/amber2lmp/amber2lammps.py +++ b/tools/amber2lmp/amber2lammps.py @@ -175,7 +175,7 @@ class Lammps: class Amber: def __init__(self): - 'Initialise the Amber class' + 'Initialize the Amber class' self.CRD_is_read = 0 self.TOP_is_read = 0 diff --git a/tools/amber2lmp/dump2trj.py b/tools/amber2lmp/dump2trj.py index d406ae7eb9..0f0b936397 100644 --- a/tools/amber2lmp/dump2trj.py +++ b/tools/amber2lmp/dump2trj.py @@ -70,7 +70,7 @@ def Find_dump_files(): class Snapshot: def __init__(self, The_trajectory): - 'Initialise the Snapshot class' + 'Initialize the Snapshot class' self.timestep = The_trajectory.timestep self.atoms = The_trajectory.atoms diff --git a/tools/amber2lmp/dump2trj99.py b/tools/amber2lmp/dump2trj99.py index 19e6064e7c..3cac42987c 100755 --- a/tools/amber2lmp/dump2trj99.py +++ b/tools/amber2lmp/dump2trj99.py @@ -68,7 +68,7 @@ def Find_dump_files(): class Snapshot: def __init__(self, The_trajectory): - 'Initialise the Snapshot class' + 'Initialize the Snapshot class' self.atoms = The_trajectory.atoms self.xlo = The_trajectory.xlo diff --git a/tools/i-pi/ipi/engine/atoms.py b/tools/i-pi/ipi/engine/atoms.py index fd52ccf96b..9e6e2752f6 100644 --- a/tools/i-pi/ipi/engine/atoms.py +++ b/tools/i-pi/ipi/engine/atoms.py @@ -51,7 +51,7 @@ class Atom(dobject): """ def __init__(self, system, index): - """Initialises Atom. + """Initializes Atom. Args: system: An Atoms object containing the required atom. @@ -116,7 +116,7 @@ class Atoms(dobject): def __init__(self, natoms, _prebind=None): - """Initialises Atoms. + """Initializes Atoms. Each replica and the centroid coordinate are all held as Atoms objects, and so slices of the global position and momentum arrays must be used in diff --git a/tools/i-pi/ipi/engine/barostats.py b/tools/i-pi/ipi/engine/barostats.py index 5dbc6049d5..b65e62746c 100644 --- a/tools/i-pi/ipi/engine/barostats.py +++ b/tools/i-pi/ipi/engine/barostats.py @@ -70,7 +70,7 @@ class Barostat(dobject): """ def __init__(self, dt=None, temp=None, pext=None, tau=None, ebaro=None, thermostat=None): - """Initialises base barostat class. + """Initializes base barostat class. Note that the external stress and the external pressure are synchronized. This makes most sense going from the stress to the pressure, but if you diff --git a/tools/i-pi/ipi/engine/beads.py b/tools/i-pi/ipi/engine/beads.py index ba4ddf1509..1a20574522 100644 --- a/tools/i-pi/ipi/engine/beads.py +++ b/tools/i-pi/ipi/engine/beads.py @@ -71,7 +71,7 @@ class Beads(dobject): """ def __init__(self, natoms, nbeads): - """Initialises Beads. + """Initializes Beads. Args: natoms: Number of atoms. diff --git a/tools/i-pi/ipi/engine/cell.py b/tools/i-pi/ipi/engine/cell.py index e9bf813502..f800773a23 100644 --- a/tools/i-pi/ipi/engine/cell.py +++ b/tools/i-pi/ipi/engine/cell.py @@ -44,7 +44,7 @@ class Cell(dobject): """ def __init__(self, h=None): - """Initialises base cell class. + """Initializes base cell class. Args: h: Optional array giving the initial lattice vector matrix. The diff --git a/tools/i-pi/ipi/engine/ensembles.py b/tools/i-pi/ipi/engine/ensembles.py index ef592405b0..23d88e436b 100644 --- a/tools/i-pi/ipi/engine/ensembles.py +++ b/tools/i-pi/ipi/engine/ensembles.py @@ -78,7 +78,7 @@ class Ensemble(dobject): """ def __init__(self, dt, temp, fixcom=False): - """Initialises Ensemble. + """Initializes Ensemble. Args: dt: The timestep of the simulation algorithms. @@ -177,7 +177,7 @@ class NVEEnsemble(Ensemble): """ def __init__(self, dt, temp, fixcom=False): - """Initialises NVEEnsemble. + """Initializes NVEEnsemble. Args: dt: The simulation timestep. @@ -273,7 +273,7 @@ class NVTEnsemble(NVEEnsemble): """ def __init__(self, dt, temp, thermostat=None, fixcom=False): - """Initialises NVTEnsemble. + """Initializes NVTEnsemble. Args: dt: The simulation timestep. @@ -384,7 +384,7 @@ class NPTEnsemble(NVTEnsemble): """ def __init__(self, dt, temp, pext, thermostat=None, barostat=None, fixcom=False): - """Initialises NPTEnsemble. + """Initializes NPTEnsemble. Args: dt: The simulation timestep. @@ -508,7 +508,7 @@ class ReplayEnsemble(Ensemble): """ def __init__(self, dt, temp, fixcom=False, intraj=None): - """Initialises ReplayEnsemble. + """Initializes ReplayEnsemble. Args: dt: The simulation timestep. diff --git a/tools/i-pi/ipi/engine/forces.py b/tools/i-pi/ipi/engine/forces.py index 58987f1e4d..5e3dabf8db 100644 --- a/tools/i-pi/ipi/engine/forces.py +++ b/tools/i-pi/ipi/engine/forces.py @@ -66,7 +66,7 @@ class ForceField(dobject): """ def __init__(self): - """Initialises ForceField.""" + """Initializes ForceField.""" # ufvx is a list [ u, f, vir, extra ] which stores the results of the force #calculation @@ -217,7 +217,7 @@ class FFSocket(ForceField): """ def __init__(self, pars=None, interface=None): - """Initialises FFSocket. + """Initializes FFSocket. Args: pars: Optional dictionary, giving the parameters needed by the driver. diff --git a/tools/i-pi/ipi/engine/initializer.py b/tools/i-pi/ipi/engine/initializer.py index de629c7f96..fd9bcfb9fa 100644 --- a/tools/i-pi/ipi/engine/initializer.py +++ b/tools/i-pi/ipi/engine/initializer.py @@ -493,7 +493,7 @@ class Initializer(dobject): rv *= np.sqrt(self.nbeads/nbeads) set_vector(v, simul.beads.p, rv) fmom = True - elif k == "thermostat": pass # thermostats must be initialised in a second stage + elif k == "thermostat": pass # thermostats must be initialized in a second stage if simul.beads.natoms == 0: raise ValueError("Initializer could not initialize the atomic positions") diff --git a/tools/i-pi/ipi/engine/outputs.py b/tools/i-pi/ipi/engine/outputs.py index 605d6a3b2d..7d6e7587b5 100644 --- a/tools/i-pi/ipi/engine/outputs.py +++ b/tools/i-pi/ipi/engine/outputs.py @@ -349,7 +349,7 @@ class CheckpointOutput(dobject): """Writes out the required trajectories. Used for both the checkpoint files and the soft-exit restart file. - We have slightly different behaviour for these two different types of + We have slightly different behavior for these two different types of checkpoint file, as the soft-exit files have their store() function called automatically, and we do not want this to be updated as the status of the simulation after a soft-exit call is unlikely to be in diff --git a/tools/i-pi/ipi/engine/properties.py b/tools/i-pi/ipi/engine/properties.py index e9c9646708..48b0c00ecc 100644 --- a/tools/i-pi/ipi/engine/properties.py +++ b/tools/i-pi/ipi/engine/properties.py @@ -212,7 +212,7 @@ class Properties(dobject): _DEFAULT_MINFID = 1e-12 def __init__(self): - """Initialises Properties.""" + """Initializes Properties.""" self.property_dict = { "step": { "dimension" : "number", @@ -1094,7 +1094,7 @@ class Trajectories(dobject): """ def __init__(self): - """Initialises a Trajectories object.""" + """Initializes a Trajectories object.""" self.traj_dict = { # Note that here we want to return COPIES of the different arrays, so we make sure to make an operation in order not to return a reference. diff --git a/tools/i-pi/ipi/engine/simulation.py b/tools/i-pi/ipi/engine/simulation.py index eba03cc036..b1483de576 100644 --- a/tools/i-pi/ipi/engine/simulation.py +++ b/tools/i-pi/ipi/engine/simulation.py @@ -20,7 +20,7 @@ along with this program. If not, see . The root class for the whole simulation. Contains references to all the top level objects used in the simulation, and controls all the steps that are not inherently system dependent, like the running of each time step, -choosing which properties to initialise, and which properties to output. +choosing which properties to initialize, and which properties to output. Classes: Simulation: Deals with running the simulation and outputting the results. @@ -81,7 +81,7 @@ class Simulation(dobject): """ def __init__(self, beads, cell, forces, ensemble, prng, outputs, nm, init, step=0, tsteps=1000, ttime=0): - """Initialises Simulation class. + """Initializes Simulation class. Args: beads: A beads object giving the atom positions. diff --git a/tools/i-pi/ipi/engine/thermostats.py b/tools/i-pi/ipi/engine/thermostats.py index 943deb47fd..7941f55916 100644 --- a/tools/i-pi/ipi/engine/thermostats.py +++ b/tools/i-pi/ipi/engine/thermostats.py @@ -31,11 +31,11 @@ Classes: the entire system. ThermoSVR: Holds the algorithms for a stochastic velocity rescaling thermostat. - ThermoGLE: Holds the algorithms for a generalised langevin equation + ThermoGLE: Holds the algorithms for a generalized langevin equation thermostat. - ThermoNMGLE: Holds the algorithms for a generalised langevin equation + ThermoNMGLE: Holds the algorithms for a generalized langevin equation thermostat in the normal mode representation. - ThermoNMGLEG: Holds the algorithms for a generalised langevin equation + ThermoNMGLEG: Holds the algorithms for a generalized langevin equation thermostat in the normal mode representation, with kinetic energy as well as potential energy sampling optimization. """ @@ -75,14 +75,14 @@ class Thermostat(dobject): """ def __init__(self, temp = 1.0, dt = 1.0, ethermo=0.0): - """Initialises Thermostat. + """Initializes Thermostat. Args: temp: The simulation temperature. Defaults to 1.0. dt: The simulation time step. Defaults to 1.0. ethermo: The initial heat energy transferred to the bath. Defaults to 0.0. Will be non-zero if the thermostat is - initialised from a checkpoint file. + initialized from a checkpoint file. """ dset(self,"temp", depend_value(name='temp', value=temp)) @@ -181,7 +181,7 @@ class ThermoLangevin(Thermostat): return np.sqrt(Constants.kb*self.temp*(1 - self.T**2)) def __init__(self, temp = 1.0, dt = 1.0, tau = 1.0, ethermo=0.0): - """Initialises ThermoLangevin. + """Initializes ThermoLangevin. Args: temp: The simulation temperature. Defaults to 1.0. @@ -189,7 +189,7 @@ class ThermoLangevin(Thermostat): tau: The thermostat damping timescale. Defaults to 1.0. ethermo: The initial heat energy transferred to the bath. Defaults to 0.0. Will be non-zero if the thermostat is - initialised from a checkpoint file. + initialized from a checkpoint file. """ super(ThermoLangevin,self).__init__(temp, dt, ethermo) @@ -241,14 +241,14 @@ class ThermoPILE_L(Thermostat): """ def __init__(self, temp = 1.0, dt = 1.0, tau = 1.0, ethermo=0.0, scale=1.0): - """Initialises ThermoPILE_L. + """Initializes ThermoPILE_L. Args: temp: The simulation temperature. Defaults to 1.0. dt: The simulation time step. Defaults to 1.0. tau: The centroid thermostat damping timescale. Defaults to 1.0. ethermo: The initial conserved energy quantity. Defaults to 0.0. Will - be non-zero if the thermostat is initialised from a checkpoint file. + be non-zero if the thermostat is initialized from a checkpoint file. scale: A float used to reduce the intensity of the PILE thermostat if required. @@ -404,14 +404,14 @@ class ThermoSVR(Thermostat): return Constants.kb*self.temp*0.5 def __init__(self, temp = 1.0, dt = 1.0, tau = 1.0, ethermo=0.0): - """Initialises ThermoSVR. + """Initializes ThermoSVR. Args: temp: The simulation temperature. Defaults to 1.0. dt: The simulation time step. Defaults to 1.0. tau: The thermostat damping timescale. Defaults to 1.0. ethermo: The initial conserved energy quantity. Defaults to 0.0. Will - be non-zero if the thermostat is initialised from a checkpoint file. + be non-zero if the thermostat is initialized from a checkpoint file. """ super(ThermoSVR,self).__init__(temp,dt,ethermo) @@ -459,14 +459,14 @@ class ThermoPILE_G(ThermoPILE_L): """ def __init__(self, temp = 1.0, dt = 1.0, tau = 1.0, ethermo=0.0, scale = 1.0): - """Initialises ThermoPILE_G. + """Initializes ThermoPILE_G. Args: temp: The simulation temperature. Defaults to 1.0. dt: The simulation time step. Defaults to 1.0. tau: The centroid thermostat damping timescale. Defaults to 1.0. ethermo: The initial conserved energy quantity. Defaults to 0.0. Will - be non-zero if the thermostat is initialised from a checkpoint file. + be non-zero if the thermostat is initialized from a checkpoint file. scale: A float used to reduce the intensity of the PILE thermostat if required. """ @@ -556,7 +556,7 @@ class ThermoGLE(Thermostat): return matrix_exp(-0.5*self.dt*self.A) def get_S(self): - """Calculates the matrix for the coloured noise.""" + """Calculates the matrix for the colored noise.""" SST = Constants.kb*(self.C - np.dot(self.T,np.dot(self.C,self.T.T))) @@ -570,7 +570,7 @@ class ThermoGLE(Thermostat): return rC[:] def __init__(self, temp = 1.0, dt = 1.0, A = None, C = None, ethermo=0.0): - """Initialises ThermoGLE. + """Initializes ThermoGLE. Args: temp: The simulation temperature. Defaults to 1.0. @@ -582,7 +582,7 @@ class ThermoGLE(Thermostat): total number of degrees of freedom in the system. ethermo: The initial heat energy transferred to the bath. Defaults to 0.0. Will be non-zero if the thermostat is - initialised from a checkpoint file. + initialized from a checkpoint file. """ super(ThermoGLE,self).__init__(temp,dt,ethermo) @@ -643,15 +643,15 @@ class ThermoGLE(Thermostat): # allocates, initializes or restarts an array of s's if self.s.shape != (self.ns + 1, len(dget(self,"m"))): if len(self.s) > 0: - warning("Mismatch in GLE s array size on restart, will reinitialise to free particle.", verbosity.low) + warning("Mismatch in GLE s array size on restart, will reinitialize to free particle.", verbosity.low) self.s = np.zeros((self.ns + 1, len(dget(self,"m")))) # Initializes the s vector in the free-particle limit - info(" GLE additional DOFs initialised to the free-particle limit.", verbosity.low) + info(" GLE additional DOFs initialized to the free-particle limit.", verbosity.low) SC = stab_cholesky(self.C*Constants.kb) self.s[:] = np.dot(SC, self.prng.gvec(self.s.shape)) else: - info("GLE additional DOFs initialised from input.", verbosity.medium) + info("GLE additional DOFs initialized from input.", verbosity.medium) def step(self): """Updates the bound momentum vector with a GLE thermostat""" @@ -699,7 +699,7 @@ class ThermoNMGLE(Thermostat): return rv[:] def __init__(self, temp = 1.0, dt = 1.0, A = None, C = None, ethermo=0.0): - """Initialises ThermoGLE. + """Initializes ThermoGLE. Args: temp: The simulation temperature. Defaults to 1.0. @@ -711,7 +711,7 @@ class ThermoNMGLE(Thermostat): total number of degrees of freedom in the system. ethermo: The initial heat energy transferred to the bath. Defaults to 0.0. Will be non-zero if the thermostat is - initialised from a checkpoint file. + initialized from a checkpoint file. """ super(ThermoNMGLE,self).__init__(temp,dt,ethermo) @@ -767,16 +767,16 @@ class ThermoNMGLE(Thermostat): # allocates, initializes or restarts an array of s's if self.s.shape != (self.nb, self.ns + 1, nm.natoms *3) : if len(self.s) > 0: - warning("Mismatch in GLE s array size on restart, will reinitialise to free particle.", verbosity.low) + warning("Mismatch in GLE s array size on restart, will reinitialize to free particle.", verbosity.low) self.s = np.zeros((self.nb, self.ns + 1, nm.natoms*3)) # Initializes the s vector in the free-particle limit - info(" GLE additional DOFs initialised to the free-particle limit.", verbosity.low) + info(" GLE additional DOFs initialized to the free-particle limit.", verbosity.low) for b in range(self.nb): SC = stab_cholesky(self.C[b]*Constants.kb) self.s[b] = np.dot(SC, self.prng.gvec(self.s[b].shape)) else: - info("GLE additional DOFs initialised from input.", verbosity.medium) + info("GLE additional DOFs initialized from input.", verbosity.medium) prev_ethermo = self.ethermo diff --git a/tools/i-pi/ipi/inputs/atoms.py b/tools/i-pi/ipi/inputs/atoms.py index 6068be1961..4ae16bfdf5 100644 --- a/tools/i-pi/ipi/inputs/atoms.py +++ b/tools/i-pi/ipi/inputs/atoms.py @@ -78,7 +78,7 @@ class InputAtoms(Input): """Takes an Atoms instance and stores a minimal representation of it. Args: - atoms: An Atoms object from which to initialise from. + atoms: An Atoms object from which to initialize from. filename: An optional string giving a filename to take the atom positions from. Defaults to ''. """ diff --git a/tools/i-pi/ipi/inputs/beads.py b/tools/i-pi/ipi/inputs/beads.py index f4caafcbb9..d889563d92 100644 --- a/tools/i-pi/ipi/inputs/beads.py +++ b/tools/i-pi/ipi/inputs/beads.py @@ -82,7 +82,7 @@ class InputBeads(Input): """Takes a Beads instance and stores a minimal representation of it. Args: - beads: A Beads object from which to initialise from. + beads: A Beads object from which to initialize from. """ super(InputBeads,self).store() diff --git a/tools/i-pi/ipi/inputs/prng.py b/tools/i-pi/ipi/inputs/prng.py index 58faaca5f0..e3464ca791 100644 --- a/tools/i-pi/ipi/inputs/prng.py +++ b/tools/i-pi/ipi/inputs/prng.py @@ -38,7 +38,7 @@ class InputRandom(Input): instance of the object. Attributes: - seed: An optional integer giving a seed to initialise the random number + seed: An optional integer giving a seed to initialize the random number generator from. Defaults to 123456. state: An optional array giving the state of the random number generator. Defaults to an empty array. @@ -74,7 +74,7 @@ class InputRandom(Input): representation of it. Args: - prng: A random number object from which to initialise from. + prng: A random number object from which to initialize from. """ super(InputRandom,self).store(prng) diff --git a/tools/i-pi/ipi/inputs/thermostats.py b/tools/i-pi/ipi/inputs/thermostats.py index cbe2deefcf..5c1ec2d65b 100644 --- a/tools/i-pi/ipi/inputs/thermostats.py +++ b/tools/i-pi/ipi/inputs/thermostats.py @@ -56,7 +56,7 @@ class InputThermo(Input): attribs = { "mode": (InputAttribute, { "dtype" : str, "options" : [ "", "langevin", "svr", "pile_l", "pile_g", "gle", "nm_gle", "nm_gle_g" ], - "help" : "The style of thermostatting. 'langevin' specifies a white noise langevin equation to be attached to the cartesian representation of the momenta. 'svr' attaches a velocity rescaling thermostat to the cartesian representation of the momenta. Both 'pile_l' and 'pile_g' attaches a white noise langevin thermostat to the normal mode representation, with 'pile_l' attaching a local langevin thermostat to the centroid mode and 'pile_g' instead attaching a global velocity rescaling thermostat. 'gle' attaches a coloured noise langevin thermostat to the cartesian representation of the momenta, 'nm_gle' attaches a coloured noise langevin thermostat to the normal mode representation of the momenta and a langevin thermostat to the centroid and 'nm_gle_g' attaches a gle thermostat to the normal modes and a svr thermostat to the centroid." + "help" : "The style of thermostatting. 'langevin' specifies a white noise langevin equation to be attached to the cartesian representation of the momenta. 'svr' attaches a velocity rescaling thermostat to the cartesian representation of the momenta. Both 'pile_l' and 'pile_g' attaches a white noise langevin thermostat to the normal mode representation, with 'pile_l' attaching a local langevin thermostat to the centroid mode and 'pile_g' instead attaching a global velocity rescaling thermostat. 'gle' attaches a colored noise langevin thermostat to the cartesian representation of the momenta, 'nm_gle' attaches a colored noise langevin thermostat to the normal mode representation of the momenta and a langevin thermostat to the centroid and 'nm_gle_g' attaches a gle thermostat to the normal modes and a svr thermostat to the centroid." }) } fields = { "ethermo" : (InputValue, { "dtype" : float, "default" : 0.0, diff --git a/tools/i-pi/ipi/interfaces/sockets.py b/tools/i-pi/ipi/interfaces/sockets.py index 2783d31e06..f946cf3149 100644 --- a/tools/i-pi/ipi/interfaces/sockets.py +++ b/tools/i-pi/ipi/interfaces/sockets.py @@ -108,7 +108,7 @@ class DriverSocket(socket.socket): """Deals with communication between the client and driver code. Deals with sending and receiving the data from the driver code. Keeps track - of the status of the driver. Initialises the driver forcefield, sends the + of the status of the driver. Initializes the driver forcefield, sends the position and cell data, and receives the force data. Attributes: @@ -119,7 +119,7 @@ class DriverSocket(socket.socket): """ def __init__(self, socket): - """Initialises DriverSocket. + """Initializes DriverSocket. Args: socket: A socket through which the communication should be done. @@ -378,7 +378,7 @@ class InterfaceSocket(object): """ def __init__(self, address="localhost", port=31415, slots=4, mode="unix", latency=1e-3, timeout=1.0, dopbc=True): - """Initialises interface. + """Initializes interface. Args: address: An optional string giving the name of the host server. @@ -556,7 +556,7 @@ class InterfaceSocket(object): Deals with maintaining the jobs list. Gets data from drivers that have finished their calculation and removes that job from the list of running - jobs, adds jobs to free clients and initialises the forcefields of new + jobs, adds jobs to free clients and initializes the forcefields of new clients. """ diff --git a/tools/i-pi/ipi/utils/depend.py b/tools/i-pi/ipi/utils/depend.py index 6c7f4ce24d..a4da91b47b 100644 --- a/tools/i-pi/ipi/utils/depend.py +++ b/tools/i-pi/ipi/utils/depend.py @@ -73,7 +73,7 @@ class synchronizer(object): """ def __init__(self, deps=None): - """Initialises synchronizer. + """Initializes synchronizer. Args: deps: Optional dictionary giving the synched objects of the form @@ -113,7 +113,7 @@ class depend_base(object): """ def __init__(self, name, synchro=None, func=None, dependants=None, dependencies=None, tainted=None): - """Initialises depend_base. + """Initializes depend_base. An unusual initialization routine, as it has to be able to deal with the depend array mechanism for returning slices as new depend arrays. @@ -291,7 +291,7 @@ class depend_value(depend_base): """ def __init__(self, name, value=None, synchro=None, func=None, dependants=None, dependencies=None, tainted=None): - """Initialises depend_value. + """Initializes depend_value. Args: name: A string giving the name of self. @@ -375,7 +375,7 @@ class depend_array(np.ndarray, depend_base): return obj def __init__(self, value, name, synchro=None, func=None, dependants=None, dependencies=None, tainted=None, base=None): - """Initialises depend_array. + """Initializes depend_array. Note that this is only called when a new array is created by an explicit constructor. diff --git a/tools/i-pi/ipi/utils/inputvalue.py b/tools/i-pi/ipi/utils/inputvalue.py index aae989a3c9..35b2945910 100644 --- a/tools/i-pi/ipi/utils/inputvalue.py +++ b/tools/i-pi/ipi/utils/inputvalue.py @@ -22,7 +22,7 @@ attributes dictionary, which are filled with the tags and attributes that are allowed to be present, along with their default values and data type. These are then filled with the data from the xml file when the program -is initialised, and are filled by the values calculated in the program which +is initialized, and are filled by the values calculated in the program which are then output to the checkpoint file when a restart file is required. Also deals with checking for user input errors, of the form of misspelt tags, @@ -65,14 +65,14 @@ class input_default(object): """ def __init__(self, factory, args = None, kwargs = None): - """Initialises input_default. + """Initializes input_default. Args: type: The class or function to be used to create the default object. - args: A tuple giving the arguments to be used to initialise + args: A tuple giving the arguments to be used to initialize the default value. kwargs: A dictionary giving the key word arguments to be used - to initialise the default value. + to initialize the default value. """ if args is None: @@ -147,10 +147,10 @@ class Input(object): #hyperlinks def __init__(self, help=None, default=None): - """Initialises Input. + """Initializes Input. Automatically adds all the fields and attribs names to the input object's - dictionary, then initialises all the appropriate input objects + dictionary, then initializes all the appropriate input objects as the corresponding values. Args: @@ -676,7 +676,7 @@ class InputAttribute(Input): """ def __init__(self, help=None, default=None, dtype=None, options=None): - """Initialises InputAttribute. + """Initializes InputAttribute. Args: help: A help string. @@ -773,7 +773,7 @@ class InputValue(InputAttribute): attribs= { "units" : ( InputAttribute, { "dtype" : str, "help" : "The units the input data is given in.", "default" : default_units } ) } def __init__(self, help=None, default=None, dtype=None, options=None, dimension=None): - """Initialises InputValue. + """Initializes InputValue. Args: help: A help string. @@ -874,7 +874,7 @@ class InputArray(InputValue): attribs["shape"] = (InputAttribute, {"dtype": tuple, "help": "The shape of the array.", "default": (0,)}) def __init__(self, help=None, default=None, dtype=None, dimension=None): - """Initialises InputArray. + """Initializes InputArray. Args: help: A help string. diff --git a/tools/i-pi/ipi/utils/io/io_xml.py b/tools/i-pi/ipi/utils/io/io_xml.py index fbf8867aaf..961a398848 100644 --- a/tools/i-pi/ipi/utils/io/io_xml.py +++ b/tools/i-pi/ipi/utils/io/io_xml.py @@ -63,7 +63,7 @@ class xml_node(object): """ def __init__(self, attribs=None, name="", fields=None): - """Initialises xml_node. + """Initializes xml_node. Args: attribs: An optional dictionary giving attribute data. Defaults to {}. @@ -101,7 +101,7 @@ class xml_handler(ContentHandler): """ def __init__(self): - """Initialises xml_handler.""" + """Initializes xml_handler.""" #root xml node with all the data self.root = xml_node(name="root", fields=[]) diff --git a/tools/i-pi/ipi/utils/prng.py b/tools/i-pi/ipi/utils/prng.py index c6626828a9..b6d9e6d21d 100644 --- a/tools/i-pi/ipi/utils/prng.py +++ b/tools/i-pi/ipi/utils/prng.py @@ -34,7 +34,7 @@ import math class Random(object): """Class to interface with the standard pseudo-random number generator. - Initialises the standard numpy pseudo-random number generator from a seed + Initializes the standard numpy pseudo-random number generator from a seed at the beginning of the simulation, and keeps track of the state so that it can be output to the checkpoint files throughout the simulation. @@ -51,11 +51,11 @@ class Random(object): """ def __init__(self, seed=12345, state=None): - """Initialises Random. + """Initializes Random. Args: - seed: An optional seed giving an integer to initialise the state with. - state: An optional state tuple to initialise the state with. + seed: An optional seed giving an integer to initialize the state with. + state: An optional state tuple to initialize the state with. """ self.rng = np.random.mtrand.RandomState(seed=seed) diff --git a/tools/polybond/lmpsdata.py b/tools/polybond/lmpsdata.py index 49e0d32544..52bc749ca6 100644 --- a/tools/polybond/lmpsdata.py +++ b/tools/polybond/lmpsdata.py @@ -881,7 +881,7 @@ class Lmpsdata: class booleanarray: """A class that stores boolean values in a list of lists.""" def __init__(self,rownum, colnum, initval): - """ initialise a list of lists (array) with + """ initialize a list of lists (array) with rownum correspondinig to the number of lists in the list and colnum corresponding to the number of elements in the list's list. initval is the value the list of lists will be initialized with. diff --git a/tools/replica/reorder_remd_traj.py b/tools/replica/reorder_remd_traj.py index 01a179351d..5033ae1e53 100644 --- a/tools/replica/reorder_remd_traj.py +++ b/tools/replica/reorder_remd_traj.py @@ -53,7 +53,7 @@ except ImportError: -#### INITIALISE MPI #### +#### INITIALIZE MPI #### # (note that all output on screen will be printed only on the ROOT proc) ROOT = 0 comm = MPI.COMM_WORLD -- GitLab From 460dd662e4146bd0261b779b942253aa8cf55e4d Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 18 Mar 2020 11:39:53 -0400 Subject: [PATCH 323/689] next chunk of converted atc doc files --- doc/src/atc_hardy_computes.rst | 54 +++++++++++++ doc/src/atc_hardy_fields.rst | 86 +++++++++++++++++++++ doc/src/atc_hardy_gradients.rst | 74 ++++++++++++++++++ doc/src/atc_hardy_kernel.rst | 64 +++++++++++++++ doc/src/atc_hardy_rates.rst | 74 ++++++++++++++++++ doc/src/fix_atc.rst | 10 +-- doc/utils/sphinx-config/false_positives.txt | 5 ++ 7 files changed, 362 insertions(+), 5 deletions(-) create mode 100644 doc/src/atc_hardy_computes.rst create mode 100644 doc/src/atc_hardy_fields.rst create mode 100644 doc/src/atc_hardy_gradients.rst create mode 100644 doc/src/atc_hardy_kernel.rst create mode 100644 doc/src/atc_hardy_rates.rst diff --git a/doc/src/atc_hardy_computes.rst b/doc/src/atc_hardy_computes.rst new file mode 100644 index 0000000000..609740fe99 --- /dev/null +++ b/doc/src/atc_hardy_computes.rst @@ -0,0 +1,54 @@ +.. index:: fix_modify AtC computes + +fix_modify AtC computes command +=============================== + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify computes + +* AtC fixID = ID of :doc:`fix atc ` instance +* computes = name of the AtC sub-command +* *add* or *delete* = add or delete the calculation of an equivalent continuum field for the specified per-atom compute as volume or number density quantity +* per-atom compute-ID = ID of a per-atom compute; fields can be calculated for all per-atom computes available in LAMMPS +* *volume* or *number* = select whether the created field is a per-unit-volume quantity or a per-atom quantity as weighted by kernel functions + +Examples +"""""""" + +.. code-block:: LAMMPS + + compute virial all stress/atom + fix_modify AtC computes add virial volume + fix_modify AtC computes delete virial + + compute centrosymmetry all centro/atom + fix_modify AtC computes add centrosymmetry number + +Description +""""""""""" + +Calculates continuum fields corresponding to specified per-atom +:doc:`computes ` created by LAMMPS. + +Restrictions +"""""""""""" + +Must be used with :doc:`fix atc hardy `. The per-atom compute +must be specified before the corresponding continuum field can be +requested. + +Related AtC commands +"""""""""""""""""""" + +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC fields ` +- :doc:`compute ` + +Default +""""""" + +None. diff --git a/doc/src/atc_hardy_fields.rst b/doc/src/atc_hardy_fields.rst new file mode 100644 index 0000000000..70f3360af8 --- /dev/null +++ b/doc/src/atc_hardy_fields.rst @@ -0,0 +1,86 @@ +.. index:: fix_modify AtC fields + +fix_modify AtC fields command +============================= + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify fields + fix_modify fields + +* AtC fixID = ID of :doc:`fix atc ` instance +* fields = name of the AtC sub-command +* *all* or *none* = output all or no fields +* *add* or *delete* = add or delete the listed output fields +* list_of_fields = one or more of the fields listed below: + + - density : mass per unit volume + - displacement : displacement vector + - momentum : momentum per unit volume + - velocity : defined by momentum divided by density + - projected_velocity : simple kernel estimation of atomic velocities + - temperature : temperature derived from the relative atomic kinetic energy + - kinetic_temperature : temperature derived from the full kinetic energy + - number_density : simple kernel estimation of number of atoms per unit volume + - stress : Cauchy stress tensor for eulerian analysis (atom_element_map), or 1st Piola-Kirchhoff stress tensor for lagrangian analysis + - transformed_stress : 1st Piola-Kirchhoff stress tensor for eulerian analysis (atom_element_map), or Cauchy stress tensor for lagrangian analysis + - heat_flux : spatial heat flux vector for eulerian, or referential heat flux vector for lagrangian + - potential_energy : potential energy per unit volume + - kinetic_energy : kinetic energy per unit volume + - thermal_energy : thermal energy (kinetic energy - continuum kinetic energy) per unit volume + - internal_energy : total internal energy (potential + thermal) per unit volume + - energy : total energy (potential + kinetic) per unit volume + - number_density : number of atoms per unit volume + - eshelby_stress : configurational stress (energy-momentum) tensor defined by [Eshelby]_ + - vacancy_concentration : volume fraction of vacancy content + - type_concentration : volume fraction of a specific atom type + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC fields add velocity temperature + + +Description +""""""""""" + +Allows modification of the fields calculated and output by the AtC +transfer class. The commands are cumulative, e.g.: + +.. code-block:: LAMMPS + + fix_modify AtC fields none + fix_modify AtC fields add velocity temperature + +will only output the velocity and temperature fields. + +Restrictions +"""""""""""" + +Must be used with :doc:`fix atc hardy `. Currently, the stress +and heat flux formulas are only correct for central force potentials, +e.g. Lennard-Jones and EAM but not Stillinger-Weber. + +Related AtC commands +"""""""""""""""""""" + +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC gradients ` +- :doc:`fix_modify AtC rates ` +- :doc:`fix_modify AtC computes ` + + +Default +""""""" + +By default, no fields are output. + +References +"""""""""" + +.. [Eshelby] J.D. Eshelby, Philos. Trans. Royal Soc. London A, Math. Phys. Sci., Vol. 244, No. 877 (1951) pp. 87-112; J. Elasticity, Vol. 5, Nos. 3-4 (1975) pp. 321-335] diff --git a/doc/src/atc_hardy_gradients.rst b/doc/src/atc_hardy_gradients.rst new file mode 100644 index 0000000000..36fad76afe --- /dev/null +++ b/doc/src/atc_hardy_gradients.rst @@ -0,0 +1,74 @@ +.. index:: fix_modify AtC gradients + +fix_modify AtC gradients command +================================ + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify gradients + +* AtC fixID = ID of :doc:`fix atc ` instance +* gradients = name of the AtC sub-command +* *add* or *delete* = select whether to add or delete calculation of gradients for the listed output fields +* list_of_fields = one or more of the fields listed below: + + - density : mass per unit volume + - displacement : displacement vector + - momentum : momentum per unit volume + - velocity : defined by momentum divided by density + - projected_velocity : simple kernel estimation of atomic velocities + - temperature : temperature derived from the relative atomic kinetic energy + - kinetic_temperature : temperature derived from the full kinetic energy + - number_density : simple kernel estimation of number of atoms per unit volume + - stress : Cauchy stress tensor for eulerian analysis (atom_element_map), or 1st Piola-Kirchhoff stress tensor for lagrangian analysis + - transformed_stress : 1st Piola-Kirchhoff stress tensor for eulerian analysis (atom_element_map), or Cauchy stress tensor for lagrangian analysis + - heat_flux : spatial heat flux vector for eulerian, or referential heat flux vector for lagrangian + - potential_energy : potential energy per unit volume + - kinetic_energy : kinetic energy per unit volume + - thermal_energy : thermal energy (kinetic energy - continuum kinetic energy) per unit volume + - internal_energy : total internal energy (potential + thermal) per unit volume + - energy : total energy (potential + kinetic) per unit volume + - number_density : number of atoms per unit volume + - eshelby_stress : configurational stress (energy-momentum) tensor defined by [Eshelby]_ + - vacancy_concentration : volume fraction of vacancy content + - type_concentration : volume fraction of a specific atom type + + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC gradients add temperature velocity stress + fix_modify AtC gradients delete velocity + + +Description +""""""""""" + +Requests calculation and output of gradients of the fields from the AtC +transfer class. These gradients will be with regard to spatial or +material coordinate for Eulerian or Lagrangian analysis, respectively, +as specified by :doc:`fix_modify AtC atom_element_map ` + + +Restrictions +"""""""""""" + +Must be used with :doc:`fix atc hardy `. + +Related AtC commands +"""""""""""""""""""" + +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC atom_element_map ` +- :doc:`fix_modify AtC fields ` +- :doc:`fix_modify AtC rates ` + +Default +""""""" + +None. diff --git a/doc/src/atc_hardy_kernel.rst b/doc/src/atc_hardy_kernel.rst new file mode 100644 index 0000000000..a52f2a9968 --- /dev/null +++ b/doc/src/atc_hardy_kernel.rst @@ -0,0 +1,64 @@ +.. index:: fix_modify AtC kernel + +fix_modify AtC kernel command +============================= + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify kernel + +* AtC fixID = ID of :doc:`fix atc ` instance +* kernel = name of the AtC sub-command +* type = *step* or *cell* or *cubic_bar* or *cubic_cylinder* or + *cubic_sphere* or *quartic_bar* or *quartic_cylinder* or + *quartic_sphere* +* the following parameter(s) are required for each kernel: + + - *step* : + - *cell* : or + - *cubic_bar* : + - *cubic_cylinder* : + - *cubic_sphere* : + - *quartic_bar* : + - *quartic_cylinder* : + - *quartic_sphere* : + + + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC kernel cell 1.0 1.0 1.0 + fix_modify AtC kernel quartic_sphere 10.0 + + +Description +""""""""""" + +Sets the localization kernel type and parameters for :doc:`fix atc hardy `. + +Restrictions +"""""""""""" + +Must be used with :doc:`fix atc hardy `. For bar kernel types, +half-width oriented along x-direction. For cylinder kernel types, +cylindrical axis is assumed to be in z-direction. + +Related AtC commands +"""""""""""""""""""" + +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC fields ` +- :doc:`fix_modify AtC gradients ` +- :doc:`fix_modify AtC rates ` +- :doc:`fix_modify AtC computes ` + +Default +""""""" + +None. diff --git a/doc/src/atc_hardy_rates.rst b/doc/src/atc_hardy_rates.rst new file mode 100644 index 0000000000..890ada0c47 --- /dev/null +++ b/doc/src/atc_hardy_rates.rst @@ -0,0 +1,74 @@ +.. index:: fix_modify AtC rates + +fix_modify AtC rates command +================================ + +Syntax +"""""" + +.. parsed-literal:: + + fix_modify rates + +* AtC fixID = ID of :doc:`fix atc ` instance +* rates = name of the AtC sub-command +* *add* or *delete* = select whether to add or delete calculation of rates for the listed output fields +* list_of_fields = one or more of the fields listed below: + + - density : mass per unit volume + - displacement : displacement vector + - momentum : momentum per unit volume + - velocity : defined by momentum divided by density + - projected_velocity : simple kernel estimation of atomic velocities + - temperature : temperature derived from the relative atomic kinetic energy + - kinetic_temperature : temperature derived from the full kinetic energy + - number_density : simple kernel estimation of number of atoms per unit volume + - stress : Cauchy stress tensor for eulerian analysis (atom_element_map), or 1st Piola-Kirchhoff stress tensor for lagrangian analysis + - transformed_stress : 1st Piola-Kirchhoff stress tensor for eulerian analysis (atom_element_map), or Cauchy stress tensor for lagrangian analysis + - heat_flux : spatial heat flux vector for eulerian, or referential heat flux vector for lagrangian + - potential_energy : potential energy per unit volume + - kinetic_energy : kinetic energy per unit volume + - thermal_energy : thermal energy (kinetic energy - continuum kinetic energy) per unit volume + - internal_energy : total internal energy (potential + thermal) per unit volume + - energy : total energy (potential + kinetic) per unit volume + - number_density : number of atoms per unit volume + - eshelby_stress : configurational stress (energy-momentum) tensor defined by [Eshelby]_ + - vacancy_concentration : volume fraction of vacancy content + - type_concentration : volume fraction of a specific atom type + + +Examples +"""""""" + +.. code-block:: LAMMPS + + fix_modify AtC rates add temperature velocity stress + fix_modify AtC rates delete stress + + +Description +""""""""""" + +Requests calculation and output of rates (time derivatives) of the +fields from the AtC transfer class. For Eulerian analysis (see +:doc:`fix_modify AtC atom_element_map `) these +rates are the partial time derivatives of the nodal fields, not the full +(material) time derivatives. + +Restrictions +"""""""""""" + +Must be used with :doc:`fix atc hardy `. + +Related AtC commands +"""""""""""""""""""" + +- :ref:`fix_modify AtC command overview ` +- :doc:`fix_modify AtC atom_element_map ` +- :doc:`fix_modify AtC fields ` +- :doc:`fix_modify AtC fields ` + +Default +""""""" + +None. diff --git a/doc/src/fix_atc.rst b/doc/src/fix_atc.rst index cffbab3fc1..19e4cffbbb 100644 --- a/doc/src/fix_atc.rst +++ b/doc/src/fix_atc.rst @@ -206,11 +206,11 @@ conditions. *fix_modify* commands for post-processing: -* `fix_modify AtC kernel `_ -* `fix_modify AtC fields `_ -* `fix_modify AtC grdients `_ -* `fix_modify AtC rates `_ -* `fix_modify AtC computes `_ +* :doc:`fix_modify AtC kernel ` +* :doc:`fix_modify AtC fields ` +* :doc:`fix_modify AtC gradients ` +* :doc:`fix_modify AtC rates ` +* :doc:`fix_modify AtC computes ` * `fix_modify AtC on_the_fly `_ * `fix_modify AtC pair_interactions/bond_interactions `_ * `fix_modify AtC sample_frequency `_ diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index 5639be11ea..0c7dfa9ba7 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -820,6 +820,8 @@ erotate Ertas ervel Espanol +Eshelby +eshelby eskm esu esub @@ -1166,6 +1168,8 @@ Hugoniot Hura hux hwloc +hx +hy hydrophobicity hydrostatic hydrostatically @@ -1175,6 +1179,7 @@ hyperdynamics hyperradius hyperspherical hysteretic +hz Ibanez ibar ibm -- GitLab From c28b9f100cac531fccaae435bc90c6d3ca67c583 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 18 Mar 2020 15:38:29 -0400 Subject: [PATCH 324/689] remove unused and broken function --- src/utils.cpp | 23 ----------------------- src/utils.h | 19 ------------------- 2 files changed, 42 deletions(-) diff --git a/src/utils.cpp b/src/utils.cpp index f6556a3ac8..5e0db6afb9 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -84,29 +84,6 @@ bool utils::strmatch(std::string text, std::string pattern) return (pos >= 0); } -/* utility function to avoid code repetition when parsing args */ -int utils::cfvarg(std::string mode, const char *arg, char *&cfv_id) -{ - int rv = utils::NONE; - cfv_id = NULL; - - if (!arg) return rv; - - if (utils::strmatch(arg,std::string("^[") + mode + "]_")) { - if (*arg == 'c') rv = utils::COMPUTE; - else if (*arg == 'f') rv = utils::FIX; - else if (*arg == 'v') rv = utils::VARIABLE; - else return rv; // should not happen - - arg += 2; - int n = strlen(arg)+1; - cfv_id = new char[n]; - strcpy(cfv_id,arg); - } - - return rv; -} - /** \brief try to detect pathname from FILE pointer. Currently only supported on Linux, otherwise will report "(unknown)". * * \param buf storage buffer for pathname. output will be truncated if not large enough diff --git a/src/utils.h b/src/utils.h index e87aa4bb91..45fb95aaac 100644 --- a/src/utils.h +++ b/src/utils.h @@ -36,25 +36,6 @@ namespace LAMMPS_NS { */ bool strmatch(std::string text, std::string pattern); - /** Categories of special arguments for cfvarg() function - * - * Enum starts from 100 to avoid conflicts with other local define flags - */ - enum {NONE=100, /// does not match any category - COMPUTE, /// processed a compute - FIX, /// processed a fix - VARIABLE /// processed a variable - }; - - /** \brief Convenience function to process 'c_', 'f_', and 'v_' arguments - * - * \param mode types to search for. 1-3 char string from 'c', 'f', or 'v' - * \param arg argument string to test against the prefixes - * \param cfv_id name or ID of the compute, fix, or variable - * \return utils::COMPUTE, utils::FIX, utils::VARIABLE or utils::NONE - */ - int cfvarg(std::string mode, const char *arg, char *&cfv_id); - /** \brief safe wrapper around fgets() which aborts on errors * or EOF and prints a suitable error message to help debugging * -- GitLab From b903cc6dc7162961739dc51d7974ffdfa3247a13 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 18 Mar 2020 17:12:36 -0400 Subject: [PATCH 325/689] remove excessive details about how to compile with cmake. refer to cmake docs. --- doc/src/Build_cmake.rst | 36 +++++++++++++++++------------------ doc/src/Build_development.rst | 6 ------ 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/doc/src/Build_cmake.rst b/doc/src/Build_cmake.rst index 206fd05253..981fd1e42e 100644 --- a/doc/src/Build_cmake.rst +++ b/doc/src/Build_cmake.rst @@ -22,7 +22,7 @@ Makefile(s). Example: cd lammps # change to the LAMMPS distribution directory mkdir build; cd build # create a new directory (folder) for build cmake [options ...] ../cmake # configuration with (command-line) cmake - make # compilation (or use "cmbuild" from "tools/cmake") + cmake --build . # compilation (or type "make") The ``cmake`` command will detect available features, enable selected packages and options, and will generate the build environment. By default @@ -30,24 +30,22 @@ this build environment will be created for "Unix Makefiles" on most platforms and particularly on Linux. However, alternate build tools (e.g. Ninja) and project files for Integrated Development Environments (IDEs) like Eclipse, CodeBlocks, or Kate can be generated, too. This is -selected via the ``-G`` command line flag. For the rest of the documentation -we will assume that the build environment is generated for makefiles +selected via the ``-G`` command line flag. Further details about features +and settings for CMake are in the `CMake online documentation `_ + +.. _cmake_doc: https://cmake.org/documentation/ + +For the rest of the documentation +we will assume that the build environment is generated for "Unix Makefiles" and thus the ``make`` command will be used to compile and link LAMMPS as indicated above, producing (by default) an executable called ``lmp`` and -a library called ``liblammps.a`` in the ``build`` folder. When generating -a build environment for the "Ninja" build tool, the build command would -be ``ninja`` instead of ``make``. Or you may copy the ``cmbuild`` script -from the :ref:`tools/cmake folder ` somewhere in your path and use that, -as it will indirectly call CMake with the configured tool. This is -particularly, if you configured the build folder with a build tool -in a non-standard location or name using ``-D CMAKE_MAKE_PROGRAM=``. - -If your machine has multiple CPU cores (most do these days), using a -command like ``make -j N`` (with N being the number of available local -CPU cores) can be much faster. If you plan to do development on -LAMMPS or need to re-compile LAMMPS repeatedly, installation of the -``ccache`` (= Compiler Cache) software may speed up repeated compilation -even more. +a library called ``liblammps.a`` in the ``build`` folder. + +If your machine has multiple CPU cores (most do these days), you can +parallelize the compilation with a command like ``make -j N`` (with N +being the number of designated CPU cores). Also installation of +the ``ccache`` (= Compiler Cache) software may speed up repeated +compilation signficantly. After compilation, you may optionally install the LAMMPS executable into your system with: @@ -129,7 +127,7 @@ command-line options. Several useful ones are: -D CMAKE_INSTALL_PREFIX=path # where to install LAMMPS executable/lib if desired -D CMAKE_BUILD_TYPE=type # type = RelWithDebInfo (default), Release, MinSizeRel, or Debug -G output # style of output CMake generates (e.g. "Unix Makefiles" or "Ninja") - -D CMAKE_MAKE_PROGRAM=builder # name of the builder executable (e.g. set to "gmake" instead of "make") + -D CMAKE_MAKE_PROGRAM=builder # name of the builder executable (e.g. when using "gmake" instead of "make") -DVARIABLE=value # setting for a LAMMPS feature to enable -D VARIABLE=value # ditto, but cannot come after CMakeLists.txt dir -C path/to/preset/file # load some CMake settings before configuring @@ -143,7 +141,7 @@ these forms can be used: yes/no, on/off, 1/0. On Unix/Linux machines, CMake generates a Makefile by default to perform the LAMMPS build. Alternate forms of build info can be generated via the -G switch, e.g. Visual Studio on a Windows machine, -Xcode on MacOS, or KDevelop on Linux. Type "cmake --help" to see the +Xcode on MacOS, or KDevelop on Linux. Type ``cmake --help`` to see the "Generator" styles of output your system supports. .. note:: diff --git a/doc/src/Build_development.rst b/doc/src/Build_development.rst index 598153e3f0..53d97a73f4 100644 --- a/doc/src/Build_development.rst +++ b/doc/src/Build_development.rst @@ -25,12 +25,6 @@ Another way of doing this without reconfiguration is calling make with variable make VERBOSE=1 -Or when using the :ref:`"cmbuild" wrapper script `: - -.. code-block:: bash - - cmbuild -v - ---------- .. _sanitizer: -- GitLab From 2cefddb16c0617814dda4c921b1e33fd00dfb30f Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 18 Mar 2020 17:16:47 -0400 Subject: [PATCH 326/689] avoid spelling errors --- doc/src/Build_cmake.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/src/Build_cmake.rst b/doc/src/Build_cmake.rst index 981fd1e42e..06e5a87594 100644 --- a/doc/src/Build_cmake.rst +++ b/doc/src/Build_cmake.rst @@ -42,10 +42,10 @@ indicated above, producing (by default) an executable called ``lmp`` and a library called ``liblammps.a`` in the ``build`` folder. If your machine has multiple CPU cores (most do these days), you can -parallelize the compilation with a command like ``make -j N`` (with N -being the number of designated CPU cores). Also installation of -the ``ccache`` (= Compiler Cache) software may speed up repeated -compilation signficantly. +compile sources in parallel with a command like ``make -j N`` (with N +being the maximum number of concurrently executed tasks). Also +installation of the ``ccache`` (= Compiler Cache) software may speed +up repeated compilation, e.g. during code development, significantly. After compilation, you may optionally install the LAMMPS executable into your system with: -- GitLab From b6ce32f651826f72ff40b4b636b3efbff7344c05 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 18 Mar 2020 17:18:46 -0400 Subject: [PATCH 327/689] step version string for next patch release --- doc/lammps.1 | 2 +- src/version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/lammps.1 b/doc/lammps.1 index 1368679d3c..d2851603c6 100644 --- a/doc/lammps.1 +++ b/doc/lammps.1 @@ -1,4 +1,4 @@ -.TH LAMMPS "3 March 2020" "2020-03-03" +.TH LAMMPS "19 March 2020" "2020-03-19" .SH NAME .B LAMMPS \- Molecular Dynamics Simulator. diff --git a/src/version.h b/src/version.h index 504992bc4b..774a0a4b96 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define LAMMPS_VERSION "3 Mar 2020" +#define LAMMPS_VERSION "19 Mar 2020" -- GitLab From 7824b3f4abe5413e62f45cb3f09d18b66041e0ab Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 18 Mar 2020 17:52:19 -0400 Subject: [PATCH 328/689] small html theme tweaks to unclutter top of page. move version string to navigation bar --- doc/utils/sphinx-config/_themes/lammps_theme/breadcrumbs.html | 3 +-- doc/utils/sphinx-config/_themes/lammps_theme/layout.html | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/utils/sphinx-config/_themes/lammps_theme/breadcrumbs.html b/doc/utils/sphinx-config/_themes/lammps_theme/breadcrumbs.html index 1eb53c70a2..5a8ef8ab94 100644 --- a/doc/utils/sphinx-config/_themes/lammps_theme/breadcrumbs.html +++ b/doc/utils/sphinx-config/_themes/lammps_theme/breadcrumbs.html @@ -1,5 +1,4 @@
    -
    LAMMPS {{ version }}
    • Docs »
    • {% for doc in parents %} @@ -22,7 +21,7 @@ {% endif %}
    -
    +
    {% if next or prev %}
    + + LAMMPS_OMP_COMPAT + Workaround for backwards-incompatible changes regarding predetermined sharing modes in OpenMP 4.x. A value of 3 or 4 should be used, reflecting the version of the OpenMP spec that is implemented by the compiler. + +
    +
    3 (default except for known OMP 4.0 compilers)
    +
    4
    +
    + + LAMMPS_MEMALIGN controls the alignment of blocks of memory allocated by LAMMPS diff --git a/doc/src/Build_basics.rst b/doc/src/Build_basics.rst index 96bc0f5bd1..62b16d9a03 100644 --- a/doc/src/Build_basics.rst +++ b/doc/src/Build_basics.rst @@ -147,7 +147,8 @@ semantics, which are incompatible with the OpenMP 3.1 semantics used in LAMMPS (for maximal compatibility with compiler versions in use). LAMMPS will try to detect compilers that use OpenMP 4.0 semantics and change the directives accordingly, but if your compiler is not -detected, you may set the CMake variable ``-D LMP_OMP_COMPAT=4``. +detected, you may set the define ``-D LAMMPS_OMP_COMPAT=4`` in ``LMP_INC`` +or the CMake build command. ---------- diff --git a/src/omp_compat.h b/src/omp_compat.h index 8abf1c54bc..add429eea8 100644 --- a/src/omp_compat.h +++ b/src/omp_compat.h @@ -25,7 +25,7 @@ // so this is what LAMMPS primarily uses. For those compilers // that strictly implement OpenMP 4.0 (such as GCC 9.0), we // give up default(none). -#if LMP_OMP_COMPAT == 4 +#if LAMMPS_OMP_COMPAT == 4 # define LMP_SHARED(...) # define LMP_DEFAULT_NONE default(shared) #else -- GitLab From f560cd6dd596857d14d3663e3c225fbaec2096d0 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 21 Mar 2020 01:08:09 -0400 Subject: [PATCH 364/689] make certain, the molecular flag is always initialized --- src/atom_vec.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/atom_vec.cpp b/src/atom_vec.cpp index 7b89c2fd79..c4dd53ad18 100644 --- a/src/atom_vec.cpp +++ b/src/atom_vec.cpp @@ -36,6 +36,7 @@ AtomVec::AtomVec(LAMMPS *lmp) : Pointers(lmp) forceclearflag = 0; size_data_bonus = 0; maxexchange = 0; + molecular = 0; kokkosable = 0; -- GitLab From 79b84c0847d0f9504527ce0b5dcb99688af2943c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 22 Mar 2020 15:44:28 -0400 Subject: [PATCH 365/689] more thorough checking if BUILD_OMP may be enabled by default. we need the OpenMP runtime, too. --- cmake/CMakeLists.txt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 4dd079eaae..36bed2d649 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -227,7 +227,15 @@ pkg_depends(USER-LB MPI) pkg_depends(USER-PHONON KSPACE) pkg_depends(USER-SCAFACOS MPI) +# detect if we may enable OpenMP support by default +set(BUILD_OMP_DEFAULT OFF) find_package(OpenMP QUIET) +if(OpenMP_FOUND) + check_include_file_cxx(omp.h HAVE_OMP_H_INCLUDE) + if(HAVE_OMP_H_INCLUDE) + set(BUILD_OMP_DEFAULT ON) + endif() +endif() # TODO: this is a temporary workaround until a better solution is found. AK 2019-05-30 # GNU GCC 9.x uses settings incompatible with our use of 'default(none)' in OpenMP pragmas @@ -237,14 +245,14 @@ find_package(OpenMP QUIET) if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.99.9)) option(BUILD_OMP "Build with OpenMP support" OFF) else() - option(BUILD_OMP "Build with OpenMP support" ${OpenMP_FOUND}) + option(BUILD_OMP "Build with OpenMP support" ${BUILD_OMP_DEFAULT}) endif() if(BUILD_OMP) find_package(OpenMP REQUIRED) check_include_file_cxx(omp.h HAVE_OMP_H_INCLUDE) if(NOT HAVE_OMP_H_INCLUDE) - message(FATAL_ERROR "Cannot find required 'omp.h' header file") + message(FATAL_ERROR "Cannot find the 'omp.h' header file required for full OpenMP support") endif() set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") -- GitLab From 62cb760ee2ea8172f621201f04417c9d60bf9474 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 22 Mar 2020 14:42:29 -0600 Subject: [PATCH 366/689] cmake: remove LIB_SOURCES and LMP_SOURCES --- cmake/CMakeLists.txt | 30 ++++++++++++------------- cmake/Modules/Packages/CORESHELL.cmake | 2 +- cmake/Modules/Packages/GPU.cmake | 2 +- cmake/Modules/Packages/KOKKOS.cmake | 2 +- cmake/Modules/Packages/OPT.cmake | 2 +- cmake/Modules/Packages/QEQ.cmake | 2 +- cmake/Modules/Packages/USER-INTEL.cmake | 2 +- cmake/Modules/Packages/USER-OMP.cmake | 2 +- cmake/Modules/Packages/USER-SDPD.cmake | 4 +++- 9 files changed, 25 insertions(+), 23 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 4dd079eaae..eb5700b19d 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -21,11 +21,6 @@ if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "$ENV{HOME}/.local" CACHE PATH "default install path" FORCE ) endif() -# To avoid conflicts with the conventional Makefile build system, we build everything here -file(GLOB LIB_SOURCES ${LAMMPS_SOURCE_DIR}/[^.]*.cpp) -file(GLOB LMP_SOURCES ${LAMMPS_SOURCE_DIR}/main.cpp) -list(REMOVE_ITEM LIB_SOURCES ${LMP_SOURCES}) - # Cmake modules/macros are in a subdirectory to keep this file cleaner set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Modules) @@ -110,8 +105,19 @@ endif() option(BUILD_TOOLS "Build and install LAMMPS tools (msi2lmp, binary2txt, chain)" OFF) -if(NOT BUILD_EXE AND NOT BUILD_LIB) - message(FATAL_ERROR "You need to at least enable one of two following options: BUILD_LIB or BUILD_EXE") +if(BUILD_LIB) + file(GLOB MAIN_SOURCES ${LAMMPS_SOURCE_DIR}/main.cpp) + list(REMOVE_ITEM ALL_SOURCES ${MAIN_SOURCES}) + add_library(lammps ${ALL_SOURCES}) + if(BUILD_EXE) + add_executable(lmp ${MAIN_SOURCES}) + target_link_libraries(lmp PRIVATE lammps) + endif() +else() + if(NOT BUILD_EXE) + message(FATAL_ERROR "You need to at least enable one of two following options: BUILD_LIB or BUILD_EXE") + endif() + add_executable(lammps ${ALL_SOURCES}) endif() option(CMAKE_VERBOSE_MAKEFILE "Generate verbose Makefiles" OFF) @@ -391,7 +397,7 @@ foreach(PKG ${DEFAULT_PACKAGES}) # detects styles in package and adds them to global list RegisterStyles(${${PKG}_SOURCES_DIR}) - list(APPEND LIB_SOURCES ${${PKG}_SOURCES}) + target_sources(lammps PRIVATE ${${PKG}_SOURCES}) include_directories(${${PKG}_SOURCES_DIR}) endif() @@ -533,7 +539,6 @@ if (${_index} GREATER -1) endif() list(REMOVE_DUPLICATES LAMMPS_LINK_LIBS) if(BUILD_LIB) - add_library(lammps ${LIB_SOURCES}) target_link_libraries(lammps ${LAMMPS_LINK_LIBS}) if(LAMMPS_DEPS) add_dependencies(lammps ${LAMMPS_DEPS}) @@ -579,15 +584,10 @@ if(BUILD_LIB) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/liblammps${LAMMPS_LIB_SUFFIX}.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) configure_file(FindLAMMPS.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FindLAMMPS${LAMMPS_LIB_SUFFIX}.cmake @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/FindLAMMPS${LAMMPS_LIB_SUFFIX}.cmake DESTINATION ${CMAKE_INSTALL_DATADIR}/cmake/Modules) -else() - list(APPEND LMP_SOURCES ${LIB_SOURCES}) endif() if(BUILD_EXE) - add_executable(lmp ${LMP_SOURCES}) - if(BUILD_LIB) - target_link_libraries(lmp lammps) - else() + if(NOT BUILD_LIB) target_link_libraries(lmp ${LAMMPS_LINK_LIBS}) if(LAMMPS_DEPS) add_dependencies(lmp ${LAMMPS_DEPS}) diff --git a/cmake/Modules/Packages/CORESHELL.cmake b/cmake/Modules/Packages/CORESHELL.cmake index 591477c899..2afe2b8c1b 100644 --- a/cmake/Modules/Packages/CORESHELL.cmake +++ b/cmake/Modules/Packages/CORESHELL.cmake @@ -8,6 +8,6 @@ if(PKG_CORESHELL) get_property(CORESHELL_SOURCES GLOBAL PROPERTY CORESHELL_SOURCES) - list(APPEND LIB_SOURCES ${CORESHELL_SOURCES}) + target_sources(lammps PRIVATE ${CORESHELL_SOURCES}) include_directories(${CORESHELL_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/GPU.cmake b/cmake/Modules/Packages/GPU.cmake index abbcb1f495..e8ca4d35ab 100644 --- a/cmake/Modules/Packages/GPU.cmake +++ b/cmake/Modules/Packages/GPU.cmake @@ -192,6 +192,6 @@ if(PKG_GPU) get_property(GPU_SOURCES GLOBAL PROPERTY GPU_SOURCES) - list(APPEND LIB_SOURCES ${GPU_SOURCES}) + target_sources(lammps PRIVATE ${GPU_SOURCES}) include_directories(${GPU_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/KOKKOS.cmake b/cmake/Modules/Packages/KOKKOS.cmake index 29beaca957..4b871ccb46 100644 --- a/cmake/Modules/Packages/KOKKOS.cmake +++ b/cmake/Modules/Packages/KOKKOS.cmake @@ -69,6 +69,6 @@ if(PKG_KOKKOS) get_property(KOKKOS_PKG_SOURCES GLOBAL PROPERTY KOKKOS_PKG_SOURCES) - list(APPEND LIB_SOURCES ${KOKKOS_PKG_SOURCES}) + target_sources(lammps PRIVATE ${KOKKOS_PKG_SOURCES}) include_directories(${KOKKOS_PKG_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/OPT.cmake b/cmake/Modules/Packages/OPT.cmake index f2802c757b..02e3877c59 100644 --- a/cmake/Modules/Packages/OPT.cmake +++ b/cmake/Modules/Packages/OPT.cmake @@ -8,6 +8,6 @@ if(PKG_OPT) get_property(OPT_SOURCES GLOBAL PROPERTY OPT_SOURCES) - list(APPEND LIB_SOURCES ${OPT_SOURCES}) + target_sources(lammps PRIVATE ${OPT_SOURCES}) include_directories(${OPT_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/QEQ.cmake b/cmake/Modules/Packages/QEQ.cmake index 94cca30540..9b151c2610 100644 --- a/cmake/Modules/Packages/QEQ.cmake +++ b/cmake/Modules/Packages/QEQ.cmake @@ -15,6 +15,6 @@ if(PKG_QEQ) endforeach() get_property(QEQ_SOURCES GLOBAL PROPERTY QEQ_SOURCES) - list(APPEND LIB_SOURCES ${QEQ_SOURCES}) + target_sources(lammps PRIVATE ${QEQ_SOURCES}) include_directories(${QEQ_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/USER-INTEL.cmake b/cmake/Modules/Packages/USER-INTEL.cmake index d0941a0a12..7b08a7b459 100644 --- a/cmake/Modules/Packages/USER-INTEL.cmake +++ b/cmake/Modules/Packages/USER-INTEL.cmake @@ -108,6 +108,6 @@ if(PKG_USER-INTEL) RegisterIntegrateStyle(${USER-INTEL_SOURCES_DIR}/verlet_lrt_intel.h) endif() - list(APPEND LIB_SOURCES ${USER-INTEL_SOURCES}) + target_sources(lammps PRIVATE ${USER-INTEL_SOURCES}) include_directories(${USER-INTEL_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/USER-OMP.cmake b/cmake/Modules/Packages/USER-OMP.cmake index 668f42f10a..4b1a4b1571 100644 --- a/cmake/Modules/Packages/USER-OMP.cmake +++ b/cmake/Modules/Packages/USER-OMP.cmake @@ -37,6 +37,6 @@ if(PKG_USER-OMP) ${USER-OMP_SOURCES_DIR}/reaxc_valence_angles_omp.cpp) endif() - list(APPEND LIB_SOURCES ${USER-OMP_SOURCES}) + target_sources(lammps PRIVATE ${USER-OMP_SOURCES}) include_directories(${USER-OMP_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/USER-SDPD.cmake b/cmake/Modules/Packages/USER-SDPD.cmake index 530dcf2bd9..1105fbd7ce 100644 --- a/cmake/Modules/Packages/USER-SDPD.cmake +++ b/cmake/Modules/Packages/USER-SDPD.cmake @@ -5,7 +5,9 @@ if(PKG_USER-SDPD) get_property(hlist GLOBAL PROPERTY FIX) if(NOT PKG_RIGID) list(REMOVE_ITEM hlist ${USER-SDPD_SOURCES_DIR}/fix_rigid_meso.h) - list(REMOVE_ITEM LIB_SOURCES ${USER-SDPD_SOURCES_DIR}/fix_rigid_meso.cpp) + get_target_property(LAMMPS_SOURCES lammps SOURCES) + list(REMOVE_ITEM LAMMPS_SOURCES ${USER-SDPD_SOURCES_DIR}/fix_rigid_meso.cpp) + set_property(TARGET lammps PROPERTY SOURCES ${LAMMPS_SOURCES}) endif() set_property(GLOBAL PROPERTY FIX "${hlist}") -- GitLab From cd89a7c4b7edb877694e07a91edc558a94845f12 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 22 Mar 2020 18:03:07 -0600 Subject: [PATCH 367/689] cmake: fix renamed target for exe --- cmake/CMakeLists.txt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index eb5700b19d..0fae7f55bf 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -105,12 +105,14 @@ endif() option(BUILD_TOOLS "Build and install LAMMPS tools (msi2lmp, binary2txt, chain)" OFF) +file(GLOB ALL_SOURCES ${LAMMPS_SOURCE_DIR}/[^.]*.cpp) if(BUILD_LIB) file(GLOB MAIN_SOURCES ${LAMMPS_SOURCE_DIR}/main.cpp) list(REMOVE_ITEM ALL_SOURCES ${MAIN_SOURCES}) add_library(lammps ${ALL_SOURCES}) if(BUILD_EXE) add_executable(lmp ${MAIN_SOURCES}) + set(LAMMPS_EXE lmp) target_link_libraries(lmp PRIVATE lammps) endif() else() @@ -118,6 +120,7 @@ else() message(FATAL_ERROR "You need to at least enable one of two following options: BUILD_LIB or BUILD_EXE") endif() add_executable(lammps ${ALL_SOURCES}) + set(LAMMPS_EXE lammps) endif() option(CMAKE_VERBOSE_MAKEFILE "Generate verbose Makefiles" OFF) @@ -588,14 +591,14 @@ endif() if(BUILD_EXE) if(NOT BUILD_LIB) - target_link_libraries(lmp ${LAMMPS_LINK_LIBS}) + target_link_libraries(${LAMMPS_EXE} ${LAMMPS_LINK_LIBS}) if(LAMMPS_DEPS) - add_dependencies(lmp ${LAMMPS_DEPS}) + add_dependencies(${LAMMPS_EXE} ${LAMMPS_DEPS}) endif() endif() - set_target_properties(lmp PROPERTIES OUTPUT_NAME ${LAMMPS_BINARY}) - install(TARGETS lmp DESTINATION ${CMAKE_INSTALL_BINDIR}) + set_target_properties(${LAMMPS_EXE} PROPERTIES OUTPUT_NAME ${LAMMPS_BINARY}) + install(TARGETS ${LAMMPS_EXE} DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ${LAMMPS_DOC_DIR}/lammps.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 RENAME ${LAMMPS_BINARY}.1) endif() -- GitLab From 5828815b3ec50845be1a312056de559c05bbff1a Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 22 Mar 2020 18:55:53 -0600 Subject: [PATCH 368/689] cmake: remove LAMMPS_LINK_LIBS --- cmake/CMakeLists.txt | 28 ++++++---------- cmake/Modules/Packages/COMPRESS.cmake | 3 +- cmake/Modules/Packages/GPU.cmake | 4 +-- cmake/Modules/Packages/KIM.cmake | 5 ++- cmake/Modules/Packages/KOKKOS.cmake | 6 ++-- cmake/Modules/Packages/KSPACE.cmake | 6 ++-- cmake/Modules/Packages/LATTE.cmake | 2 +- cmake/Modules/Packages/MESSAGE.cmake | 2 +- cmake/Modules/Packages/MSCG.cmake | 2 +- cmake/Modules/Packages/PYTHON.cmake | 2 +- cmake/Modules/Packages/USER-COLVARS.cmake | 4 +-- cmake/Modules/Packages/USER-INTEL.cmake | 6 ++-- cmake/Modules/Packages/USER-MOLFILE.cmake | 2 +- cmake/Modules/Packages/USER-NETCDF.cmake | 4 +-- cmake/Modules/Packages/USER-PLUMED.cmake | 8 ++--- cmake/Modules/Packages/USER-QMMM.cmake | 2 +- cmake/Modules/Packages/USER-QUIP.cmake | 2 +- cmake/Modules/Packages/USER-SCAFACOS.cmake | 38 +++++++++++----------- cmake/Modules/Packages/USER-VTK.cmake | 2 +- cmake/Modules/Packages/VORONOI.cmake | 2 +- 20 files changed, 60 insertions(+), 70 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 0fae7f55bf..9190374a2e 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -126,7 +126,6 @@ endif() option(CMAKE_VERBOSE_MAKEFILE "Generate verbose Makefiles" OFF) include(GNUInstallDirs) -set(LAMMPS_LINK_LIBS) set(LAMMPS_DEPS) set(LAMMPS_API_DEFINES) @@ -173,7 +172,7 @@ if(PKG_USER-ADIOS) # script that defines the MPI::MPI_C target enable_language(C) find_package(ADIOS2 REQUIRED) - list(APPEND LAMMPS_LINK_LIBS adios2::adios2) + target_link_libraries(lammps PRIVATE adios2::adios2) endif() # do MPI detection after language activation, @@ -188,9 +187,8 @@ if(BUILD_MPI) include(MPI4WIN) else() find_package(MPI REQUIRED) - include_directories(${MPI_CXX_INCLUDE_PATH}) add_definitions(-DMPICH_SKIP_MPICXX -DOMPI_SKIP_MPICXX=1) - list(APPEND LAMMPS_LINK_LIBS ${MPI_CXX_LIBRARIES}) + target_link_libraries(lammps PRIVATE MPI::MPI_CXX) option(LAMMPS_LONGLONG_TO_LONG "Workaround if your system or MPI version does not recognize 'long long' data types" OFF) if(LAMMPS_LONGLONG_TO_LONG) add_definitions(-DLAMMPS_LONGLONG_TO_LONG) @@ -201,7 +199,7 @@ else() file(GLOB MPI_SOURCES ${LAMMPS_SOURCE_DIR}/STUBS/mpi.c) add_library(mpi_stubs STATIC ${MPI_SOURCES}) include_directories(${LAMMPS_SOURCE_DIR}/STUBS) - list(APPEND LAMMPS_LINK_LIBS mpi_stubs) + target_link_libraries(lammps PRIVATE mpi_stubs) endif() set(LAMMPS_SIZES "smallbig" CACHE STRING "LAMMPS integer sizes (smallsmall: all 32-bit, smallbig: 64-bit #atoms #timesteps, bigbig: also 64-bit imageint, 64-bit atom ids)") @@ -284,8 +282,7 @@ option(WITH_JPEG "Enable JPEG support" ${JPEG_FOUND}) if(WITH_JPEG) find_package(JPEG REQUIRED) add_definitions(-DLAMMPS_JPEG) - include_directories(${JPEG_INCLUDE_DIR}) - list(APPEND LAMMPS_LINK_LIBS ${JPEG_LIBRARIES}) + target_link_libraries(lammps PRIVATE JPEG::JPEG) endif() find_package(PNG QUIET) @@ -298,8 +295,7 @@ endif() if(WITH_PNG) find_package(PNG REQUIRED) find_package(ZLIB REQUIRED) - include_directories(${PNG_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS ${PNG_LIBRARIES} ${ZLIB_LIBRARIES}) + target_link_libraries(lammps PRIVATE PNG::PNG ZLIB::ZLIB) add_definitions(-DLAMMPS_PNG) endif() @@ -376,7 +372,7 @@ include(CheckLibraryExists) # message(FATAL_ERROR "Could not find needed math function - ${FUNC}") # endif(NOT FOUND_${FUNC}_${MATH_LIBRARIES}) #endforeach(FUNC) -list(APPEND LAMMPS_LINK_LIBS ${MATH_LIBRARIES}) +target_link_libraries(lammps PRIVATE ${MATH_LIBRARIES}) ###################################### # Generate Basic Style files @@ -442,7 +438,7 @@ foreach(SIMPLE_LIB POEMS USER-ATC USER-AWPMD USER-H5MD) if(LAMMPS_USE_MPI4WIN) add_dependencies(${PKG_LIB} mpi4win_build) endif() - list(APPEND LAMMPS_LINK_LIBS ${PKG_LIB}) + target_link_libraries(lammps PRIVATE ${PKG_LIB}) if(PKG_LIB STREQUAL awpmd) target_include_directories(awpmd PUBLIC ${LAMMPS_LIB_SOURCE_DIR}/awpmd/systems/interact ${LAMMPS_LIB_SOURCE_DIR}/awpmd/ivutils/include) elseif(PKG_LIB STREQUAL h5md) @@ -486,9 +482,9 @@ include(Packages/GPU) ###################################################################### if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") if(LAMMPS_USE_MPI4WIN) - list(APPEND LAMMPS_LINK_LIBS ${MPI4WIN_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${MPI4WIN_LIBRARIES}) endif() - list(APPEND LAMMPS_LINK_LIBS -lwsock32 -lpsapi) + target_link_libraries(lammps PRIVATE -lwsock32 -lpsapi) endif() ###################################################### @@ -538,11 +534,9 @@ list(APPEND LAMMPS_DEPS gitversion) get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) list (FIND LANGUAGES "Fortran" _index) if (${_index} GREATER -1) - list(APPEND LAMMPS_LINK_LIBS ${CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES}) endif() -list(REMOVE_DUPLICATES LAMMPS_LINK_LIBS) if(BUILD_LIB) - target_link_libraries(lammps ${LAMMPS_LINK_LIBS}) if(LAMMPS_DEPS) add_dependencies(lammps ${LAMMPS_DEPS}) endif() @@ -591,7 +585,6 @@ endif() if(BUILD_EXE) if(NOT BUILD_LIB) - target_link_libraries(${LAMMPS_EXE} ${LAMMPS_LINK_LIBS}) if(LAMMPS_DEPS) add_dependencies(${LAMMPS_EXE} ${LAMMPS_DEPS}) endif() @@ -736,7 +729,6 @@ if(BUILD_SHARED_LIBS) else() message(STATUS "Static library flags: ${CMAKE_STATIC_LINKER_FLAGS}") endif() -message(STATUS "Link libraries: ${LAMMPS_LINK_LIBS}") if(BUILD_MPI) message(STATUS "Using MPI with headers in ${MPI_CXX_INCLUDE_PATH} and these libraries: ${MPI_CXX_LIBRARIES};${MPI_Fortran_LIBRARIES}") endif() diff --git a/cmake/Modules/Packages/COMPRESS.cmake b/cmake/Modules/Packages/COMPRESS.cmake index 864b868865..ea5d5e37bd 100644 --- a/cmake/Modules/Packages/COMPRESS.cmake +++ b/cmake/Modules/Packages/COMPRESS.cmake @@ -1,5 +1,4 @@ if(PKG_COMPRESS) find_package(ZLIB REQUIRED) - include_directories(${ZLIB_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS ${ZLIB_LIBRARIES}) + target_link_libraries(lammps PRIVATE ZLIB::ZLIB) endif() diff --git a/cmake/Modules/Packages/GPU.cmake b/cmake/Modules/Packages/GPU.cmake index e8ca4d35ab..427644f9c7 100644 --- a/cmake/Modules/Packages/GPU.cmake +++ b/cmake/Modules/Packages/GPU.cmake @@ -107,7 +107,7 @@ if(PKG_GPU) target_compile_definitions(gpu PRIVATE -DUSE_CUDPP) endif() - list(APPEND LAMMPS_LINK_LIBS gpu) + target_link_libraries(lammps PRIVATE gpu) if(LAMMPS_USE_MPI4WIN) add_dependencies(gpu mpi4win_build) endif() @@ -171,7 +171,7 @@ if(PKG_GPU) target_compile_definitions(gpu PRIVATE -D_${GPU_PREC_SETTING} -D${OCL_TUNE}_OCL -DMPI_GERYON -DUCL_NO_EXIT) target_compile_definitions(gpu PRIVATE -DUSE_OPENCL) - list(APPEND LAMMPS_LINK_LIBS gpu) + target_link_libraries(lammps PRIVATE gpu) if(LAMMPS_USE_MPI4WIN) add_dependencies(gpu mpi4win_build) endif() diff --git a/cmake/Modules/Packages/KIM.cmake b/cmake/Modules/Packages/KIM.cmake index 617068ce13..002fbbcaed 100644 --- a/cmake/Modules/Packages/KIM.cmake +++ b/cmake/Modules/Packages/KIM.cmake @@ -2,8 +2,7 @@ if(PKG_KIM) set(KIM-API_MIN_VERSION 2.1) find_package(CURL) if(CURL_FOUND) - include_directories(${CURL_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS ${CURL_LIBRARIES}) + target_link_libraries(lammps PRIVATE CURL::libcurl) add_definitions(-DLMP_KIM_CURL) set(LMP_DEBUG_CURL OFF CACHE STRING "Set libcurl verbose mode on/off. If on, it displays a lot of verbose information about its operations.") mark_as_advanced(LMP_DEBUG_CURL) @@ -62,6 +61,6 @@ if(PKG_KIM) else() find_package(KIM-API ${KIM-API_MIN_VERSION} REQUIRED) endif() - list(APPEND LAMMPS_LINK_LIBS "${KIM-API_LDFLAGS}") + target_link_libraries(lammps PRIVATE "${KIM-API_LDFLAGS}") include_directories(${KIM-API_INCLUDE_DIRS}) endif() diff --git a/cmake/Modules/Packages/KOKKOS.cmake b/cmake/Modules/Packages/KOKKOS.cmake index 4b871ccb46..58d2c139f6 100644 --- a/cmake/Modules/Packages/KOKKOS.cmake +++ b/cmake/Modules/Packages/KOKKOS.cmake @@ -5,7 +5,7 @@ if(PKG_KOKKOS) option(EXTERNAL_KOKKOS "Build against external kokkos library") if(EXTERNAL_KOKKOS) find_package(Kokkos REQUIRED) - list(APPEND LAMMPS_LINK_LIBS Kokkos::kokkos) + target_link_libraries(lammps PRIVATE Kokkos::kokkos) else() set(LAMMPS_LIB_KOKKOS_SRC_DIR ${LAMMPS_LIB_SOURCE_DIR}/kokkos) set(LAMMPS_LIB_KOKKOS_BIN_DIR ${LAMMPS_LIB_BINARY_DIR}/kokkos) @@ -16,7 +16,7 @@ if(PKG_KOKKOS) ${LAMMPS_LIB_KOKKOS_SRC_DIR}/algorithms/src ${LAMMPS_LIB_KOKKOS_BIN_DIR}) include_directories(${Kokkos_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS kokkos) + target_link_libraries(lammps PRIVATE kokkos) endif() add_definitions(-DLMP_KOKKOS) @@ -45,7 +45,7 @@ if(PKG_KOKKOS) if(KOKKOS_ENABLE_CUDA) if(NOT ${FFT} STREQUAL "KISS") add_definitions(-DFFT_CUFFT) - list(APPEND LAMMPS_LINK_LIBS cufft) + target_link_libraries(lammps PRIVATE cufft) endif() endif() endif() diff --git a/cmake/Modules/Packages/KSPACE.cmake b/cmake/Modules/Packages/KSPACE.cmake index 07612447f9..4f92a6963c 100644 --- a/cmake/Modules/Packages/KSPACE.cmake +++ b/cmake/Modules/Packages/KSPACE.cmake @@ -20,7 +20,7 @@ if(PKG_KSPACE) find_package(${FFTW} REQUIRED) add_definitions(-DFFT_FFTW3) include_directories(${${FFTW}_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS ${${FFTW}_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${${FFTW}_LIBRARIES}) if(FFTW3_OMP_LIBRARY OR FFTW3F_OMP_LIBRARY) option(FFT_FFTW_THREADS "Use threaded FFTW library" ON) else() @@ -30,7 +30,7 @@ if(PKG_KSPACE) if(FFT_FFTW_THREADS) if(FFTW3_OMP_LIBRARY OR FFTW3F_OMP_LIBRARY) add_definitions(-DFFT_FFTW_THREADS) - list(APPEND LAMMPS_LINK_LIBS ${${FFTW}_OMP_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${${FFTW}_OMP_LIBRARIES}) else() message(FATAL_ERROR "Need OpenMP enabled FFTW3 library for FFT_THREADS") endif() @@ -43,7 +43,7 @@ if(PKG_KSPACE) add_definitions(-DFFT_MKL_THREADS) endif() include_directories(${MKL_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS ${MKL_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${MKL_LIBRARIES}) else() # last option is KISSFFT add_definitions(-DFFT_KISS) diff --git a/cmake/Modules/Packages/LATTE.cmake b/cmake/Modules/Packages/LATTE.cmake index 9f665d7f0e..55d9b31797 100644 --- a/cmake/Modules/Packages/LATTE.cmake +++ b/cmake/Modules/Packages/LATTE.cmake @@ -36,5 +36,5 @@ if(PKG_LATTE) if(NOT LAPACK_FOUND) add_dependencies(latte_build linalg) endif() - list(APPEND LAMMPS_LINK_LIBS ${LATTE_LIBRARIES} ${LAPACK_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${LATTE_LIBRARIES} ${LAPACK_LIBRARIES}) endif() diff --git a/cmake/Modules/Packages/MESSAGE.cmake b/cmake/Modules/Packages/MESSAGE.cmake index aff9c2964a..c28c50c507 100644 --- a/cmake/Modules/Packages/MESSAGE.cmake +++ b/cmake/Modules/Packages/MESSAGE.cmake @@ -27,6 +27,6 @@ if(PKG_MESSAGE) target_include_directories(cslib PRIVATE ${LAMMPS_LIB_SOURCE_DIR}/message/cslib/src/STUBS_ZMQ) endif() - list(APPEND LAMMPS_LINK_LIBS cslib) + target_link_libraries(lammps PRIVATE cslib) include_directories(${LAMMPS_LIB_SOURCE_DIR}/message/cslib/src) endif() diff --git a/cmake/Modules/Packages/MSCG.cmake b/cmake/Modules/Packages/MSCG.cmake index 35f0c57449..e300ed6ae2 100644 --- a/cmake/Modules/Packages/MSCG.cmake +++ b/cmake/Modules/Packages/MSCG.cmake @@ -43,6 +43,6 @@ if(PKG_MSCG) message(FATAL_ERROR "MSCG not found, help CMake to find it by setting MSCG_LIBRARY and MSCG_INCLUDE_DIRS, or set DOWNLOAD_MSCG=ON to download it") endif() endif() - list(APPEND LAMMPS_LINK_LIBS ${MSCG_LIBRARIES} ${GSL_LIBRARIES} ${LAPACK_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${MSCG_LIBRARIES} GSL::gsl ${LAPACK_LIBRARIES}) include_directories(${MSCG_INCLUDE_DIRS}) endif() diff --git a/cmake/Modules/Packages/PYTHON.cmake b/cmake/Modules/Packages/PYTHON.cmake index 4f8959ae38..7d6e2999f7 100644 --- a/cmake/Modules/Packages/PYTHON.cmake +++ b/cmake/Modules/Packages/PYTHON.cmake @@ -2,5 +2,5 @@ if(PKG_PYTHON) find_package(PythonLibs REQUIRED) add_definitions(-DLMP_PYTHON) include_directories(${PYTHON_INCLUDE_DIR}) - list(APPEND LAMMPS_LINK_LIBS ${PYTHON_LIBRARY}) + target_link_libraries(lammps PRIVATE ${PYTHON_LIBRARY}) endif() diff --git a/cmake/Modules/Packages/USER-COLVARS.cmake b/cmake/Modules/Packages/USER-COLVARS.cmake index a112fbb6aa..2a337b9c8b 100644 --- a/cmake/Modules/Packages/USER-COLVARS.cmake +++ b/cmake/Modules/Packages/USER-COLVARS.cmake @@ -16,10 +16,10 @@ if(PKG_USER-COLVARS) add_library(colvars STATIC ${COLVARS_SOURCES}) target_include_directories(colvars PUBLIC ${LAMMPS_LIB_SOURCE_DIR}/colvars) - list(APPEND LAMMPS_LINK_LIBS colvars) + target_link_libraries(lammps PRIVATE colvars) if(COLVARS_LEPTON) - list(APPEND LAMMPS_LINK_LIBS lepton) + target_link_libraries(lammps PRIVATE lepton) target_compile_options(colvars PRIVATE -DLEPTON) target_include_directories(colvars PUBLIC ${LEPTON_DIR}/include) endif() diff --git a/cmake/Modules/Packages/USER-INTEL.cmake b/cmake/Modules/Packages/USER-INTEL.cmake index 7b08a7b459..0a9b634bc7 100644 --- a/cmake/Modules/Packages/USER-INTEL.cmake +++ b/cmake/Modules/Packages/USER-INTEL.cmake @@ -25,7 +25,7 @@ if(PKG_USER-INTEL) if(INTEL_LRT_MODE STREQUAL "THREADS") if(Threads_FOUND) add_definitions(-DLMP_INTEL_USELRT) - list(APPEND LAMMPS_LINK_LIBS ${CMAKE_THREAD_LIBS_INIT}) + target_link_libraries(lammps PRIVATE Threads::Threads) else() message(FATAL_ERROR "Must have working threads library for Long-range thread support") endif() @@ -44,7 +44,7 @@ if(PKG_USER-INTEL) find_package(TBB QUIET) if(TBB_FOUND) - list(APPEND LAMMPS_LINK_LIBS ${TBB_MALLOC_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${TBB_MALLOC_LIBRARIES}) else() add_definitions(-DLMP_INTEL_NO_TBB) if(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") @@ -55,7 +55,7 @@ if(PKG_USER-INTEL) find_package(MKL QUIET) if(MKL_FOUND) add_definitions(-DLMP_USE_MKL_RNG) - list(APPEND LAMMPS_LINK_LIBS ${MKL_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${MKL_LIBRARIES}) else() message(STATUS "Pair style dpd/intel will be faster with MKL libraries") endif() diff --git a/cmake/Modules/Packages/USER-MOLFILE.cmake b/cmake/Modules/Packages/USER-MOLFILE.cmake index 16ffc34994..cbba1eee7b 100644 --- a/cmake/Modules/Packages/USER-MOLFILE.cmake +++ b/cmake/Modules/Packages/USER-MOLFILE.cmake @@ -6,5 +6,5 @@ if(PKG_USER-MOLFILE) if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows") target_link_libraries(molfile INTERFACE ${CMAKE_DL_LIBS}) endif() - list(APPEND LAMMPS_LINK_LIBS molfile) + target_link_libraries(lammps PRIVATE molfile) endif() diff --git a/cmake/Modules/Packages/USER-NETCDF.cmake b/cmake/Modules/Packages/USER-NETCDF.cmake index 921156f1e0..8d62f5f7ec 100644 --- a/cmake/Modules/Packages/USER-NETCDF.cmake +++ b/cmake/Modules/Packages/USER-NETCDF.cmake @@ -10,13 +10,13 @@ if(PKG_USER-NETCDF) if(NETCDF_FOUND) include_directories(${NETCDF_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS ${NETCDF_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${NETCDF_LIBRARIES}) add_definitions(-DLMP_HAS_NETCDF) endif(NETCDF_FOUND) if(PNETCDF_FOUND) include_directories(${PNETCDF_INCLUDES}) - list(APPEND LAMMPS_LINK_LIBS ${PNETCDF_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${PNETCDF_LIBRARIES}) add_definitions(-DLMP_HAS_PNETCDF) endif(PNETCDF_FOUND) diff --git a/cmake/Modules/Packages/USER-PLUMED.cmake b/cmake/Modules/Packages/USER-PLUMED.cmake index 426ae2df2a..9669f1955c 100644 --- a/cmake/Modules/Packages/USER-PLUMED.cmake +++ b/cmake/Modules/Packages/USER-PLUMED.cmake @@ -70,12 +70,12 @@ if(PKG_USER-PLUMED) list(APPEND LAMMPS_DEPS plumed_build) if(PLUMED_MODE STREQUAL "STATIC") add_definitions(-D__PLUMED_WRAPPER_CXX=1) - list(APPEND LAMMPS_LINK_LIBS ${PLUMED_INSTALL_DIR}/lib/libplumed.a ${PLUMED_LINK_LIBS} ${CMAKE_DL_LIBS}) + target_link_libraries(lammps ${PLUMED_INSTALL_DIR}/lib/libplumed.a ${PLUMED_LINK_LIBS} ${CMAKE_DL_LIBS}) elseif(PLUMED_MODE STREQUAL "SHARED") - list(APPEND LAMMPS_LINK_LIBS ${PLUMED_INSTALL_DIR}/lib/libplumed${CMAKE_SHARED_LIBRARY_SUFFIX} ${PLUMED_INSTALL_DIR}/lib/libplumedKernel${CMAKE_SHARED_LIBRARY_SUFFIX} ${CMAKE_DL_LIBS}) + target_link_libraries(lammps PRIVATE ${PLUMED_INSTALL_DIR}/lib/libplumed${CMAKE_SHARED_LIBRARY_SUFFIX} ${PLUMED_INSTALL_DIR}/lib/libplumedKernel${CMAKE_SHARED_LIBRARY_SUFFIX} ${CMAKE_DL_LIBS}) elseif(PLUMED_MODE STREQUAL "RUNTIME") add_definitions(-D__PLUMED_HAS_DLOPEN=1 -D__PLUMED_DEFAULT_KERNEL=${PLUMED_INSTALL_DIR}/lib/libplumedKernel${CMAKE_SHARED_LIBRARY_SUFFIX}) - list(APPEND LAMMPS_LINK_LIBS ${PLUMED_INSTALL_DIR}/lib/libplumedWrapper.a -rdynamic ${CMAKE_DL_LIBS}) + target_link_libraries(lammps PRIVATE ${PLUMED_INSTALL_DIR}/lib/libplumedWrapper.a -rdynamic ${CMAKE_DL_LIBS}) endif() set(PLUMED_INCLUDE_DIRS "${PLUMED_INSTALL_DIR}/include") else() @@ -90,7 +90,7 @@ if(PKG_USER-PLUMED) add_definitions(-D__PLUMED_HAS_DLOPEN=1 -D__PLUMED_DEFAULT_KERNEL=${PLUMED_LIBDIR}/libplumedKernel${CMAKE_SHARED_LIBRARY_SUFFIX}) include(${PLUMED_LIBDIR}/plumed/src/lib/Plumed.cmake.runtime) endif() - list(APPEND LAMMPS_LINK_LIBS ${PLUMED_LOAD}) + target_link_libraries(lammps PRIVATE ${PLUMED_LOAD}) endif() include_directories(${PLUMED_INCLUDE_DIRS}) endif() diff --git a/cmake/Modules/Packages/USER-QMMM.cmake b/cmake/Modules/Packages/USER-QMMM.cmake index 544455868e..0f3fa93b2a 100644 --- a/cmake/Modules/Packages/USER-QMMM.cmake +++ b/cmake/Modules/Packages/USER-QMMM.cmake @@ -8,6 +8,6 @@ if(PKG_USER-QMMM) message(WARNING "It is recommended to use BUILD_SHARED_LIBS=yes with USER-QMMM") endif() add_library(qmmm STATIC ${LAMMPS_LIB_SOURCE_DIR}/qmmm/libqmmm.c) - list(APPEND LAMMPS_LINK_LIBS qmmm) + target_link_libraries(lammps PRIVATE qmmm) target_include_directories(qmmm PUBLIC ${LAMMPS_LIB_SOURCE_DIR}/qmmm) endif() diff --git a/cmake/Modules/Packages/USER-QUIP.cmake b/cmake/Modules/Packages/USER-QUIP.cmake index 93096a2f54..52ba7e9c47 100644 --- a/cmake/Modules/Packages/USER-QUIP.cmake +++ b/cmake/Modules/Packages/USER-QUIP.cmake @@ -1,5 +1,5 @@ if(PKG_USER-QUIP) enable_language(Fortran) find_package(QUIP REQUIRED) - list(APPEND LAMMPS_LINK_LIBS ${QUIP_LIBRARIES} ${LAPACK_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${LAPACK_LIBRARIES}) endif() diff --git a/cmake/Modules/Packages/USER-SCAFACOS.cmake b/cmake/Modules/Packages/USER-SCAFACOS.cmake index 8bb9e63605..0fac1fe919 100644 --- a/cmake/Modules/Packages/USER-SCAFACOS.cmake +++ b/cmake/Modules/Packages/USER-SCAFACOS.cmake @@ -49,28 +49,28 @@ if(PKG_USER-SCAFACOS) set(SCAFACOS_INCLUDE_DIRS ${SCAFACOS_BUILD_DIR}/include) list(APPEND LAMMPS_DEPS scafacos_build) # list and order from pkg_config file of ScaFaCoS build - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_direct.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_ewald.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_fmm.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_p2nfft.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_p3m.a) - list(APPEND LAMMPS_LINK_LIBS ${GSL_LIBRARIES}) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_near.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_gridsort.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_resort.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_redist.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_common.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_pnfft.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_pfft.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_fftw3_mpi.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_fftw3.a) - list(APPEND LAMMPS_LINK_LIBS ${MPI_Fortran_LIBRARIES}) - list(APPEND LAMMPS_LINK_LIBS ${MPI_C_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_direct.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_ewald.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_fmm.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_p2nfft.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_p3m.a) + target_link_libraries(lammps PRIVATE ${GSL_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_near.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_gridsort.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_resort.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_redist.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_common.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_pnfft.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_pfft.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_fftw3_mpi.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_fftw3.a) + target_link_libraries(lammps PRIVATE ${MPI_Fortran_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${MPI_C_LIBRARIES}) else() find_package(PkgConfig REQUIRED) pkg_check_modules(SCAFACOS REQUIRED scafacos) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_LDFLAGS}) + target_link_libraries(lammps PRIVATE ${SCAFACOS_LDFLAGS}) endif() include_directories(${SCAFACOS_INCLUDE_DIRS}) endif() diff --git a/cmake/Modules/Packages/USER-VTK.cmake b/cmake/Modules/Packages/USER-VTK.cmake index d264577ca2..fb69f115b2 100644 --- a/cmake/Modules/Packages/USER-VTK.cmake +++ b/cmake/Modules/Packages/USER-VTK.cmake @@ -2,5 +2,5 @@ if(PKG_USER-VTK) find_package(VTK REQUIRED NO_MODULE) include(${VTK_USE_FILE}) add_definitions(-DLAMMPS_VTK) - list(APPEND LAMMPS_LINK_LIBS ${VTK_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${VTK_LIBRARIES}) endif() diff --git a/cmake/Modules/Packages/VORONOI.cmake b/cmake/Modules/Packages/VORONOI.cmake index 5418132034..f567c35597 100644 --- a/cmake/Modules/Packages/VORONOI.cmake +++ b/cmake/Modules/Packages/VORONOI.cmake @@ -39,5 +39,5 @@ if(PKG_VORONOI) endif() endif() include_directories(${VORO_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS ${VORO_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${VORO_LIBRARIES}) endif() -- GitLab From 0e3f4f3de2bd7ad50a70353e9e749758796cb10d Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 22 Mar 2020 19:07:23 -0600 Subject: [PATCH 369/689] cmake: remove LAMMPS_DEPS --- cmake/CMakeLists.txt | 12 +----------- cmake/Modules/MPI4WIN.cmake | 2 +- cmake/Modules/Packages/KIM.cmake | 2 +- cmake/Modules/Packages/LATTE.cmake | 2 +- cmake/Modules/Packages/MSCG.cmake | 2 +- cmake/Modules/Packages/USER-PLUMED.cmake | 2 +- cmake/Modules/Packages/USER-SCAFACOS.cmake | 2 +- cmake/Modules/Packages/USER-SMD.cmake | 2 +- cmake/Modules/Packages/VORONOI.cmake | 2 +- 9 files changed, 9 insertions(+), 19 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 9190374a2e..b9e8d5b919 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -126,7 +126,6 @@ endif() option(CMAKE_VERBOSE_MAKEFILE "Generate verbose Makefiles" OFF) include(GNUInstallDirs) -set(LAMMPS_DEPS) set(LAMMPS_API_DEFINES) set(DEFAULT_PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE @@ -526,7 +525,7 @@ add_custom_target(gitversion COMMAND ${CMAKE_COMMAND} -DLAMMPS_STYLE_HEADERS_DIR="${LAMMPS_STYLE_HEADERS_DIR}" -P ${CMAKE_CURRENT_SOURCE_DIR}/Modules/generate_lmpgitversion.cmake) set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${LAMMPS_STYLE_HEADERS_DIR}/gitversion.h) -list(APPEND LAMMPS_DEPS gitversion) +add_dependencies(lammps gitversion) ########################################### # Actually add executable and lib to build @@ -537,9 +536,6 @@ if (${_index} GREATER -1) target_link_libraries(lammps PRIVATE ${CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES}) endif() if(BUILD_LIB) - if(LAMMPS_DEPS) - add_dependencies(lammps ${LAMMPS_DEPS}) - endif() set(LAMMPS_CXX_HEADERS ${LAMMPS_SOURCE_DIR}/angle.h ${LAMMPS_SOURCE_DIR}/atom.h @@ -584,12 +580,6 @@ if(BUILD_LIB) endif() if(BUILD_EXE) - if(NOT BUILD_LIB) - if(LAMMPS_DEPS) - add_dependencies(${LAMMPS_EXE} ${LAMMPS_DEPS}) - endif() - endif() - set_target_properties(${LAMMPS_EXE} PROPERTIES OUTPUT_NAME ${LAMMPS_BINARY}) install(TARGETS ${LAMMPS_EXE} DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ${LAMMPS_DOC_DIR}/lammps.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 RENAME ${LAMMPS_BINARY}.1) diff --git a/cmake/Modules/MPI4WIN.cmake b/cmake/Modules/MPI4WIN.cmake index 1f3195041a..1fe6daada3 100644 --- a/cmake/Modules/MPI4WIN.cmake +++ b/cmake/Modules/MPI4WIN.cmake @@ -19,5 +19,5 @@ ExternalProject_get_property(mpi4win_build SOURCE_DIR) add_definitions(-DMPICH_SKIP_MPICXX) include_directories("${SOURCE_DIR}/include") set(MPI4WIN_LIBRARIES "${SOURCE_DIR}/lib/libmpi.a") -list(APPEND LAMMPS_DEPS mpi4win_build) +add_dependencies(lammps mpi4win_build) set(LAMMPS_USE_MPI4WIN ON) diff --git a/cmake/Modules/Packages/KIM.cmake b/cmake/Modules/Packages/KIM.cmake index 002fbbcaed..56fc1449fa 100644 --- a/cmake/Modules/Packages/KIM.cmake +++ b/cmake/Modules/Packages/KIM.cmake @@ -57,7 +57,7 @@ if(PKG_KIM) ExternalProject_get_property(kim_build INSTALL_DIR) set(KIM-API_INCLUDE_DIRS ${INSTALL_DIR}/include/kim-api) set(KIM-API_LDFLAGS ${INSTALL_DIR}/${_KIM_LIBDIR}/libkim-api${CMAKE_SHARED_LIBRARY_SUFFIX}) - list(APPEND LAMMPS_DEPS kim_build) + add_dependencies(lammps kim_build) else() find_package(KIM-API ${KIM-API_MIN_VERSION} REQUIRED) endif() diff --git a/cmake/Modules/Packages/LATTE.cmake b/cmake/Modules/Packages/LATTE.cmake index 55d9b31797..abadd1cd97 100644 --- a/cmake/Modules/Packages/LATTE.cmake +++ b/cmake/Modules/Packages/LATTE.cmake @@ -24,7 +24,7 @@ if(PKG_LATTE) -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} BUILD_BYPRODUCTS /${_LATTE_LIBDIR}/liblatte.a ) - list(APPEND LAMMPS_DEPS latte_build) + add_dependencies(lammps latte_build) ExternalProject_get_property(latte_build INSTALL_DIR) set(LATTE_LIBRARIES ${INSTALL_DIR}/${_LATTE_LIBDIR}/liblatte.a) else() diff --git a/cmake/Modules/Packages/MSCG.cmake b/cmake/Modules/Packages/MSCG.cmake index e300ed6ae2..2c63e69fa7 100644 --- a/cmake/Modules/Packages/MSCG.cmake +++ b/cmake/Modules/Packages/MSCG.cmake @@ -32,7 +32,7 @@ if(PKG_MSCG) set(MSCG_LIBRARIES ${BINARY_DIR}/libmscg.a) ExternalProject_get_property(mscg_build SOURCE_DIR) set(MSCG_INCLUDE_DIRS ${SOURCE_DIR}/src) - list(APPEND LAMMPS_DEPS mscg_build) + add_dependencies(lammps mscg_build) if(NOT LAPACK_FOUND) file(MAKE_DIRECTORY ${MSCG_INCLUDE_DIRS}) add_dependencies(mscg_build linalg) diff --git a/cmake/Modules/Packages/USER-PLUMED.cmake b/cmake/Modules/Packages/USER-PLUMED.cmake index 9669f1955c..2bca281fa8 100644 --- a/cmake/Modules/Packages/USER-PLUMED.cmake +++ b/cmake/Modules/Packages/USER-PLUMED.cmake @@ -67,7 +67,7 @@ if(PKG_USER-PLUMED) ) ExternalProject_get_property(plumed_build INSTALL_DIR) set(PLUMED_INSTALL_DIR ${INSTALL_DIR}) - list(APPEND LAMMPS_DEPS plumed_build) + add_dependencies(lammps plumed_build) if(PLUMED_MODE STREQUAL "STATIC") add_definitions(-D__PLUMED_WRAPPER_CXX=1) target_link_libraries(lammps ${PLUMED_INSTALL_DIR}/lib/libplumed.a ${PLUMED_LINK_LIBS} ${CMAKE_DL_LIBS}) diff --git a/cmake/Modules/Packages/USER-SCAFACOS.cmake b/cmake/Modules/Packages/USER-SCAFACOS.cmake index 0fac1fe919..ebd750c04b 100644 --- a/cmake/Modules/Packages/USER-SCAFACOS.cmake +++ b/cmake/Modules/Packages/USER-SCAFACOS.cmake @@ -47,7 +47,7 @@ if(PKG_USER-SCAFACOS) ExternalProject_get_property(scafacos_build INSTALL_DIR) set(SCAFACOS_BUILD_DIR ${INSTALL_DIR}) set(SCAFACOS_INCLUDE_DIRS ${SCAFACOS_BUILD_DIR}/include) - list(APPEND LAMMPS_DEPS scafacos_build) + add_dependencies(lammps scafacos_build) # list and order from pkg_config file of ScaFaCoS build target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs.a) target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_direct.a) diff --git a/cmake/Modules/Packages/USER-SMD.cmake b/cmake/Modules/Packages/USER-SMD.cmake index a868918e37..eed60ae8bd 100644 --- a/cmake/Modules/Packages/USER-SMD.cmake +++ b/cmake/Modules/Packages/USER-SMD.cmake @@ -16,7 +16,7 @@ if(PKG_USER-SMD) ) ExternalProject_get_property(Eigen3_build SOURCE_DIR) set(EIGEN3_INCLUDE_DIR ${SOURCE_DIR}) - list(APPEND LAMMPS_DEPS Eigen3_build) + add_dependencies(lammps Eigen3_build) else() find_package(Eigen3 NO_MODULE) mark_as_advanced(Eigen3_DIR) diff --git a/cmake/Modules/Packages/VORONOI.cmake b/cmake/Modules/Packages/VORONOI.cmake index f567c35597..d2bb185228 100644 --- a/cmake/Modules/Packages/VORONOI.cmake +++ b/cmake/Modules/Packages/VORONOI.cmake @@ -31,7 +31,7 @@ if(PKG_VORONOI) ExternalProject_get_property(voro_build SOURCE_DIR) set(VORO_LIBRARIES ${SOURCE_DIR}/src/libvoro++.a) set(VORO_INCLUDE_DIRS ${SOURCE_DIR}/src) - list(APPEND LAMMPS_DEPS voro_build) + add_dependencies(lammps voro_build) else() find_package(VORO) if(NOT VORO_FOUND) -- GitLab From e1f01d3e6514eecb83584c1e2b14c88569db70bb Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 22 Mar 2020 21:14:26 -0400 Subject: [PATCH 370/689] use consistent naming for c++11 style kspace thread --- src/USER-INTEL/verlet_lrt_intel.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/USER-INTEL/verlet_lrt_intel.cpp b/src/USER-INTEL/verlet_lrt_intel.cpp index a3c05c46bc..bd143c4c94 100644 --- a/src/USER-INTEL/verlet_lrt_intel.cpp +++ b/src/USER-INTEL/verlet_lrt_intel.cpp @@ -185,7 +185,7 @@ void VerletLRTIntel::setup(int flag) _kspace_done = 0; pthread_mutex_unlock(&_kmutex); #elif defined(_LMP_INTEL_LRT_11) - kspace_thread.join(); + _kspace_thread.join(); #endif if (kspace_compute_flag) _intel_kspace->compute_second(eflag,vflag); @@ -298,9 +298,9 @@ void VerletLRTIntel::run(int n) pthread_cond_signal(&_kcond); pthread_mutex_unlock(&_kmutex); #elif defined(_LMP_INTEL_LRT_11) - std::thread kspace_thread; + std::thread _kspace_thread; if (kspace_compute_flag) - kspace_thread=std::thread([=] { + _kspace_thread=std::thread([=] { _intel_kspace->compute_first(eflag, vflag); timer->stamp(Timer::KSPACE); } ); @@ -332,7 +332,7 @@ void VerletLRTIntel::run(int n) pthread_mutex_unlock(&_kmutex); #elif defined(_LMP_INTEL_LRT_11) if (kspace_compute_flag) - kspace_thread.join(); + _kspace_thread.join(); #endif if (kspace_compute_flag) { -- GitLab From 3076e267073f7501467933cb846a1b129373e2fb Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 22 Mar 2020 19:20:00 -0600 Subject: [PATCH 371/689] cmake: create imported target for FFTW --- cmake/Modules/FindFFTW3.cmake | 28 +++++++++++++++++++++++---- cmake/Modules/FindFFTW3F.cmake | 30 ++++++++++++++++++++++++----- cmake/Modules/Packages/KSPACE.cmake | 5 ++--- 3 files changed, 51 insertions(+), 12 deletions(-) diff --git a/cmake/Modules/FindFFTW3.cmake b/cmake/Modules/FindFFTW3.cmake index 63752f85df..708ec49509 100644 --- a/cmake/Modules/FindFFTW3.cmake +++ b/cmake/Modules/FindFFTW3.cmake @@ -14,14 +14,34 @@ find_path(FFTW3_INCLUDE_DIR fftw3.h HINTS ${PC_FFTW3_INCLUDE_DIRS}) find_library(FFTW3_LIBRARY NAMES fftw3 HINTS ${PC_FFTW3_LIBRARY_DIRS}) find_library(FFTW3_OMP_LIBRARY NAMES fftw3_omp HINTS ${PC_FFTW3_LIBRARY_DIRS}) -set(FFTW3_INCLUDE_DIRS ${FFTW3_INCLUDE_DIR}) -set(FFTW3_LIBRARIES ${FFTW3_LIBRARY}) -set(FFTW3_OMP_LIBRARIES ${FFTW3_OMP_LIBRARY}) - include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set FFTW3_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(FFTW3 DEFAULT_MSG FFTW3_LIBRARY FFTW3_INCLUDE_DIR) +# Copy the results to the output variables and target. +if(FFTW3_FOUND) + set(FFTW3_LIBRARIES ${FFTW3_LIBRARY} ) + set(FFTW3_INCLUDE_DIRS ${FFTW3_INCLUDE_DIR} ) + + if(NOT TARGET FFTW3::FFTW3) + add_library(FFTW3::FFTW3 UNKNOWN IMPORTED) + set_target_properties(FFTW3::FFTW3 PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${FFTW3_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${FFTW3_INCLUDE_DIRS}") + endif() + if(FFTW3_OMP_LIBRARY) + set(FFTW3_OMP_LIBRARIES ${FFTW3_OMP_LIBRARY}) + if(NOT TARGET FFTW3::FFTW3_OMP) + add_library(FFTW3::FFTW3_OMP UNKNOWN IMPORTED) + set_target_properties(FFTW3::FFTW3_OMP PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${FFTW3_OMP_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${FFTW3_INCLUDE_DIRS}") + endif() + endif() +endif() + mark_as_advanced(FFTW3_INCLUDE_DIR FFTW3_LIBRARY FFTW3_OMP_LIBRARY) diff --git a/cmake/Modules/FindFFTW3F.cmake b/cmake/Modules/FindFFTW3F.cmake index c67aa5faf1..3dbcdaa04e 100644 --- a/cmake/Modules/FindFFTW3F.cmake +++ b/cmake/Modules/FindFFTW3F.cmake @@ -13,14 +13,34 @@ find_path(FFTW3F_INCLUDE_DIR fftw3.h HINTS ${PC_FFTW3F_INCLUDE_DIRS}) find_library(FFTW3F_LIBRARY NAMES fftw3f HINTS ${PC_FFTW3F_LIBRARY_DIRS}) find_library(FFTW3F_OMP_LIBRARY NAMES fftw3f_omp HINTS ${PC_FFTW3F_LIBRARY_DIRS}) -set(FFTW3F_INCLUDE_DIRS ${FFTW3F_INCLUDE_DIR}) -set(FFTW3F_LIBRARIES ${FFTW3F_LIBRARY}) -set(FFTW3F_OMP_LIBRARIES ${FFTW3F_OMP_LIBRARY}) - include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set FFTW3F_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(FFTW3F DEFAULT_MSG FFTW3F_LIBRARY FFTW3F_INCLUDE_DIR) -mark_as_advanced(FFTW3F_INCLUDE_DIR FFTW3F_LIBRARY) +# Copy the results to the output variables and target. +if(FFTW3F_FOUND) + set(FFTW3F_LIBRARIES ${FFTW3F_LIBRARY} ) + set(FFTW3F_INCLUDE_DIRS ${FFTW3F_INCLUDE_DIR} ) + + if(NOT TARGET FFTW3F::FFTW3F) + add_library(FFTW3F::FFTW3F UNKNOWN IMPORTED) + set_target_properties(FFTW3F::FFTW3F PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${FFTW3F_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${FFTW3F_INCLUDE_DIRS}") + endif() + if(FFTW3F_OMP_LIBRARY) + set(FFTW3F_OMP_LIBRARIES ${FFTW3F_OMP_LIBRARY}) + if(NOT TARGET FFTW3F::FFTW3F_OMP) + add_library(FFTW3F::FFTW3F_OMP UNKNOWN IMPORTED) + set_target_properties(FFTW3F::FFTW3F_OMP PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${FFTW3F_OMP_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${FFTW3F_INCLUDE_DIRS}") + endif() + endif() +endif() + +mark_as_advanced(FFTW3F_INCLUDE_DIR FFTW3F_LIBRARY FFTW3F_OMP_LIBRARY) diff --git a/cmake/Modules/Packages/KSPACE.cmake b/cmake/Modules/Packages/KSPACE.cmake index 4f92a6963c..db12787013 100644 --- a/cmake/Modules/Packages/KSPACE.cmake +++ b/cmake/Modules/Packages/KSPACE.cmake @@ -19,8 +19,7 @@ if(PKG_KSPACE) if(FFT STREQUAL "FFTW3") find_package(${FFTW} REQUIRED) add_definitions(-DFFT_FFTW3) - include_directories(${${FFTW}_INCLUDE_DIRS}) - target_link_libraries(lammps PRIVATE ${${FFTW}_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${FFTW}::${FFTW}) if(FFTW3_OMP_LIBRARY OR FFTW3F_OMP_LIBRARY) option(FFT_FFTW_THREADS "Use threaded FFTW library" ON) else() @@ -30,7 +29,7 @@ if(PKG_KSPACE) if(FFT_FFTW_THREADS) if(FFTW3_OMP_LIBRARY OR FFTW3F_OMP_LIBRARY) add_definitions(-DFFT_FFTW_THREADS) - target_link_libraries(lammps PRIVATE ${${FFTW}_OMP_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${FFTW}::${FFTW}_OMP) else() message(FATAL_ERROR "Need OpenMP enabled FFTW3 library for FFT_THREADS") endif() -- GitLab From 591212af3ac3a6c0d5f9fce59199b39b279929e8 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 22 Mar 2020 19:57:48 -0600 Subject: [PATCH 372/689] cmake: add back include path for now --- cmake/CMakeLists.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index b9e8d5b919..c6d149e7d6 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -112,15 +112,17 @@ if(BUILD_LIB) add_library(lammps ${ALL_SOURCES}) if(BUILD_EXE) add_executable(lmp ${MAIN_SOURCES}) - set(LAMMPS_EXE lmp) target_link_libraries(lmp PRIVATE lammps) + set_target_properties(lmp PROPERTIES OUTPUT_NAME ${LAMMPS_BINARY}) + install(TARGETS lmp DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() else() if(NOT BUILD_EXE) message(FATAL_ERROR "You need to at least enable one of two following options: BUILD_LIB or BUILD_EXE") endif() add_executable(lammps ${ALL_SOURCES}) - set(LAMMPS_EXE lammps) + set_target_properties(lammps PROPERTIES OUTPUT_NAME ${LAMMPS_BINARY}) + install(TARGETS lammps DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() option(CMAKE_VERBOSE_MAKEFILE "Generate verbose Makefiles" OFF) @@ -186,6 +188,7 @@ if(BUILD_MPI) include(MPI4WIN) else() find_package(MPI REQUIRED) + include_directories(${MPI_CXX_INCLUDE_PATH}) add_definitions(-DMPICH_SKIP_MPICXX -DOMPI_SKIP_MPICXX=1) target_link_libraries(lammps PRIVATE MPI::MPI_CXX) option(LAMMPS_LONGLONG_TO_LONG "Workaround if your system or MPI version does not recognize 'long long' data types" OFF) @@ -580,8 +583,6 @@ if(BUILD_LIB) endif() if(BUILD_EXE) - set_target_properties(${LAMMPS_EXE} PROPERTIES OUTPUT_NAME ${LAMMPS_BINARY}) - install(TARGETS ${LAMMPS_EXE} DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ${LAMMPS_DOC_DIR}/lammps.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 RENAME ${LAMMPS_BINARY}.1) endif() -- GitLab From 98bfbbd57630fb21421d73c2478571068e343a5c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 22 Mar 2020 22:21:12 -0400 Subject: [PATCH 373/689] fix typo in CMake module --- cmake/Modules/Packages/USER-INTEL.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Modules/Packages/USER-INTEL.cmake b/cmake/Modules/Packages/USER-INTEL.cmake index d0941a0a12..9ae4333ee2 100644 --- a/cmake/Modules/Packages/USER-INTEL.cmake +++ b/cmake/Modules/Packages/USER-INTEL.cmake @@ -31,7 +31,7 @@ if(PKG_USER-INTEL) endif() endif() if(INTEL_LRT_MODE STREQUAL "C++11") - add_definitions(-DLMP_INTEL_USERLRT -DLMP_INTEL_LRT11) + add_definitions(-DLMP_INTEL_USELRT -DLMP_INTEL_LRT11) endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") -- GitLab From a42f7163d222367003c291e7c307521966c9a266 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 22 Mar 2020 21:29:15 -0600 Subject: [PATCH 374/689] cmake: move include up --- cmake/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index c6d149e7d6..ae80996196 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -105,6 +105,7 @@ endif() option(BUILD_TOOLS "Build and install LAMMPS tools (msi2lmp, binary2txt, chain)" OFF) +include(GNUInstallDirs) file(GLOB ALL_SOURCES ${LAMMPS_SOURCE_DIR}/[^.]*.cpp) if(BUILD_LIB) file(GLOB MAIN_SOURCES ${LAMMPS_SOURCE_DIR}/main.cpp) @@ -126,7 +127,6 @@ else() endif() option(CMAKE_VERBOSE_MAKEFILE "Generate verbose Makefiles" OFF) -include(GNUInstallDirs) set(LAMMPS_API_DEFINES) -- GitLab From 6e1f18961c87595058f2f8c83414ba0717eb1e13 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Mon, 23 Mar 2020 09:42:46 -0400 Subject: [PATCH 375/689] Convert characters to UTF-8 --- src/KSPACE/msm.cpp | 4 ++-- src/USER-INTEL/pair_tersoff_intel.cpp | 2 +- src/USER-SMTBQ/pair_smtbq.cpp | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/KSPACE/msm.cpp b/src/KSPACE/msm.cpp index 126236a328..1520c2c607 100644 --- a/src/KSPACE/msm.cpp +++ b/src/KSPACE/msm.cpp @@ -2920,7 +2920,7 @@ void MSM::compute_phis_and_dphis(const double &dx, const double &dy, /* ---------------------------------------------------------------------- compute phi using interpolating polynomial - see Eq 7 from Parallel Computing 35 (2009) 164–177 + see Eq 7 from Parallel Computing 35 (2009) 164-177 and Hardy's thesis ------------------------------------------------------------------------- */ @@ -2999,7 +2999,7 @@ inline double MSM::compute_phi(const double &xi) /* ---------------------------------------------------------------------- compute the derivative of phi phi is an interpolating polynomial - see Eq 7 from Parallel Computing 35 (2009) 164–177 + see Eq 7 from Parallel Computing 35 (2009) 164-177 and Hardy's thesis ------------------------------------------------------------------------- */ diff --git a/src/USER-INTEL/pair_tersoff_intel.cpp b/src/USER-INTEL/pair_tersoff_intel.cpp index 76d06b02dd..8784029320 100644 --- a/src/USER-INTEL/pair_tersoff_intel.cpp +++ b/src/USER-INTEL/pair_tersoff_intel.cpp @@ -12,7 +12,7 @@ ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- - Contributing author: Markus Höhnerbach (RWTH) + Contributing author: Markus Höhnerbach (RWTH) ------------------------------------------------------------------------- */ #include diff --git a/src/USER-SMTBQ/pair_smtbq.cpp b/src/USER-SMTBQ/pair_smtbq.cpp index f61fc1a72e..fcf6d141f2 100644 --- a/src/USER-SMTBQ/pair_smtbq.cpp +++ b/src/USER-SMTBQ/pair_smtbq.cpp @@ -13,7 +13,7 @@ /* ---------------------------------------------------------------------- The SMTBQ code has been developed with the financial support of CNRS and - of the Regional Council of Burgundy (Convention n¡ 2010-9201AAO037S03129) + of the Regional Council of Burgundy (Convention n¡ 2010-9201AAO037S03129) Copyright (2015) Universite de Bourgogne : Nicolas SALLES, Olivier POLITANO @@ -943,7 +943,7 @@ void PairSMTBQ::compute(int eflag, int vflag) 3 -> Short int. Ox-Ox 4 -> Short int. SMTB (repulsion) 5 -> Covalent energy SMTB - 6 -> Somme des Q(i)² + 6 -> Somme des Q(i)² ------------------------------------------------------------------------- */ /* -------------- N-body forces Calcul --------------- */ @@ -3022,7 +3022,7 @@ void PairSMTBQ::groupQEqAllParallel_QEq() ngp = igp = 0; nelt[ngp] = 0; - // On prend un oxygène + // On prend un oxygène // printf ("[me %d] On prend un oxygene\n",me); for (ii = 0; ii < inum; ii++) { -- GitLab From 6ee25db32a46c80da89a69ccfa667e283404ff3a Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Mon, 23 Mar 2020 08:00:51 -0600 Subject: [PATCH 376/689] cmake: fftw needs to be public due to DSO --- cmake/Modules/Packages/KSPACE.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Modules/Packages/KSPACE.cmake b/cmake/Modules/Packages/KSPACE.cmake index db12787013..2a586dccf3 100644 --- a/cmake/Modules/Packages/KSPACE.cmake +++ b/cmake/Modules/Packages/KSPACE.cmake @@ -19,7 +19,7 @@ if(PKG_KSPACE) if(FFT STREQUAL "FFTW3") find_package(${FFTW} REQUIRED) add_definitions(-DFFT_FFTW3) - target_link_libraries(lammps PRIVATE ${FFTW}::${FFTW}) + target_link_libraries(lammps PUBLIC ${FFTW}::${FFTW}) if(FFTW3_OMP_LIBRARY OR FFTW3F_OMP_LIBRARY) option(FFT_FFTW_THREADS "Use threaded FFTW library" ON) else() -- GitLab From 9b8266173faff9ab80e77461be42e566e658491e Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Mon, 23 Mar 2020 08:23:16 -0600 Subject: [PATCH 377/689] cmake: JPEG imported target is >=cmake-3.12 only --- cmake/CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index ae80996196..6dd80d3253 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -284,7 +284,12 @@ option(WITH_JPEG "Enable JPEG support" ${JPEG_FOUND}) if(WITH_JPEG) find_package(JPEG REQUIRED) add_definitions(-DLAMMPS_JPEG) - target_link_libraries(lammps PRIVATE JPEG::JPEG) + if(CMAKE_VERSION VERSION_LESS 3.12) + include_directories(${JPEG_INCLUDE_DIR}) + target_link_libraries(lammps PRIVATE ${JPEG_LIBRARIES}) + else() + target_link_libraries(lammps PRIVATE JPEG::JPEG) + endif() endif() find_package(PNG QUIET) -- GitLab From d92b9ba8d0c38de37c1699dbcaecfce7931766db Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Mon, 23 Mar 2020 08:51:29 -0600 Subject: [PATCH 378/689] cmake: mpi needs to be public due to DSO --- cmake/CMakeLists.txt | 2 +- cmake/Modules/Packages/USER-PLUMED.cmake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 6dd80d3253..362cce94db 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -190,7 +190,7 @@ if(BUILD_MPI) find_package(MPI REQUIRED) include_directories(${MPI_CXX_INCLUDE_PATH}) add_definitions(-DMPICH_SKIP_MPICXX -DOMPI_SKIP_MPICXX=1) - target_link_libraries(lammps PRIVATE MPI::MPI_CXX) + target_link_libraries(lammps PUBLIC MPI::MPI_CXX) option(LAMMPS_LONGLONG_TO_LONG "Workaround if your system or MPI version does not recognize 'long long' data types" OFF) if(LAMMPS_LONGLONG_TO_LONG) add_definitions(-DLAMMPS_LONGLONG_TO_LONG) diff --git a/cmake/Modules/Packages/USER-PLUMED.cmake b/cmake/Modules/Packages/USER-PLUMED.cmake index 2bca281fa8..a6cd20adbb 100644 --- a/cmake/Modules/Packages/USER-PLUMED.cmake +++ b/cmake/Modules/Packages/USER-PLUMED.cmake @@ -70,7 +70,7 @@ if(PKG_USER-PLUMED) add_dependencies(lammps plumed_build) if(PLUMED_MODE STREQUAL "STATIC") add_definitions(-D__PLUMED_WRAPPER_CXX=1) - target_link_libraries(lammps ${PLUMED_INSTALL_DIR}/lib/libplumed.a ${PLUMED_LINK_LIBS} ${CMAKE_DL_LIBS}) + target_link_libraries(lammps PRIVATE ${PLUMED_INSTALL_DIR}/lib/libplumed.a ${PLUMED_LINK_LIBS} ${CMAKE_DL_LIBS}) elseif(PLUMED_MODE STREQUAL "SHARED") target_link_libraries(lammps PRIVATE ${PLUMED_INSTALL_DIR}/lib/libplumed${CMAKE_SHARED_LIBRARY_SUFFIX} ${PLUMED_INSTALL_DIR}/lib/libplumedKernel${CMAKE_SHARED_LIBRARY_SUFFIX} ${CMAKE_DL_LIBS}) elseif(PLUMED_MODE STREQUAL "RUNTIME") -- GitLab From 0f00bb1ca6c08c3d5fcc14857f2a629fd9c8292d Mon Sep 17 00:00:00 2001 From: david-castillo Date: Mon, 23 Mar 2020 16:48:08 +0100 Subject: [PATCH 379/689] Added new argument r0stop to fix restrain bond Added new fix restrain lowerbound harmonic --- doc/src/fix_restrain.rst | 33 +++++++++- src/fix_restrain.cpp | 133 ++++++++++++++++++++++++++++++++++++--- src/fix_restrain.h | 4 +- 3 files changed, 160 insertions(+), 10 deletions(-) diff --git a/doc/src/fix_restrain.rst b/doc/src/fix_restrain.rst index 3965cee04d..9b9beaa5ac 100644 --- a/doc/src/fix_restrain.rst +++ b/doc/src/fix_restrain.rst @@ -17,10 +17,18 @@ Syntax .. parsed-literal:: - *bond* args = atom1 atom2 Kstart Kstop r0 + *bond* args = atom1 atom2 Kstart Kstop r0start r0stop atom1,atom2 = IDs of 2 atoms in bond Kstart,Kstop = restraint coefficients at start/end of run (energy units) - r0 = equilibrium bond distance (distance units) + r0start = equilibrium bond distance at start of run (distance units) + r0stop = equilibrium bond distance at end of run (distance units). If not + specified it's assumed to be equal to r0start + *lbond* args = atom1 atom2 Kstart Kstop r0start r0stop + atom1,atom2 = IDs of 2 atoms in bond + Kstart,Kstop = restraint coefficients at start/end of run (energy units) + r0start = equilibrium bond distance at start of run (distance units) + r0stop = equilibrium bond distance at end of run (distance units). If not + specified it's assumed to be equal to r0start *angle* args = atom1 atom2 atom3 Kstart Kstop theta0 atom1,atom2,atom3 = IDs of 3 atoms in angle, atom2 = middle atom Kstart,Kstop = restraint coefficients at start/end of run (energy units) @@ -38,6 +46,7 @@ Examples .. code-block:: LAMMPS fix holdem all restrain bond 45 48 2000.0 2000.0 2.75 + fix holdem all restrain lbond 45 48 2000.0 2000.0 2.75 fix holdem all restrain dihedral 1 2 3 4 2000.0 2000.0 120.0 fix holdem all restrain bond 45 48 2000.0 2000.0 2.75 dihedral 1 2 3 4 2000.0 2000.0 120.0 fix texas_holdem all restrain dihedral 1 2 3 4 0.0 2000.0 120.0 dihedral 1 2 3 5 0.0 2000.0 -120.0 dihedral 1 2 3 6 0.0 2000.0 0.0 @@ -141,6 +150,26 @@ is included in :math:`K`. ---------- +The *lbond* keyword applies a lowerbound bond restraint to the specified atoms +using the same functional form used by the :doc:`bond_style harmonic ` command if the distance between +the atoms is smaller than the equilibrium bond distance and 0 otherwise. The potential associated with +the restraint is + +.. math:: + + E = K (r - r_0)^2 if r < r_0 + E = 0 if r >= r_0 + +with the following coefficients: + +* :math:`K` (energy/distance\^2) +* :math:`r_0` (distance) + +:math:`K` and :math:`r_0` are specified with the fix. Note that the usual 1/2 factor +is included in :math:`K`. + +---------- + The *angle* keyword applies an angle restraint to the specified atoms using the same functional form used by the :doc:`angle_style harmonic ` command. The potential associated with the restraint is diff --git a/src/fix_restrain.cpp b/src/fix_restrain.cpp index 5a0d4fb662..5f65d7069b 100644 --- a/src/fix_restrain.cpp +++ b/src/fix_restrain.cpp @@ -34,7 +34,7 @@ using namespace LAMMPS_NS; using namespace FixConst; using namespace MathConst; -enum{BOND,ANGLE,DIHEDRAL}; +enum{BOND,LBOUND,ANGLE,DIHEDRAL}; #define TOLERANCE 0.05 #define SMALL 0.001 @@ -45,7 +45,7 @@ enum{BOND,ANGLE,DIHEDRAL}; FixRestrain::FixRestrain(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), rstyle(NULL), mult(NULL), ids(NULL), kstart(NULL), kstop(NULL), target(NULL), - cos_target(NULL), sin_target(NULL) + deqstart(NULL), deqstop(NULL), cos_target(NULL), sin_target(NULL) { if (narg < 4) error->all(FLERR,"Illegal fix restrain command"); @@ -72,6 +72,8 @@ FixRestrain::FixRestrain(LAMMPS *lmp, int narg, char **arg) : memory->grow(kstart,maxrestrain,"restrain:kstart"); memory->grow(kstop,maxrestrain,"restrain:kstop"); memory->grow(target,maxrestrain,"restrain:target"); + memory->grow(deqstart,maxrestrain,"restrain:deqstart"); + memory->grow(deqstop,maxrestrain,"restrain:deqstop"); memory->grow(cos_target,maxrestrain,"restrain:cos_target"); memory->grow(sin_target,maxrestrain,"restrain:sin_target"); } @@ -83,8 +85,29 @@ FixRestrain::FixRestrain(LAMMPS *lmp, int narg, char **arg) : ids[nrestrain][1] = force->inumeric(FLERR,arg[iarg+2]); kstart[nrestrain] = force->numeric(FLERR,arg[iarg+3]); kstop[nrestrain] = force->numeric(FLERR,arg[iarg+4]); - target[nrestrain] = force->numeric(FLERR,arg[iarg+5]); - iarg += 6; + deqstart[nrestrain] = force->numeric(FLERR,arg[iarg+5]); + if (iarg+6 == narg) { + deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+5]); + iarg += 6; + } else { + deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+6]); + iarg += 7; + } + } else if (strcmp(arg[iarg],"lbound") == 0) { + if (iarg+6 > narg) error->all(FLERR,"Illegal fix restrain command"); + rstyle[nrestrain] = LBOUND; + ids[nrestrain][0] = force->inumeric(FLERR,arg[iarg+1]); + ids[nrestrain][1] = force->inumeric(FLERR,arg[iarg+2]); + kstart[nrestrain] = force->numeric(FLERR,arg[iarg+3]); + kstop[nrestrain] = force->numeric(FLERR,arg[iarg+4]); + deqstart[nrestrain] = force->numeric(FLERR,arg[iarg+5]); + if (iarg+6 == narg) { + deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+5]); + iarg += 6; + } else { + deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+6]); + iarg += 7; + } } else if (strcmp(arg[iarg],"angle") == 0) { if (iarg+7 > narg) error->all(FLERR,"Illegal fix restrain command"); rstyle[nrestrain] = ANGLE; @@ -139,6 +162,8 @@ FixRestrain::~FixRestrain() memory->destroy(kstart); memory->destroy(kstop); memory->destroy(target); + memory->destroy(deqstart); + memory->destroy(deqstop); memory->destroy(cos_target); memory->destroy(sin_target); } @@ -192,11 +217,13 @@ void FixRestrain::post_force(int /*vflag*/) energy = 0.0; ebond = 0.0; + elbound = 0.0; eangle = 0.0; edihed = 0.0; for (int m = 0; m < nrestrain; m++) if (rstyle[m] == BOND) restrain_bond(m); + else if (rstyle[m] == LBOUND) restrain_lbound(m); else if (rstyle[m] == ANGLE) restrain_angle(m); else if (rstyle[m] == DIHEDRAL) restrain_dihedral(m); } @@ -233,6 +260,7 @@ void FixRestrain::restrain_bond(int m) double delta = update->ntimestep - update->beginstep; if (delta != 0.0) delta /= update->endstep - update->beginstep; double k = kstart[m] + delta * (kstop[m] - kstart[m]); + double deq = deqstart[m] + delta * (deqstop[m] - deqstart[m]); i1 = atom->map(ids[m][0]); i2 = atom->map(ids[m][1]); @@ -269,7 +297,7 @@ void FixRestrain::restrain_bond(int m) rsq = delx*delx + dely*dely + delz*delz; r = sqrt(rsq); - dr = r - target[m]; + dr = r - deq; rk = k * dr; // force & energy @@ -277,7 +305,7 @@ void FixRestrain::restrain_bond(int m) if (r > 0.0) fbond = -2.0*rk/r; else fbond = 0.0; - ebond += rk*dr; + ebond += rk*dr; energy += rk*dr; // apply force to each of 2 atoms @@ -295,6 +323,94 @@ void FixRestrain::restrain_bond(int m) } } +/* ---------------------------------------------------------------------- + apply harmonic lower-bound bond restraints +---------------------------------------------------------------------- */ + +void FixRestrain::restrain_lbound(int m) +{ + int i1,i2; + double delx,dely,delz,fbond; + double rsq,r,dr,rk; + + double **x = atom->x; + double **f = atom->f; + int nlocal = atom->nlocal; + int newton_bond = force->newton_bond; + + double delta = update->ntimestep - update->beginstep; + if (delta != 0.0) delta /= update->endstep - update->beginstep; + double k = kstart[m] + delta * (kstop[m] - kstart[m]); + double deq = deqstart[m] + delta * (deqstop[m] - deqstart[m]); + + i1 = atom->map(ids[m][0]); + i2 = atom->map(ids[m][1]); + + // newton_bond on: only processor owning i2 computes restraint + // newton_bond off: only processors owning either of i1,i2 computes restraint + + if (newton_bond) { + if (i2 == -1 || i2 >= nlocal) return; + if (i1 == -1) { + char str[128]; + sprintf(str, + "Restrain atoms %d %d missing on proc %d at step " BIGINT_FORMAT, + ids[m][0],ids[m][1], + comm->me,update->ntimestep); + error->one(FLERR,str); + } + } else { + if ((i1 == -1 || i1 >= nlocal) && (i2 == -1 || i2 >= nlocal)) return; + if (i1 == -1 || i2 == -1) { + char str[128]; + sprintf(str, + "Restrain atoms %d %d missing on proc %d at step " BIGINT_FORMAT, + ids[m][0],ids[m][1], + comm->me,update->ntimestep); + error->one(FLERR,str); + } + } + + delx = x[i1][0] - x[i2][0]; + dely = x[i1][1] - x[i2][1]; + delz = x[i1][2] - x[i2][2]; + domain->minimum_image(delx,dely,delz); + + rsq = delx*delx + dely*dely + delz*delz; + r = sqrt(rsq); + dr = r - deq; + rk = k * dr; + + // force & energy + + if (dr < 0) { + if (r > 0.0) fbond = -2.0*rk/r; + else fbond = 0.0; + + elbound += rk*dr; + energy += rk*dr; + } else { + fbond = 0.0; + + elbound += 0.0; + energy += 0.0; + } + + // apply force to each of 2 atoms + + if (newton_bond || i1 < nlocal) { + f[i1][0] += delx*fbond; + f[i1][1] += dely*fbond; + f[i1][2] += delz*fbond; + } + + if (newton_bond || i2 < nlocal) { + f[i2][0] -= delx*fbond; + f[i2][1] -= dely*fbond; + f[i2][2] -= delz*fbond; + } +} + /* ---------------------------------------------------------------------- apply harmonic angle restraints ---------------------------------------------------------------------- */ @@ -655,9 +771,12 @@ double FixRestrain::compute_vector(int n) MPI_Allreduce(&ebond,&ebond_all,1,MPI_DOUBLE,MPI_SUM,world); return ebond_all; } else if (n == 1) { + MPI_Allreduce(&elbound,&elbound_all,1,MPI_DOUBLE,MPI_SUM,world); + return elbound_all; + } else if (n == 3) { MPI_Allreduce(&eangle,&eangle_all,1,MPI_DOUBLE,MPI_SUM,world); return eangle_all; - } else if (n == 2) { + } else if (n == 4) { MPI_Allreduce(&edihed,&edihed_all,1,MPI_DOUBLE,MPI_SUM,world); return edihed_all; } else { diff --git a/src/fix_restrain.h b/src/fix_restrain.h index 4572905d46..3497b7daf5 100644 --- a/src/fix_restrain.h +++ b/src/fix_restrain.h @@ -44,14 +44,16 @@ class FixRestrain : public Fix { int *rstyle; int *mult; int **ids; - double *kstart,*kstop,*target; + double *kstart,*kstop,*deqstart,*deqstop,*target; double *cos_target,*sin_target; double energy,energy_all; double ebond,ebond_all; + double elbound,elbound_all; double eangle,eangle_all; double edihed,edihed_all; void restrain_bond(int); + void restrain_lbound(int); void restrain_angle(int); void restrain_dihedral(int); }; -- GitLab From 6209479797e29df62dd17476127e30a64d73d08f Mon Sep 17 00:00:00 2001 From: david-castillo Date: Mon, 23 Mar 2020 17:57:58 +0100 Subject: [PATCH 380/689] Removed some tabs Changed mathjax for multiline formula --- doc/src/fix_restrain.rst | 9 ++++++--- src/fix_restrain.cpp | 16 ++++++++-------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/doc/src/fix_restrain.rst b/doc/src/fix_restrain.rst index 9b9beaa5ac..110b26680d 100644 --- a/doc/src/fix_restrain.rst +++ b/doc/src/fix_restrain.rst @@ -150,16 +150,19 @@ is included in :math:`K`. ---------- -The *lbond* keyword applies a lowerbound bond restraint to the specified atoms +The *lbond* keyword applies a lower bound bond restraint to the specified atoms using the same functional form used by the :doc:`bond_style harmonic ` command if the distance between the atoms is smaller than the equilibrium bond distance and 0 otherwise. The potential associated with the restraint is .. math:: - E = K (r - r_0)^2 if r < r_0 - E = 0 if r >= r_0 + E = K (r - r_0)^2 ,if\;r < r_0 +.. math:: + + E = 0 \qquad\quad\quad ,if\;r \ge r_0 + with the following coefficients: * :math:`K` (energy/distance\^2) diff --git a/src/fix_restrain.cpp b/src/fix_restrain.cpp index 5f65d7069b..a6793a36be 100644 --- a/src/fix_restrain.cpp +++ b/src/fix_restrain.cpp @@ -87,11 +87,11 @@ FixRestrain::FixRestrain(LAMMPS *lmp, int narg, char **arg) : kstop[nrestrain] = force->numeric(FLERR,arg[iarg+4]); deqstart[nrestrain] = force->numeric(FLERR,arg[iarg+5]); if (iarg+6 == narg) { - deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+5]); - iarg += 6; + deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+5]); + iarg += 6; } else { - deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+6]); - iarg += 7; + deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+6]); + iarg += 7; } } else if (strcmp(arg[iarg],"lbound") == 0) { if (iarg+6 > narg) error->all(FLERR,"Illegal fix restrain command"); @@ -102,11 +102,11 @@ FixRestrain::FixRestrain(LAMMPS *lmp, int narg, char **arg) : kstop[nrestrain] = force->numeric(FLERR,arg[iarg+4]); deqstart[nrestrain] = force->numeric(FLERR,arg[iarg+5]); if (iarg+6 == narg) { - deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+5]); - iarg += 6; + deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+5]); + iarg += 6; } else { - deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+6]); - iarg += 7; + deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+6]); + iarg += 7; } } else if (strcmp(arg[iarg],"angle") == 0) { if (iarg+7 > narg) error->all(FLERR,"Illegal fix restrain command"); -- GitLab From e76afb33edc939ee63d2033e750d186bc2799c5a Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Mon, 23 Mar 2020 12:06:58 -0600 Subject: [PATCH 381/689] cmake: update to new target_link_libraries() signature --- cmake/CMakeLists.txt | 8 ++++---- cmake/Modules/Packages/GPU.cmake | 4 ++-- cmake/Modules/Packages/USER-H5MD.cmake | 2 +- cmake/pkgconfig/liblammps.pc.in | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 362cce94db..cc9b3fc56a 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -457,14 +457,14 @@ foreach(SIMPLE_LIB POEMS USER-ATC USER-AWPMD USER-H5MD) endforeach() if(PKG_USER-AWPMD) - target_link_libraries(awpmd ${LAPACK_LIBRARIES}) + target_link_libraries(awpmd PRIVATE ${LAPACK_LIBRARIES}) endif() if(PKG_USER-ATC) if(LAMMPS_SIZES STREQUAL BIGBIG) message(FATAL_ERROR "The USER-ATC Package is not compatible with -DLAMMPS_BIGBIG") endif() - target_link_libraries(atc ${LAPACK_LIBRARIES}) + target_link_libraries(atc PRIVATE ${LAPACK_LIBRARIES}) endif() include(Packages/USER-H5MD) @@ -599,7 +599,7 @@ if(BUILD_TOOLS) if(CMAKE_GENERATOR_SUPPORT_FORTRAN) enable_language(Fortran) add_executable(chain.x ${LAMMPS_TOOLS_DIR}/chain.f) - target_link_libraries(chain.x ${CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES}) + target_link_libraries(chain.x PRIVATE ${CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES}) install(TARGETS chain.x DESTINATION ${CMAKE_INSTALL_BINDIR}) else() message(WARNING "CMake build doesn't support fortran, skipping building 'chain.x'") @@ -609,7 +609,7 @@ if(BUILD_TOOLS) get_filename_component(MSI2LMP_SOURCE_DIR ${LAMMPS_TOOLS_DIR}/msi2lmp/src ABSOLUTE) file(GLOB MSI2LMP_SOURCES ${MSI2LMP_SOURCE_DIR}/[^.]*.c) add_executable(msi2lmp ${MSI2LMP_SOURCES}) - target_link_libraries(msi2lmp m) + target_link_libraries(msi2lmp PRIVATE ${MATH_LIBRARIES}) install(TARGETS msi2lmp DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ${LAMMPS_DOC_DIR}/msi2lmp.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) endif() diff --git a/cmake/Modules/Packages/GPU.cmake b/cmake/Modules/Packages/GPU.cmake index 427644f9c7..95bb525dd5 100644 --- a/cmake/Modules/Packages/GPU.cmake +++ b/cmake/Modules/Packages/GPU.cmake @@ -99,7 +99,7 @@ if(PKG_GPU) add_library(gpu STATIC ${GPU_LIB_SOURCES} ${GPU_LIB_CUDPP_SOURCES} ${GPU_OBJS}) - target_link_libraries(gpu ${CUDA_LIBRARIES} ${CUDA_CUDA_LIBRARY}) + target_link_libraries(gpu PRIVATE ${CUDA_LIBRARIES} ${CUDA_CUDA_LIBRARY}) target_include_directories(gpu PRIVATE ${LAMMPS_LIB_BINARY_DIR}/gpu ${CUDA_INCLUDE_DIRS}) target_compile_definitions(gpu PRIVATE -D_${GPU_PREC_SETTING} -DMPI_GERYON -DUCL_NO_EXIT ${GPU_CUDA_MPS_FLAGS}) if(CUDPP_OPT) @@ -166,7 +166,7 @@ if(PKG_GPU) ) add_library(gpu STATIC ${GPU_LIB_SOURCES}) - target_link_libraries(gpu ${OpenCL_LIBRARIES}) + target_link_libraries(gpu PRIVATE ${OpenCL_LIBRARIES}) target_include_directories(gpu PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/gpu ${OpenCL_INCLUDE_DIRS}) target_compile_definitions(gpu PRIVATE -D_${GPU_PREC_SETTING} -D${OCL_TUNE}_OCL -DMPI_GERYON -DUCL_NO_EXIT) target_compile_definitions(gpu PRIVATE -DUSE_OPENCL) diff --git a/cmake/Modules/Packages/USER-H5MD.cmake b/cmake/Modules/Packages/USER-H5MD.cmake index 40ea7b7444..1e3fcf82ce 100644 --- a/cmake/Modules/Packages/USER-H5MD.cmake +++ b/cmake/Modules/Packages/USER-H5MD.cmake @@ -2,7 +2,7 @@ if(PKG_USER-H5MD) enable_language(C) find_package(HDF5 REQUIRED) - target_link_libraries(h5md ${HDF5_LIBRARIES}) + target_link_libraries(h5md PRIVATE ${HDF5_LIBRARIES}) target_include_directories(h5md PRIVATE ${HDF5_INCLUDE_DIRS}) include_directories(${HDF5_INCLUDE_DIRS}) endif() diff --git a/cmake/pkgconfig/liblammps.pc.in b/cmake/pkgconfig/liblammps.pc.in index a8710ca224..a89f992c4a 100644 --- a/cmake/pkgconfig/liblammps.pc.in +++ b/cmake/pkgconfig/liblammps.pc.in @@ -22,7 +22,7 @@ # CMakeLists.txt: # find_package(PkgConfig) # pkg_check_modules(LAMMPS IMPORTED_TARGET lammps) -# target_link_libraries( PkgConfig::LAMMPS) +# target_link_libraries( PRIVATE PkgConfig::LAMMPS) prefix=@CMAKE_INSTALL_PREFIX@ libdir=@CMAKE_INSTALL_FULL_LIBDIR@ -- GitLab From bcfc606efb2622e9afdfae6984f6b01a187f0997 Mon Sep 17 00:00:00 2001 From: Evan Weinberg Date: Mon, 23 Mar 2020 13:20:56 -0700 Subject: [PATCH 382/689] SNAP optimizations, kernel fusion, large reduction of memory usage on the GPU, misc. performance optimizations. --- src/KOKKOS/pair_snap_kokkos.h | 12 +- src/KOKKOS/pair_snap_kokkos_impl.h | 111 ++--- src/KOKKOS/sna_kokkos.h | 20 +- src/KOKKOS/sna_kokkos_impl.h | 676 ++++++++++++++--------------- 4 files changed, 349 insertions(+), 470 deletions(-) diff --git a/src/KOKKOS/pair_snap_kokkos.h b/src/KOKKOS/pair_snap_kokkos.h index e53dec4d86..b57ef2d9e5 100644 --- a/src/KOKKOS/pair_snap_kokkos.h +++ b/src/KOKKOS/pair_snap_kokkos.h @@ -37,15 +37,13 @@ struct TagPairSNAPBeta{}; struct TagPairSNAPComputeNeigh{}; struct TagPairSNAPPreUi{}; struct TagPairSNAPComputeUi{}; -struct TagPairSNAPComputeUiTot{}; // accumulate ulist into ulisttot separately struct TagPairSNAPComputeUiCPU{}; struct TagPairSNAPComputeZi{}; struct TagPairSNAPComputeBi{}; struct TagPairSNAPZeroYi{}; struct TagPairSNAPComputeYi{}; -struct TagPairSNAPComputeDuidrj{}; +struct TagPairSNAPComputeFusedDeidrj{}; struct TagPairSNAPComputeDuidrjCPU{}; -struct TagPairSNAPComputeDeidrj{}; struct TagPairSNAPComputeDeidrjCPU{}; template @@ -83,9 +81,6 @@ public: KOKKOS_INLINE_FUNCTION void operator() (TagPairSNAPComputeUi,const typename Kokkos::TeamPolicy::member_type& team) const; - KOKKOS_INLINE_FUNCTION - void operator() (TagPairSNAPComputeUiTot,const typename Kokkos::TeamPolicy::member_type& team) const; - KOKKOS_INLINE_FUNCTION void operator() (TagPairSNAPComputeUiCPU,const typename Kokkos::TeamPolicy::member_type& team) const; @@ -102,14 +97,11 @@ public: void operator() (TagPairSNAPComputeYi,const int& ii) const; KOKKOS_INLINE_FUNCTION - void operator() (TagPairSNAPComputeDuidrj,const typename Kokkos::TeamPolicy::member_type& team) const; + void operator() (TagPairSNAPComputeFusedDeidrj,const typename Kokkos::TeamPolicy::member_type& team) const; KOKKOS_INLINE_FUNCTION void operator() (TagPairSNAPComputeDuidrjCPU,const typename Kokkos::TeamPolicy::member_type& team) const; - KOKKOS_INLINE_FUNCTION - void operator() (TagPairSNAPComputeDeidrj,const typename Kokkos::TeamPolicy::member_type& team) const; - KOKKOS_INLINE_FUNCTION void operator() (TagPairSNAPComputeDeidrjCPU,const typename Kokkos::TeamPolicy::member_type& team) const; diff --git a/src/KOKKOS/pair_snap_kokkos_impl.h b/src/KOKKOS/pair_snap_kokkos_impl.h index 1156d11c31..d807f149a9 100644 --- a/src/KOKKOS/pair_snap_kokkos_impl.h +++ b/src/KOKKOS/pair_snap_kokkos_impl.h @@ -30,7 +30,6 @@ #include "kokkos.h" #include "sna.h" - #define MAXLINE 1024 #define MAXWORD 3 @@ -255,26 +254,19 @@ void PairSNAPKokkos::compute(int eflag_in, int vflag_in) // scratch size: 2 * team_size * (twojmax+1)^2, to cover all `m1`,`m2` values // 2 is for double buffer - typename Kokkos::TeamPolicy policy_ui(((chunk_size+team_size-1)/team_size)*max_neighs,team_size,vector_length); + const int tile_size = (twojmax+1)*(twojmax+1); typedef Kokkos::View< SNAcomplex*, Kokkos::DefaultExecutionSpace::scratch_memory_space, Kokkos::MemoryTraits > ScratchViewType; - int scratch_size = ScratchViewType::shmem_size( 2 * team_size * (twojmax+1)*(twojmax+1)); + int scratch_size = ScratchViewType::shmem_size( 2 * team_size * tile_size ); + + typename Kokkos::TeamPolicy policy_ui(((chunk_size+team_size-1)/team_size)*max_neighs,team_size,vector_length); policy_ui = policy_ui.set_scratch_size(0, Kokkos::PerTeam( scratch_size )); Kokkos::parallel_for("ComputeUi",policy_ui,*this); - // ComputeUitot - vector_length = 1; - team_size = 128; - team_size_max = Kokkos::TeamPolicy::team_size_max(*this); - if (team_size*vector_length > team_size_max) - team_size = team_size_max/vector_length; - - typename Kokkos::TeamPolicy policy_ui_tot(((idxu_max+team_size-1)/team_size)*chunk_size,team_size,vector_length); - Kokkos::parallel_for("ComputeUiTot",policy_ui_tot,*this); } @@ -316,7 +308,7 @@ void PairSNAPKokkos::compute(int eflag_in, int vflag_in) typename Kokkos::RangePolicy policy_yi(0,chunk_size*idxz_max); Kokkos::parallel_for("ComputeYi",policy_yi,*this); - //ComputeDuidrj + //ComputeDuidrj and Deidrj if (lmp->kokkos->ngpus == 0) { // CPU int vector_length = 1; int team_size = 1; @@ -324,53 +316,37 @@ void PairSNAPKokkos::compute(int eflag_in, int vflag_in) typename Kokkos::TeamPolicy policy_duidrj_cpu(((chunk_size+team_size-1)/team_size)*max_neighs,team_size,vector_length); snaKK.set_dir(-1); // technically doesn't do anything Kokkos::parallel_for("ComputeDuidrjCPU",policy_duidrj_cpu,*this); - } else { // GPU, utilize scratch memory and splitting over dimensions - int team_size_max = Kokkos::TeamPolicy::team_size_max(*this); + typename Kokkos::TeamPolicy policy_deidrj_cpu(((chunk_size+team_size-1)/team_size)*max_neighs,team_size,vector_length); + + Kokkos::parallel_for("ComputeDeidrjCPU",policy_deidrj_cpu,*this); + } else { // GPU, utilize scratch memory and splitting over dimensions, fused dui and dei + + int team_size_max = Kokkos::TeamPolicy::team_size_max(*this); int vector_length = 32; int team_size = 2; // need to cap b/c of shared memory reqs if (team_size*vector_length > team_size_max) team_size = team_size_max/vector_length; - // scratch size: 2 * 2 * team_size * (twojmax+1)^2, to cover all `m1`,`m2` values + // scratch size: 2 * 2 * team_size * (twojmax+1)*(twojmax/2+1), to cover half `m1`,`m2` values due to symmetry // 2 is for double buffer + const int tile_size = (twojmax+1)*(twojmax/2+1); + typedef Kokkos::View< SNAcomplex*, - Kokkos::DefaultExecutionSpace::scratch_memory_space, - Kokkos::MemoryTraits > - ScratchViewType; - - int scratch_size = ScratchViewType::shmem_size( 4 * team_size * (twojmax+1)*(twojmax+1)); - typename Kokkos::TeamPolicy policy_duidrj(((chunk_size+team_size-1)/team_size)*max_neighs,team_size,vector_length); - policy_duidrj = policy_duidrj.set_scratch_size(0, Kokkos::PerTeam( scratch_size )); - // Need to call three times, once for each direction + Kokkos::DefaultExecutionSpace::scratch_memory_space, + Kokkos::MemoryTraits > + ScratchViewType; + int scratch_size = ScratchViewType::shmem_size( 4 * team_size * tile_size); + + typename Kokkos::TeamPolicy policy_fused_deidrj(((chunk_size+team_size-1)/team_size)*max_neighs,team_size,vector_length); + policy_fused_deidrj = policy_fused_deidrj.set_scratch_size(0, Kokkos::PerTeam( scratch_size )); + for (int k = 0; k < 3; k++) { snaKK.set_dir(k); - Kokkos::parallel_for("ComputeDuidrj",policy_duidrj,*this); + Kokkos::parallel_for("ComputeFusedDeidrj",policy_fused_deidrj,*this); } } - //ComputeDeidrj - if (lmp->kokkos->ngpus == 0) { // CPU - int vector_length = 1; - int team_size = 1; - - typename Kokkos::TeamPolicy policy_deidrj_cpu(((chunk_size+team_size-1)/team_size)*max_neighs,team_size,vector_length); - - Kokkos::parallel_for("ComputeDeidrjCPU",policy_deidrj_cpu,*this); - - } else { // GPU, different loop strategy internally - - int team_size_max = Kokkos::TeamPolicy::team_size_max(*this); - int vector_length = 32; // coalescing disaster right now, will fix later - int team_size = 8; - if (team_size*vector_length > team_size_max) - team_size = team_size_max/vector_length; - - typename Kokkos::TeamPolicy policy_deidrj(((chunk_size+team_size-1)/team_size)*max_neighs,team_size,vector_length); - - Kokkos::parallel_for("ComputeDeidrj",policy_deidrj,*this); - } - //ComputeForce if (eflag) { if (neighflag == HALF) { @@ -642,25 +618,6 @@ void PairSNAPKokkos::operator() (TagPairSNAPComputeUi,const typename my_sna.compute_ui(team,ii,jj); } -template -KOKKOS_INLINE_FUNCTION -void PairSNAPKokkos::operator() (TagPairSNAPComputeUiTot,const typename Kokkos::TeamPolicy::member_type& team) const { - SNAKokkos my_sna = snaKK; - - // Extract the quantum number - const int idx = team.team_rank() + team.team_size() * (team.league_rank() % ((my_sna.idxu_max+team.team_size()-1)/team.team_size())); - if (idx >= my_sna.idxu_max) return; - - // Extract the atomic index - const int ii = team.league_rank() / ((my_sna.idxu_max+team.team_size()-1)/team.team_size()); - if (ii >= chunk_size) return; - - // Extract the number of neighbors neighbor number - const int ninside = d_ninside(ii); - - my_sna.compute_uitot(team,idx,ii,ninside); -} - template KOKKOS_INLINE_FUNCTION void PairSNAPKokkos::operator() (TagPairSNAPComputeUiCPU,const typename Kokkos::TeamPolicy::member_type& team) const { @@ -718,7 +675,7 @@ void PairSNAPKokkos::operator() (TagPairSNAPComputeBi,const typename template KOKKOS_INLINE_FUNCTION -void PairSNAPKokkos::operator() (TagPairSNAPComputeDuidrj,const typename Kokkos::TeamPolicy::member_type& team) const { +void PairSNAPKokkos::operator() (TagPairSNAPComputeFusedDeidrj,const typename Kokkos::TeamPolicy::member_type& team) const { SNAKokkos my_sna = snaKK; // Extract the atom number @@ -730,7 +687,7 @@ void PairSNAPKokkos::operator() (TagPairSNAPComputeDuidrj,const type const int ninside = d_ninside(ii); if (jj >= ninside) return; - my_sna.compute_duidrj(team,ii,jj); + my_sna.compute_fused_deidrj(team,ii,jj); } template @@ -750,24 +707,6 @@ void PairSNAPKokkos::operator() (TagPairSNAPComputeDuidrjCPU,const t my_sna.compute_duidrj_cpu(team,ii,jj); } - -template -KOKKOS_INLINE_FUNCTION -void PairSNAPKokkos::operator() (TagPairSNAPComputeDeidrj,const typename Kokkos::TeamPolicy::member_type& team) const { - SNAKokkos my_sna = snaKK; - - // Extract the atom number - int ii = team.team_rank() + team.team_size() * (team.league_rank() % ((chunk_size+team.team_size()-1)/team.team_size())); - if (ii >= chunk_size) return; - - // Extract the neighbor number - const int jj = team.league_rank() / ((chunk_size+team.team_size()-1)/team.team_size()); - const int ninside = d_ninside(ii); - if (jj >= ninside) return; - - my_sna.compute_deidrj(team,ii,jj); -} - template KOKKOS_INLINE_FUNCTION void PairSNAPKokkos::operator() (TagPairSNAPComputeDeidrjCPU,const typename Kokkos::TeamPolicy::member_type& team) const { diff --git a/src/KOKKOS/sna_kokkos.h b/src/KOKKOS/sna_kokkos.h index 48d9114fbf..a6d9db3218 100644 --- a/src/KOKKOS/sna_kokkos.h +++ b/src/KOKKOS/sna_kokkos.h @@ -135,14 +135,10 @@ inline KOKKOS_INLINE_FUNCTION void pre_ui(const typename Kokkos::TeamPolicy::member_type& team,const int&); // ForceSNAP KOKKOS_INLINE_FUNCTION - void compute_ui(const typename Kokkos::TeamPolicy::member_type& team, int, int); // ForceSNAP + void compute_ui(const typename Kokkos::TeamPolicy::member_type& team, const int, const int); // ForceSNAP KOKKOS_INLINE_FUNCTION void compute_ui_cpu(const typename Kokkos::TeamPolicy::member_type& team, int, int); // ForceSNAP KOKKOS_INLINE_FUNCTION - void compute_ui_orig(const typename Kokkos::TeamPolicy::member_type& team, int, int); // ForceSNAP - KOKKOS_INLINE_FUNCTION - void compute_uitot(const typename Kokkos::TeamPolicy::member_type& team, int, int, int); // ForceSNAP - KOKKOS_INLINE_FUNCTION void compute_zi(const int&); // ForceSNAP KOKKOS_INLINE_FUNCTION void zero_yi(const int&,const int&); // ForceSNAP @@ -155,12 +151,10 @@ inline // functions for derivatives KOKKOS_INLINE_FUNCTION - void compute_duidrj(const typename Kokkos::TeamPolicy::member_type& team, int, int); //ForceSNAP + void compute_fused_deidrj(const typename Kokkos::TeamPolicy::member_type& team, const int, const int); //ForceSNAP KOKKOS_INLINE_FUNCTION void compute_duidrj_cpu(const typename Kokkos::TeamPolicy::member_type& team, int, int); //ForceSNAP KOKKOS_INLINE_FUNCTION - void compute_deidrj(const typename Kokkos::TeamPolicy::member_type& team, int, int); // ForceSNAP - KOKKOS_INLINE_FUNCTION void compute_deidrj_cpu(const typename Kokkos::TeamPolicy::member_type& team, int, int); // ForceSNAP KOKKOS_INLINE_FUNCTION double compute_sfac(double, double); // add_uarraytot, compute_duarray @@ -251,10 +245,6 @@ inline KOKKOS_INLINE_FUNCTION void add_uarraytot(const typename Kokkos::TeamPolicy::member_type& team, int, int, double, double, double); // compute_ui - KOKKOS_INLINE_FUNCTION - void compute_uarray(const typename Kokkos::TeamPolicy::member_type& team, int, int, - double, double, double, - double, double); // compute_ui KOKKOS_INLINE_FUNCTION void compute_uarray_cpu(const typename Kokkos::TeamPolicy::member_type& team, int, int, double, double, double, @@ -267,12 +257,8 @@ inline inline int compute_ncoeff(); // SNAKokkos() KOKKOS_INLINE_FUNCTION - void compute_duarray(const typename Kokkos::TeamPolicy::member_type& team, int, int, - double, double, double, // compute_duidrj - double, double, double, double, double); - KOKKOS_INLINE_FUNCTION void compute_duarray_cpu(const typename Kokkos::TeamPolicy::member_type& team, int, int, - double, double, double, // compute_duidrj + double, double, double, // compute_duidrj_cpu double, double, double, double, double); // Sets the style for the switching function diff --git a/src/KOKKOS/sna_kokkos_impl.h b/src/KOKKOS/sna_kokkos_impl.h index ef3312bd16..1daf8fd05c 100644 --- a/src/KOKKOS/sna_kokkos_impl.h +++ b/src/KOKKOS/sna_kokkos_impl.h @@ -19,6 +19,7 @@ #include #include #include +#include namespace LAMMPS_NS { @@ -231,11 +232,22 @@ void SNAKokkos::grow_rij(int newnatom, int newnmax) zlist = t_sna_2c_ll("sna:zlist",idxz_max,natom); //ulist = t_sna_3c("sna:ulist",natom,nmax,idxu_max); - ulist = t_sna_3c_ll("sna:ulist",idxu_max,natom,nmax); +#ifdef KOKKOS_ENABLE_CUDA + if (std::is_same::value) { + // dummy allocation + ulist = t_sna_3c_ll("sna:ulist",1,1,1); + dulist = t_sna_4c_ll("sna:dulist",1,1,1); + } else { +#endif + ulist = t_sna_3c_ll("sna:ulist",idxu_max,natom,nmax); + dulist = t_sna_4c_ll("sna:dulist",idxu_max,natom,nmax); +#ifdef KOKKOS_ENABLE_CUDA + } +#endif + //ylist = t_sna_2c_lr("sna:ylist",natom,idxu_max); ylist = t_sna_2c_ll("sna:ylist",idxu_max,natom); - //dulist = t_sna_4c("sna:dulist",natom,nmax,idxu_max); dulist = t_sna_4c_ll("sna:dulist",idxu_max,natom,nmax); } @@ -269,14 +281,14 @@ void SNAKokkos::pre_ui(const typename Kokkos::TeamPolicy } /* ---------------------------------------------------------------------- - compute Ui by summing over bispectrum components + compute Ui by computing Wigner U-functions for one neighbor and + accumulating to the total. GPU only. ------------------------------------------------------------------------- */ template KOKKOS_INLINE_FUNCTION -void SNAKokkos::compute_ui(const typename Kokkos::TeamPolicy::member_type& team, int iatom, int jnbor) +void SNAKokkos::compute_ui(const typename Kokkos::TeamPolicy::member_type& team, const int iatom, const int jnbor) { - double rsq, r, x, y, z, z0, theta0; // utot(j,ma,mb) = 0 for all j,ma,ma // utot(j,ma,ma) = 1 for all j,ma @@ -284,22 +296,143 @@ void SNAKokkos::compute_ui(const typename Kokkos::TeamPolicy 0)?rootpq2*buf1[jjup_shared_idx-1]:SNAcomplex(0.,0.); + //const SNAcomplex u_up2 = (ma > 0)?rootpq2*ulist(jjup_index-1,iatom,jnbor):SNAcomplex(0.,0.); + caconjxpy(b, u_up2, u_accum); + + // VMK recursion relation: grab contribution which is multiplied by a* + const double rootpq1 = rootpqarray(j - ma, j - mb); + const SNAcomplex u_up1 = (ma < j)?rootpq1*buf1[jjup_shared_idx]:SNAcomplex(0.,0.); + //const SNAcomplex u_up1 = (ma < j)?rootpq1*ulist(jjup_index,iatom,jnbor):SNAcomplex(0.,0.); + caconjxpy(a, u_up1, u_accum); + + //ulist(jju_index,iatom,jnbor) = u_accum; + // back up into shared memory for next iter + buf2[jju_shared_idx] = u_accum; + + Kokkos::atomic_add(&(ulisttot(jju_index,iatom).re), sfac * u_accum.re); + Kokkos::atomic_add(&(ulisttot(jju_index,iatom).im), sfac * u_accum.im); + + // copy left side to right side with inversion symmetry VMK 4.4(2) + // u[ma-j,mb-j] = (-1)^(ma-mb)*Conj([u[ma,mb)) + // if j is even (-> physical j integer), last element maps to self, skip + //if (!(m == total_iters - 1 && j % 2 == 0)) { + if (m < total_iters - 1 || j % 2 == 1) { + const int sign_factor = (((ma+mb)%2==0)?1:-1); + const int jju_shared_flip = (j+1-mb)*(j+1)-(ma+1); + const int jjup_flip = jju + jju_shared_flip; // jju+(j+1-mb)*(j+1)-(ma+1); + + + if (sign_factor == 1) { + u_accum.im = -u_accum.im; + } else { + u_accum.re = -u_accum.re; + } + //ulist(jjup_flip,iatom,jnbor) = u_accum; + buf2[jju_shared_flip] = u_accum; + + Kokkos::atomic_add(&(ulisttot(jjup_flip,iatom).re), sfac * u_accum.re); + Kokkos::atomic_add(&(ulisttot(jjup_flip,iatom).im), sfac * u_accum.im); + } + }); + // In CUDA backend, + // ThreadVectorRange has a __syncwarp (appropriately masked for + // vector lengths < 32) implict at the end + + // swap double buffers + auto tmp = buf1; buf1 = buf2; buf2 = tmp; + + + } } +/* ---------------------------------------------------------------------- + compute Ui by summing over bispectrum components. CPU only. +------------------------------------------------------------------------- */ + template KOKKOS_INLINE_FUNCTION void SNAKokkos::compute_ui_cpu(const typename Kokkos::TeamPolicy::member_type& team, int iatom, int jnbor) @@ -327,37 +460,6 @@ void SNAKokkos::compute_ui_cpu(const typename Kokkos::TeamPolicy -KOKKOS_INLINE_FUNCTION -void SNAKokkos::compute_uitot(const typename Kokkos::TeamPolicy::member_type& team, int idx, int iatom, int ninside) -{ - // fuse initialize in, avoid this load? - SNAcomplex utot = ulisttot(idx, iatom); - for (int jnbor = 0; jnbor < ninside; jnbor++) { - - const auto x = rij(iatom,jnbor,0); - const auto y = rij(iatom,jnbor,1); - const auto z = rij(iatom,jnbor,2); - const auto rsq = x * x + y * y + z * z; - const auto r = sqrt(rsq); - - const double wj_local = wj(iatom, jnbor); - const double rcut = rcutij(iatom, jnbor); - const double sfac = compute_sfac(r, rcut) * wj_local; - - auto ulist_local = ulist(idx, iatom, jnbor); - utot.re += sfac * ulist_local.re; - utot.im += sfac * ulist_local.im; - } - - ulisttot(idx, iatom) = utot; - -} - /* ---------------------------------------------------------------------- compute Zi by summing over products of Ui not updated yet @@ -509,72 +611,203 @@ void SNAKokkos::compute_yi(int iter, } /* ---------------------------------------------------------------------- - compute dEidRj + Fused calculation of the derivative of Ui w.r.t. atom j + and of dEidRj. GPU only. ------------------------------------------------------------------------- */ template KOKKOS_INLINE_FUNCTION -void SNAKokkos::compute_deidrj(const typename Kokkos::TeamPolicy::member_type& team, int iatom, int jnbor) +void SNAKokkos::compute_fused_deidrj(const typename Kokkos::TeamPolicy::member_type& team, const int iatom, const int jnbor) { - t_scalar3 final_sum; + // get shared memory offset + const int max_m_tile = (twojmax+1)*(twojmax/2+1); + const int team_rank = team.team_rank(); + const int scratch_shift = team_rank * max_m_tile; - // Like in ComputeUi/ComputeDuidrj, regular loop over j. - for (int j = 0; j <= twojmax; j++) { - int jju = idxu_block(j); + // double buffer for ulist + SNAcomplex* ulist_buf1 = (SNAcomplex*)team.team_shmem( ).get_shmem(team.team_size()*max_m_tile*sizeof(SNAcomplex), 0) + scratch_shift; + SNAcomplex* ulist_buf2 = (SNAcomplex*)team.team_shmem( ).get_shmem(team.team_size()*max_m_tile*sizeof(SNAcomplex), 0) + scratch_shift; + + // double buffer for dulist + SNAcomplex* dulist_buf1 = (SNAcomplex*)team.team_shmem( ).get_shmem(team.team_size()*max_m_tile*sizeof(SNAcomplex), 0) + scratch_shift; + SNAcomplex* dulist_buf2 = (SNAcomplex*)team.team_shmem( ).get_shmem(team.team_size()*max_m_tile*sizeof(SNAcomplex), 0) + scratch_shift; + + const double x = rij(iatom,jnbor,0); + const double y = rij(iatom,jnbor,1); + const double z = rij(iatom,jnbor,2); + const double rsq = x * x + y * y + z * z; + const double r = sqrt(rsq); + const double rcut = rcutij(iatom, jnbor); + const double rscale0 = rfac0 * MY_PI / (rcut - rmin0); + const double theta0 = (r - rmin0) * rscale0; + const double cs = cos(theta0); + const double sn = sin(theta0); + const double z0 = r * cs / sn; + const double dz0dr = z0 / r - (r*rscale0) * (rsq + z0 * z0) / rsq; + + const double wj_local = wj(iatom, jnbor); + const double sfac = wj_local * compute_sfac(r, rcut); + const double dsfac = wj_local * compute_dsfac(r, rcut); + + const double rinv = 1.0 / r; + + // extract a single unit vector + const double u = (dir == 0 ? x * rinv : dir == 1 ? y * rinv : z * rinv); + + // Compute Cayley-Klein parameters for unit quaternion + const double r0inv = 1.0 / sqrt(r * r + z0 * z0); + + const SNAcomplex a = { r0inv * z0, -r0inv * z }; + const SNAcomplex b = { r0inv * y, -r0inv * x }; + + const double dr0invdr = -r0inv * r0inv * r0inv * (r + z0 * dz0dr); + const double dr0inv = dr0invdr * u; + const double dz0 = dz0dr * u; + + const SNAcomplex da = { dz0 * r0inv + z0 * dr0inv, + - z * dr0inv + (dir == 2 ? - r0inv : 0.) }; + + const SNAcomplex db = { y * dr0inv + (dir==1?r0inv:0.), + -x * dr0inv + (dir==0?-r0inv:0.) }; + + // Accumulate the full contribution to dedr on the fly + const double du_prod = dsfac * u; // chain rule + const SNAcomplex y_local = ylist(0, iatom); - // Flatten loop over ma, mb, reduce w/in + // Symmetry factor of 0.5 b/c 0 element is on diagonal for even j==0 + double dedr_full_sum = 0.5 * du_prod * y_local.re; + // single has a warp barrier at the end + Kokkos::single(Kokkos::PerThread(team), [=]() { + //dulist(0,iatom,jnbor,dir) = { dsfac * u, 0. }; // fold in chain rule here + ulist_buf1[0] = {1., 0.}; + dulist_buf1[0] = {0., 0.}; + }); + + for (int j = 1; j <= twojmax; j++) { + int jju = idxu_block[j]; + int jjup = idxu_block[j-1]; + + // flatten the loop over ma,mb + + // for (int ma = 0; ma <= j; ma++) const int n_ma = j+1; // for (int mb = 0; 2*mb <= j; mb++) const int n_mb = j/2+1; const int total_iters = n_ma * n_mb; - t_scalar3 sum; + double dedr_sum = 0.; // j-local sum //for (int m = 0; m < total_iters; m++) { Kokkos::parallel_reduce(Kokkos::ThreadVectorRange(team, total_iters), - [&] (const int m, t_scalar3& sum_tmp) { + [&] (const int m, double& sum_tmp) { // ma fast, mb slow int ma = m % n_ma; int mb = m / n_ma; - // get index - const int jju_index = jju+mb+mb*j+ma; - - // get ylist, rescale last element by 0.5 - SNAcomplex y_local = ylist(jju_index,iatom); - - const SNAcomplex du_x = dulist(jju_index,iatom,jnbor,0); - const SNAcomplex du_y = dulist(jju_index,iatom,jnbor,1); - const SNAcomplex du_z = dulist(jju_index,iatom,jnbor,2); + const int jju_index = jju+m; + // Load y_local, apply the symmetry scaling factor + // The "secret" of the shared memory optimization is it eliminates + // all global memory reads to duidrj in lieu of caching values in + // shared memory and otherwise always writing, making the kernel + // ultimately compute bound. We take advantage of that by adding + // some reads back in. + auto y_local = ylist(jju_index,iatom); if (j % 2 == 0 && 2*mb == j) { if (ma == mb) { y_local = 0.5*y_local; } - else if (ma > mb) { y_local = { 0., 0. }; } + else if (ma > mb) { y_local = { 0., 0. }; } // can probably avoid this outright // else the ma < mb gets "double counted", cancelling the 0.5. } - sum_tmp.x += du_x.re * y_local.re + du_x.im * y_local.im; - sum_tmp.y += du_y.re * y_local.re + du_y.im * y_local.im; - sum_tmp.z += du_z.re * y_local.re + du_z.im * y_local.im; + // index into shared memory + const int jju_shared_idx = m; + const int jjup_shared_idx = jju_shared_idx - mb; - }, sum); // end loop over flattened ma,mb + // Need to compute and accumulate both u and du (mayhaps, we could probably + // balance some read and compute by reading u each time). + SNAcomplex u_accum = { 0., 0. }; + SNAcomplex du_accum = { 0., 0. }; - final_sum.x += sum.x; - final_sum.y += sum.y; - final_sum.z += sum.z; + const double rootpq2 = -rootpqarray(ma, j - mb); + const SNAcomplex u_up2 = (ma > 0)?rootpq2*ulist_buf1[jjup_shared_idx-1]:SNAcomplex(0.,0.); + caconjxpy(b, u_up2, u_accum); + + const double rootpq1 = rootpqarray(j - ma, j - mb); + const SNAcomplex u_up1 = (ma < j)?rootpq1*ulist_buf1[jjup_shared_idx]:SNAcomplex(0.,0.); + caconjxpy(a, u_up1, u_accum); + + // Next, spin up du_accum + const SNAcomplex du_up1 = (ma < j) ? rootpq1*dulist_buf1[jjup_shared_idx] : SNAcomplex(0.,0.); + caconjxpy(da, u_up1, du_accum); + caconjxpy(a, du_up1, du_accum); + + const SNAcomplex du_up2 = (ma > 0) ? rootpq2*dulist_buf1[jjup_shared_idx-1] : SNAcomplex(0.,0.); + caconjxpy(db, u_up2, du_accum); + caconjxpy(b, du_up2, du_accum); + + // No need to save u_accum to global memory + // Cache u_accum, du_accum to scratch memory. + ulist_buf2[jju_shared_idx] = u_accum; + dulist_buf2[jju_shared_idx] = du_accum; + + // Directly accumulate deidrj into sum_tmp + //dulist(jju_index,iatom,jnbor,dir) = ((dsfac * u)*u_accum) + (sfac*du_accum); + const SNAcomplex du_prod = ((dsfac * u)*u_accum) + (sfac*du_accum); + sum_tmp += du_prod.re * y_local.re + du_prod.im * y_local.im; + + // copy left side to right side with inversion symmetry VMK 4.4(2) + // u[ma-j][mb-j] = (-1)^(ma-mb)*Conj([u[ma][mb]) + if (j%2==1 && mb+1==n_mb) { + int sign_factor = (((ma+mb)%2==0)?1:-1); + //const int jjup_flip = jju+(j+1-mb)*(j+1)-(ma+1); // no longer needed b/c we don't update dulist + const int jju_shared_flip = (j+1-mb)*(j+1)-(ma+1); + + if (sign_factor == 1) { + u_accum.im = -u_accum.im; + du_accum.im = -du_accum.im; + } else { + u_accum.re = -u_accum.re; + du_accum.re = -du_accum.re; + } + + // We don't need the second half of the tile for the deidrj accumulation. + // That's taken care of by the symmetry factor above. + //dulist(jjup_flip,iatom,jnbor,dir) = ((dsfac * u)*u_accum) + (sfac*du_accum); + + // We do need it for ortho polynomial generation, though + ulist_buf2[jju_shared_flip] = u_accum; + dulist_buf2[jju_shared_flip] = du_accum; + } + + }, dedr_sum); + + // swap buffers + auto tmp = ulist_buf1; ulist_buf1 = ulist_buf2; ulist_buf2 = tmp; + tmp = dulist_buf1; dulist_buf1 = dulist_buf2; dulist_buf2 = tmp; + + // Accumulate dedr. This "should" be in a single, but + // a Kokkos::single call implies a warp sync, and we may + // as well avoid that. This does no harm as long as the + // final assignment is in a single block. + //Kokkos::single(Kokkos::PerThread(team), [=]() { + dedr_full_sum += dedr_sum; + //}); } + // Store the accumulated dedr. Kokkos::single(Kokkos::PerThread(team), [&] () { - dedr(iatom,jnbor,0) = final_sum.x*2.0; - dedr(iatom,jnbor,1) = final_sum.y*2.0; - dedr(iatom,jnbor,2) = final_sum.z*2.0; + dedr(iatom,jnbor,dir) = dedr_full_sum*2.0; }); - } +/* ---------------------------------------------------------------------- + compute dEidRj, CPU path only. +------------------------------------------------------------------------- */ + + template KOKKOS_INLINE_FUNCTION void SNAKokkos::compute_deidrj_cpu(const typename Kokkos::TeamPolicy::member_type& team, int iatom, int jnbor) @@ -624,6 +857,7 @@ void SNAKokkos::compute_deidrj_cpu(const typename Kokkos::TeamPolicy /* ---------------------------------------------------------------------- compute Bi by summing conj(Ui)*Zi + not updated yet ------------------------------------------------------------------------- */ template @@ -708,28 +942,6 @@ void SNAKokkos::compute_bi(const typename Kokkos::TeamPolicy -KOKKOS_INLINE_FUNCTION -void SNAKokkos::compute_duidrj(const typename Kokkos::TeamPolicy::member_type& team, int iatom, int jnbor) -{ - double rsq, r, x, y, z, z0, theta0, cs, sn; - double dz0dr; - - x = rij(iatom,jnbor,0); - y = rij(iatom,jnbor,1); - z = rij(iatom,jnbor,2); - rsq = x * x + y * y + z * z; - r = sqrt(rsq); - double rscale0 = rfac0 * MY_PI / (rcutij(iatom,jnbor) - rmin0); - theta0 = (r - rmin0) * rscale0; - cs = cos(theta0); - sn = sin(theta0); - z0 = r * cs / sn; - dz0dr = z0 / r - (r*rscale0) * (rsq + z0 * z0) / rsq; - - compute_duarray(team, iatom, jnbor, x, y, z, z0, r, dz0dr, wj(iatom,jnbor), rcutij(iatom,jnbor)); -} - template KOKKOS_INLINE_FUNCTION void SNAKokkos::compute_duidrj_cpu(const typename Kokkos::TeamPolicy::member_type& team, int iatom, int jnbor) @@ -774,119 +986,6 @@ void SNAKokkos::add_uarraytot(const typename Kokkos::TeamPolicy -KOKKOS_INLINE_FUNCTION -void SNAKokkos::compute_uarray(const typename Kokkos::TeamPolicy::member_type& team, int iatom, int jnbor, - double x, double y, double z, - double z0, double r) -{ - // define size of scratch memory buffer - const int max_m_tile = (twojmax+1)*(twojmax+1); - const int team_rank = team.team_rank(); - - // get scratch memory double buffer - SNAcomplex* buf1 = (SNAcomplex*)team.team_shmem( ).get_shmem(team.team_size()*max_m_tile*sizeof(SNAcomplex), 0); - SNAcomplex* buf2 = (SNAcomplex*)team.team_shmem( ).get_shmem(team.team_size()*max_m_tile*sizeof(SNAcomplex), 0); - - // compute Cayley-Klein parameters for unit quaternion, - // pack into complex number - double r0inv = 1.0 / sqrt(r * r + z0 * z0); - SNAcomplex a = { r0inv * z0, -r0inv * z }; - SNAcomplex b = { r0inv * y, -r0inv * x }; - - // VMK Section 4.8.2 - - // All writes go to global memory and shared memory - // so we can avoid all global memory reads - Kokkos::single(Kokkos::PerThread(team), [=]() { - ulist(0,iatom,jnbor) = { 1.0, 0.0 }; - buf1[max_m_tile*team_rank] = {1.,0.}; - }); - - for (int j = 1; j <= twojmax; j++) { - const int jju = idxu_block[j]; - int jjup = idxu_block[j-1]; - - // fill in left side of matrix layer from previous layer - - // Flatten loop over ma, mb, need to figure out total - // number of iterations - - // for (int ma = 0; ma <= j; ma++) - const int n_ma = j+1; - // for (int mb = 0; 2*mb <= j; mb++) - const int n_mb = j/2+1; - - const int total_iters = n_ma * n_mb; - - //for (int m = 0; m < total_iters; m++) { - Kokkos::parallel_for(Kokkos::ThreadVectorRange(team, total_iters), - [&] (const int m) { - - // ma fast, mb slow - int ma = m % n_ma; - int mb = m / n_ma; - - // index into global memory array - const int jju_index = jju+mb+mb*j+ma; - - // index into shared memory buffer for previous level - const int jju_shared_idx = max_m_tile*team_rank+mb+mb*j+ma; - - // index into shared memory buffer for next level - const int jjup_shared_idx = max_m_tile*team_rank+mb*j+ma; - - SNAcomplex u_accum = {0., 0.}; - - // VMK recursion relation: grab contribution which is multiplied by a* - const double rootpq1 = rootpqarray(j - ma, j - mb); - const SNAcomplex u_up1 = (ma < j)?rootpq1*buf1[jjup_shared_idx]:SNAcomplex(0.,0.); - caconjxpy(a, u_up1, u_accum); - - // VMK recursion relation: grab contribution which is multiplied by b* - const double rootpq2 = -rootpqarray(ma, j - mb); - const SNAcomplex u_up2 = (ma > 0)?rootpq2*buf1[jjup_shared_idx-1]:SNAcomplex(0.,0.); - caconjxpy(b, u_up2, u_accum); - - ulist(jju_index,iatom,jnbor) = u_accum; - - // We no longer accumulate into ulisttot in this kernel. - // Instead, we have a separate kernel which avoids atomics. - // Running two separate kernels is net faster. - - // back up into shared memory for next iter - if (j != twojmax) buf2[jju_shared_idx] = u_accum; - - // copy left side to right side with inversion symmetry VMK 4.4(2) - // u[ma-j,mb-j] = (-1)^(ma-mb)*Conj([u[ma,mb)) - // We can avoid this if we're on the last row for an integer j - if (!(n_ma % 2 == 1 && (mb+1) == n_mb)) { - - int sign_factor = ((ma%2==0)?1:-1)*(mb%2==0?1:-1); - const int jjup_flip = jju+(j+1-mb)*(j+1)-(ma+1); - const int jju_shared_flip = max_m_tile*team_rank+(j+1-mb)*(j+1)-(ma+1); - - if (sign_factor == 1) { - u_accum.im = -u_accum.im; - } else { - u_accum.re = -u_accum.re; - } - ulist(jjup_flip,iatom,jnbor) = u_accum; - if (j != twojmax) buf2[jju_shared_flip] = u_accum; - } - }); - // In CUDA backend, - // ThreadVectorRange has a __syncwarp (appropriately masked for - // vector lengths < 32) implicit at the end - - // swap double buffers - auto tmp = buf1; buf1 = buf2; buf2 = tmp; - //std::swap(buf1, buf2); // throws warnings - - } -} - -// CPU version template KOKKOS_INLINE_FUNCTION void SNAKokkos::compute_uarray_cpu(const typename Kokkos::TeamPolicy::member_type& team, int iatom, int jnbor, @@ -976,152 +1075,9 @@ void SNAKokkos::compute_uarray_cpu(const typename Kokkos::TeamPolicy /* ---------------------------------------------------------------------- compute derivatives of Wigner U-functions for one neighbor - see comments in compute_uarray() + see comments in compute_uarray_cpu() ------------------------------------------------------------------------- */ -template -KOKKOS_INLINE_FUNCTION -void SNAKokkos::compute_duarray(const typename Kokkos::TeamPolicy::member_type& team, int iatom, int jnbor, - double x, double y, double z, - double z0, double r, double dz0dr, - double wj, double rcut) -{ - - // get shared memory offset - const int max_m_tile = (twojmax+1)*(twojmax+1); - const int team_rank = team.team_rank(); - - // double buffer for ulist - SNAcomplex* ulist_buf1 = (SNAcomplex*)team.team_shmem( ).get_shmem(team.team_size()*max_m_tile*sizeof(SNAcomplex), 0); - SNAcomplex* ulist_buf2 = (SNAcomplex*)team.team_shmem( ).get_shmem(team.team_size()*max_m_tile*sizeof(SNAcomplex), 0); - - // double buffer for dulist - SNAcomplex* dulist_buf1 = (SNAcomplex*)team.team_shmem( ).get_shmem(team.team_size()*max_m_tile*sizeof(SNAcomplex), 0); - SNAcomplex* dulist_buf2 = (SNAcomplex*)team.team_shmem( ).get_shmem(team.team_size()*max_m_tile*sizeof(SNAcomplex), 0); - - const double sfac = wj * compute_sfac(r, rcut); - const double dsfac = wj * compute_dsfac(r, rcut); - - const double rinv = 1.0 / r; - - // extract a single unit vector - const double u = (dir == 0 ? x * rinv : dir == 1 ? y * rinv : z * rinv); - - // Compute Cayley-Klein parameters for unit quaternion - - const double r0inv = 1.0 / sqrt(r * r + z0 * z0); - - const SNAcomplex a = { r0inv * z0, -r0inv * z }; - const SNAcomplex b = { r0inv * y, -r0inv * x }; - - const double dr0invdr = -r0inv * r0inv * r0inv * (r + z0 * dz0dr); - const double dr0inv = dr0invdr * u; - const double dz0 = dz0dr * u; - - const SNAcomplex da = { dz0 * r0inv + z0 * dr0inv, - - z * dr0inv + (dir == 2 ? - r0inv : 0.) }; - - const SNAcomplex db = { y * dr0inv + (dir==1?r0inv:0.), - -x * dr0inv + (dir==0?-r0inv:0.) }; - - // single has a warp barrier at the end - Kokkos::single(Kokkos::PerThread(team), [=]() { - dulist(0,iatom,jnbor,dir) = { dsfac * u, 0. }; // fold in chain rule here - ulist_buf1[max_m_tile*team_rank] = {1., 0.}; - dulist_buf1[max_m_tile*team_rank] = {0., 0.}; - }); - - - for (int j = 1; j <= twojmax; j++) { - int jju = idxu_block[j]; - int jjup = idxu_block[j-1]; - - // flatten the loop over ma,mb - - // for (int ma = 0; ma <= j; ma++) - const int n_ma = j+1; - // for (int mb = 0; 2*mb <= j; mb++) - const int n_mb = j/2+1; - - const int total_iters = n_ma * n_mb; - - //for (int m = 0; m < total_iters; m++) { - Kokkos::parallel_for(Kokkos::ThreadVectorRange(team, total_iters), - [&] (const int m) { - - // ma fast, mb slow - int ma = m % n_ma; - int mb = m / n_ma; - - const int jju_index = jju+mb+mb*j+ma; - - // index into shared memory - const int jju_shared_idx = max_m_tile*team_rank+mb+mb*j+ma; - const int jjup_shared_idx = max_m_tile*team_rank+mb*j+ma; - - // Need to compute and accumulate both u and du (mayhaps, we could probably - // balance some read and compute by reading u each time). - SNAcomplex u_accum = { 0., 0. }; - SNAcomplex du_accum = { 0., 0. }; - - const double rootpq1 = rootpqarray(j - ma, j - mb); - const SNAcomplex u_up1 = (ma < j)?rootpq1*ulist_buf1[jjup_shared_idx]:SNAcomplex(0.,0.); - caconjxpy(a, u_up1, u_accum); - - const double rootpq2 = -rootpqarray(ma, j - mb); - const SNAcomplex u_up2 = (ma > 0)?rootpq2*ulist_buf1[jjup_shared_idx-1]:SNAcomplex(0.,0.); - caconjxpy(b, u_up2, u_accum); - - // No need to save u_accum to global memory - if (j != twojmax) ulist_buf2[jju_shared_idx] = u_accum; - - // Next, spin up du_accum - const SNAcomplex du_up1 = (ma < j) ? rootpq1*dulist_buf1[jjup_shared_idx] : SNAcomplex(0.,0.); - caconjxpy(da, u_up1, du_accum); - caconjxpy(a, du_up1, du_accum); - - const SNAcomplex du_up2 = (ma > 0) ? rootpq2*dulist_buf1[jjup_shared_idx-1] : SNAcomplex(0.,0.); - caconjxpy(db, u_up2, du_accum); - caconjxpy(b, du_up2, du_accum); - - dulist(jju_index,iatom,jnbor,dir) = ((dsfac * u)*u_accum) + (sfac*du_accum); - - if (j != twojmax) dulist_buf2[jju_shared_idx] = du_accum; - - // copy left side to right side with inversion symmetry VMK 4.4(2) - // u[ma-j][mb-j] = (-1)^(ma-mb)*Conj([u[ma][mb]) - - int sign_factor = ((ma%2==0)?1:-1)*(mb%2==0?1:-1); - const int jjup_flip = jju+(j+1-mb)*(j+1)-(ma+1); - const int jju_shared_flip = max_m_tile*team_rank+(j+1-mb)*(j+1)-(ma+1); - - if (sign_factor == 1) { - //ulist_alt(iatom,jnbor,jjup_flip).re = u_accum.re; - //ulist_alt(iatom,jnbor,jjup_flip).im = -u_accum.im; - u_accum.im = -u_accum.im; - du_accum.im = -du_accum.im; - } else { - //ulist_alt(iatom,jnbor,jjup_flip).re = -u_accum.re; - //ulist_alt(iatom,jnbor,jjup_flip).im = u_accum.im; - u_accum.re = -u_accum.re; - du_accum.re = -du_accum.re; - } - - dulist(jjup_flip,iatom,jnbor,dir) = ((dsfac * u)*u_accum) + (sfac*du_accum); - - if (j != twojmax) { - ulist_buf2[jju_shared_flip] = u_accum; - dulist_buf2[jju_shared_flip] = du_accum; - } - - }); - - // swap buffers - auto tmp = ulist_buf1; ulist_buf1 = ulist_buf2; ulist_buf2 = tmp; - tmp = dulist_buf1; dulist_buf1 = dulist_buf2; dulist_buf2 = tmp; - } -} - template KOKKOS_INLINE_FUNCTION void SNAKokkos::compute_duarray_cpu(const typename Kokkos::TeamPolicy::member_type& team, int iatom, int jnbor, @@ -1680,11 +1636,17 @@ double SNAKokkos::memory_usage() bytes += jdimpq*jdimpq * sizeof(double); // pqarray bytes += idxcg_max * sizeof(double); // cglist - bytes += natom * idxu_max * sizeof(double) * 2; // ulist +#ifdef KOKKOS_ENABLE_CUDA + if (!std::is_same::value) { +#endif + bytes += natom * idxu_max * sizeof(double) * 2; // ulist + bytes += natom * idxu_max * 3 * sizeof(double) * 2; // dulist +#ifdef KOKKOS_ENABLE_CUDA + } +#endif bytes += natom * idxu_max * sizeof(double) * 2; // ulisttot if (!Kokkos::Impl::is_same::value) bytes += natom * idxu_max * sizeof(double) * 2; // ulisttot_lr - bytes += natom * idxu_max * 3 * sizeof(double) * 2; // dulist bytes += natom * idxz_max * sizeof(double) * 2; // zlist bytes += natom * idxb_max * sizeof(double); // blist -- GitLab From 36095bbfdf39c85b6932bd0ec03ac062209e497e Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Mon, 23 Mar 2020 21:15:00 -0600 Subject: [PATCH 383/689] Tweak comment --- src/KOKKOS/sna_kokkos_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/KOKKOS/sna_kokkos_impl.h b/src/KOKKOS/sna_kokkos_impl.h index 1daf8fd05c..182a49bfb1 100644 --- a/src/KOKKOS/sna_kokkos_impl.h +++ b/src/KOKKOS/sna_kokkos_impl.h @@ -333,7 +333,7 @@ void SNAKokkos::compute_ui(const typename Kokkos::TeamPolicy Date: Mon, 23 Mar 2020 23:31:12 -0400 Subject: [PATCH 384/689] Cleaned up comment. --- src/KOKKOS/sna_kokkos_impl.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/KOKKOS/sna_kokkos_impl.h b/src/KOKKOS/sna_kokkos_impl.h index 182a49bfb1..e7b7087951 100644 --- a/src/KOKKOS/sna_kokkos_impl.h +++ b/src/KOKKOS/sna_kokkos_impl.h @@ -462,7 +462,6 @@ void SNAKokkos::compute_ui_cpu(const typename Kokkos::TeamPolicy -- GitLab From 5fa99cb07281675ebde5ada638d6597ba23a95f5 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Mon, 23 Mar 2020 21:33:11 -0600 Subject: [PATCH 385/689] Comment cleanup --- src/KOKKOS/sna_kokkos_impl.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/KOKKOS/sna_kokkos_impl.h b/src/KOKKOS/sna_kokkos_impl.h index e7b7087951..e6c34a245b 100644 --- a/src/KOKKOS/sna_kokkos_impl.h +++ b/src/KOKKOS/sna_kokkos_impl.h @@ -856,7 +856,6 @@ void SNAKokkos::compute_deidrj_cpu(const typename Kokkos::TeamPolicy /* ---------------------------------------------------------------------- compute Bi by summing conj(Ui)*Zi - not updated yet ------------------------------------------------------------------------- */ template -- GitLab From 0060473cee2824527c44a1839ae7a870f42f9b08 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 24 Mar 2020 11:35:21 -0400 Subject: [PATCH 386/689] fix up some escaped '*' characters in "code-block" sections that do not need to be escaped --- doc/src/bond_oxdna.rst | 2 +- doc/src/pair_bop.rst | 4 ++-- doc/src/pair_class2.rst | 8 ++++---- doc/src/pair_coeff.rst | 12 ++++++------ doc/src/pair_cosine_squared.rst | 2 +- doc/src/pair_meam_sw_spline.rst | 4 +++- doc/src/pair_nb3b_harmonic.rst | 4 +++- doc/src/pair_polymorphic.rst | 4 ++-- doc/src/pair_python.rst | 12 ++++++------ doc/src/pair_spin_magelec.rst | 2 +- 10 files changed, 29 insertions(+), 25 deletions(-) diff --git a/doc/src/bond_oxdna.rst b/doc/src/bond_oxdna.rst index 8e69b298bf..71e5105436 100644 --- a/doc/src/bond_oxdna.rst +++ b/doc/src/bond_oxdna.rst @@ -32,7 +32,7 @@ Examples bond_coeff * 2.0 0.25 0.7564 bond_style oxrna2/fene - bond_coeff \* 2.0 0.25 0.76107 + bond_coeff * 2.0 0.25 0.76107 Description """"""""""" diff --git a/doc/src/pair_bop.rst b/doc/src/pair_bop.rst index ce7b69f41f..5cd045931a 100644 --- a/doc/src/pair_bop.rst +++ b/doc/src/pair_bop.rst @@ -132,9 +132,9 @@ and Te. If your LAMMPS simulation has 4 atoms types and you want the 1st 3 to be Cd, and the 4th to be Te, you would use the following pair_coeff command: -.. parsed-literal:: +.. code-block:: LAMMPS - pair_coeff \* \* CdTe Cd Cd Cd Te + pair_coeff * * CdTe Cd Cd Cd Te The 1st 2 arguments must be \* \* so as to span all LAMMPS atom types. The first three Cd arguments map LAMMPS atom types 1,2,3 to the Cd diff --git a/doc/src/pair_class2.rst b/doc/src/pair_class2.rst index d1c673ab97..8131799181 100644 --- a/doc/src/pair_class2.rst +++ b/doc/src/pair_class2.rst @@ -60,18 +60,18 @@ Examples .. code-block:: LAMMPS pair_style lj/class2 10.0 - pair_coeff \* \* 100.0 2.5 - pair_coeff 1 2\* 100.0 2.5 9.0 + pair_coeff * * 100.0 2.5 + pair_coeff 1 2* 100.0 2.5 9.0 pair_style lj/class2/coul/cut 10.0 pair_style lj/class2/coul/cut 10.0 8.0 - pair_coeff \* \* 100.0 3.0 + pair_coeff * * 100.0 3.0 pair_coeff 1 1 100.0 3.5 9.0 pair_coeff 1 1 100.0 3.5 9.0 9.0 pair_style lj/class2/coul/long 10.0 pair_style lj/class2/coul/long 10.0 8.0 - pair_coeff \* \* 100.0 3.0 + pair_coeff * * 100.0 3.0 pair_coeff 1 1 100.0 3.5 9.0 Description diff --git a/doc/src/pair_coeff.rst b/doc/src/pair_coeff.rst index 26910c1746..1886ce1118 100644 --- a/doc/src/pair_coeff.rst +++ b/doc/src/pair_coeff.rst @@ -19,11 +19,11 @@ Examples .. code-block:: LAMMPS pair_coeff 1 2 1.0 1.0 2.5 - pair_coeff 2 \* 1.0 1.0 - pair_coeff 3\* 1\*2 1.0 1.0 2.5 - pair_coeff \* \* 1.0 1.0 - pair_coeff \* \* nialhjea 1 1 2 - pair_coeff \* 3 morse.table ENTRY1 + pair_coeff 2 * 1.0 1.0 + pair_coeff 3* 1*2 1.0 1.0 2.5 + pair_coeff * * 1.0 1.0 + pair_coeff * * nialhjea 1 1 2 + pair_coeff * 3 morse.table ENTRY1 pair_coeff 1 2 lj/cut 1.0 1.0 2.5 (for pair_style hybrid) Description @@ -55,7 +55,7 @@ pairs, then overwrite the coeffs for just the I,J = 2,3 pair: .. code-block:: LAMMPS - pair_coeff \* \* 1.0 1.0 2.5 + pair_coeff * * 1.0 1.0 2.5 pair_coeff 2 3 2.0 1.0 1.12 A line in a data file that specifies pair coefficients uses the exact diff --git a/doc/src/pair_cosine_squared.rst b/doc/src/pair_cosine_squared.rst index 4f19ddd1e4..b7fa29bbd5 100644 --- a/doc/src/pair_cosine_squared.rst +++ b/doc/src/pair_cosine_squared.rst @@ -31,7 +31,7 @@ Examples .. code-block:: LAMMPS pair_style cosine/squared 3.0 - pair_coeff \* \* 1.0 1.3 + pair_coeff * * 1.0 1.3 pair_coeff 1 3 1.0 1.3 2.0 pair_coeff 1 3 1.0 1.3 wca pair_coeff 1 3 1.0 1.3 2.0 wca diff --git a/doc/src/pair_meam_sw_spline.rst b/doc/src/pair_meam_sw_spline.rst index ebb51795c2..0cf4c57975 100644 --- a/doc/src/pair_meam_sw_spline.rst +++ b/doc/src/pair_meam_sw_spline.rst @@ -75,7 +75,9 @@ If your LAMMPS simulation has 3 atoms types and they are all to be treated with this potential, you would use the following pair_coeff command: -pair_coeff \* \* Ti.meam.sw.spline Ti Ti Ti +.. code-block:: LAMMPS + + pair_coeff * * Ti.meam.sw.spline Ti Ti Ti The 1st 2 arguments must be \* \* so as to span all LAMMPS atom types. The three Ti arguments map LAMMPS atom types 1,2,3 to the Ti element diff --git a/doc/src/pair_nb3b_harmonic.rst b/doc/src/pair_nb3b_harmonic.rst index c4f3f3c3e8..9d63df65d5 100644 --- a/doc/src/pair_nb3b_harmonic.rst +++ b/doc/src/pair_nb3b_harmonic.rst @@ -64,7 +64,9 @@ NULL values are placeholders for atom types that will be used with other potentials. An example of a pair_coeff command for use with the *hybrid* pair style is: -pair_coeff \* \* nb3b/harmonic MgOH.nb3b.harmonic Mg O H +.. code-block:: LAMMPS + + pair_coeff * * nb3b/harmonic MgOH.nb3b.harmonic Mg O H Three-body non-bonded harmonic files in the *potentials* directory of the LAMMPS distribution have a ".nb3b.harmonic" suffix. Lines that diff --git a/doc/src/pair_polymorphic.rst b/doc/src/pair_polymorphic.rst index e06e9e7855..c0db3f10a4 100644 --- a/doc/src/pair_polymorphic.rst +++ b/doc/src/pair_polymorphic.rst @@ -180,9 +180,9 @@ functions for Si-C tersoff potential. If your LAMMPS simulation has 4 atoms types and you want the 1st 3 to be Si, and the 4th to be C, you would use the following pair_coeff command: -.. parsed-literal:: +.. code-block:: LAMMPS - pair_coeff \* \* SiC_tersoff.poly Si Si Si C + pair_coeff * * SiC_tersoff.poly Si Si Si C The 1st 2 arguments must be \* \* so as to span all LAMMPS atom types. The first three Si arguments map LAMMPS atom types 1,2,3 to the diff --git a/doc/src/pair_python.rst b/doc/src/pair_python.rst index fa76d4c16c..e654a6025f 100644 --- a/doc/src/pair_python.rst +++ b/doc/src/pair_python.rst @@ -113,8 +113,8 @@ which the parameters epsilon and sigma are both 1.0: class LJCutMelt(LAMMPSPairPotential): def __init__(self): super(LJCutMelt,self).__init__() - # set coeffs: 48\*eps\*sig\*\*12, 24\*eps\*sig\*\*6, - # 4\*eps\*sig\*\*12, 4\*eps\*sig\*\*6 + # set coeffs: 48*eps*sig**12, 24*eps*sig**6, + # 4*eps*sig**12, 4*eps*sig**6 self.units = 'lj' self.coeff = {'lj' : {'lj' : (48.0,24.0,4.0,4.0)}} @@ -137,18 +137,18 @@ the *LJCutMelt* example, here are the two functions: def compute_force(self,rsq,itype,jtype): coeff = self.coeff[self.pmap[itype]][self.pmap[jtype]] r2inv = 1.0/rsq - r6inv = r2inv\*r2inv\*r2inv + r6inv = r2inv*r2inv*r2inv lj1 = coeff[0] lj2 = coeff[1] - return (r6inv \* (lj1\*r6inv - lj2))\*r2inv + return (r6inv * (lj1*r6inv - lj2))*r2inv def compute_energy(self,rsq,itype,jtype): coeff = self.coeff[self.pmap[itype]][self.pmap[jtype]] r2inv = 1.0/rsq - r6inv = r2inv\*r2inv\*r2inv + r6inv = r2inv*r2inv*r2inv lj3 = coeff[2] lj4 = coeff[3] - return (r6inv \* (lj3\*r6inv - lj4)) + return (r6inv * (lj3*r6inv - lj4)) .. note:: diff --git a/doc/src/pair_spin_magelec.rst b/doc/src/pair_spin_magelec.rst index a220299b07..e4d6b81b8a 100644 --- a/doc/src/pair_spin_magelec.rst +++ b/doc/src/pair_spin_magelec.rst @@ -18,7 +18,7 @@ Examples .. code-block:: LAMMPS pair_style spin/magelec 4.5 - pair_coeff \* \* magelec 4.5 0.00109 1.0 1.0 1.0 + pair_coeff * * magelec 4.5 0.00109 1.0 1.0 1.0 Description """"""""""" -- GitLab From 572502b33d86a7b834dbbe5d646dee42c65e00e9 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 09:35:57 -0600 Subject: [PATCH 387/689] cmake: add_definitions() -> target_compile_definitions() --- cmake/CMakeLists.txt | 20 ++++++++++---------- cmake/Modules/MPI4WIN.cmake | 2 +- cmake/Modules/Packages/KIM.cmake | 6 +++--- cmake/Modules/Packages/KOKKOS.cmake | 4 ++-- cmake/Modules/Packages/KSPACE.cmake | 14 +++++++------- cmake/Modules/Packages/PYTHON.cmake | 2 +- cmake/Modules/Packages/USER-INTEL.cmake | 12 ++++++------ cmake/Modules/Packages/USER-NETCDF.cmake | 6 +++--- cmake/Modules/Packages/USER-OMP.cmake | 2 +- cmake/Modules/Packages/USER-PLUMED.cmake | 8 ++++---- cmake/Modules/Packages/USER-VTK.cmake | 2 +- 11 files changed, 39 insertions(+), 39 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index cc9b3fc56a..b1d90af045 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -189,11 +189,11 @@ if(BUILD_MPI) else() find_package(MPI REQUIRED) include_directories(${MPI_CXX_INCLUDE_PATH}) - add_definitions(-DMPICH_SKIP_MPICXX -DOMPI_SKIP_MPICXX=1) + target_compile_definitions(lammps PRIVATE -DMPICH_SKIP_MPICXX -DOMPI_SKIP_MPICXX=1) target_link_libraries(lammps PUBLIC MPI::MPI_CXX) option(LAMMPS_LONGLONG_TO_LONG "Workaround if your system or MPI version does not recognize 'long long' data types" OFF) if(LAMMPS_LONGLONG_TO_LONG) - add_definitions(-DLAMMPS_LONGLONG_TO_LONG) + target_compile_definitions(lammps PRIVATE -DLAMMPS_LONGLONG_TO_LONG) endif() endif() else() @@ -209,7 +209,7 @@ set(LAMMPS_SIZES_VALUES smallbig bigbig smallsmall) set_property(CACHE LAMMPS_SIZES PROPERTY STRINGS ${LAMMPS_SIZES_VALUES}) validate_option(LAMMPS_SIZES LAMMPS_SIZES_VALUES) string(TOUPPER ${LAMMPS_SIZES} LAMMPS_SIZES) -add_definitions(-DLAMMPS_${LAMMPS_SIZES}) +target_compile_definitions(lammps PRIVATE -DLAMMPS_${LAMMPS_SIZES}) set(LAMMPS_API_DEFINES "${LAMMPS_API_DEFINES} -DLAMMPS_${LAMMPS_SIZES}") # posix_memalign is not available on Windows @@ -219,12 +219,12 @@ else() set(LAMMPS_MEMALIGN "64" CACHE STRING "enables the use of the posix_memalign() call instead of malloc() when large chunks or memory are allocated by LAMMPS. Set to 0 to disable") endif() if(NOT ${LAMMPS_MEMALIGN} STREQUAL "0") - add_definitions(-DLAMMPS_MEMALIGN=${LAMMPS_MEMALIGN}) + target_compile_definitions(lammps PRIVATE -DLAMMPS_MEMALIGN=${LAMMPS_MEMALIGN}) endif() option(LAMMPS_EXCEPTIONS "enable the use of C++ exceptions for error messages (useful for library interface)" OFF) if(LAMMPS_EXCEPTIONS) - add_definitions(-DLAMMPS_EXCEPTIONS) + target_compile_definitions(lammps PUBLIC -DLAMMPS_EXCEPTIONS) set(LAMMPS_API_DEFINES "${LAMMPS_API_DEFINES} -DLAMMPS_EXCEPTIONS") endif() @@ -283,7 +283,7 @@ find_package(JPEG QUIET) option(WITH_JPEG "Enable JPEG support" ${JPEG_FOUND}) if(WITH_JPEG) find_package(JPEG REQUIRED) - add_definitions(-DLAMMPS_JPEG) + target_compile_definitions(lammps PRIVATE -DLAMMPS_JPEG) if(CMAKE_VERSION VERSION_LESS 3.12) include_directories(${JPEG_INCLUDE_DIR}) target_link_libraries(lammps PRIVATE ${JPEG_LIBRARIES}) @@ -303,7 +303,7 @@ if(WITH_PNG) find_package(PNG REQUIRED) find_package(ZLIB REQUIRED) target_link_libraries(lammps PRIVATE PNG::PNG ZLIB::ZLIB) - add_definitions(-DLAMMPS_PNG) + target_compile_definitions(lammps PRIVATE -DLAMMPS_PNG) endif() find_program(GZIP_EXECUTABLE gzip) @@ -313,7 +313,7 @@ if(WITH_GZIP) if(NOT GZIP_FOUND) message(FATAL_ERROR "gzip executable not found") endif() - add_definitions(-DLAMMPS_GZIP) + target_compile_definitions(lammps PRIVATE -DLAMMPS_GZIP) endif() find_program(FFMPEG_EXECUTABLE ffmpeg) @@ -323,7 +323,7 @@ if(WITH_FFMPEG) if(NOT FFMPEG_FOUND) message(FATAL_ERROR "ffmpeg executable not found") endif() - add_definitions(-DLAMMPS_FFMPEG) + target_compile_definitions(lammps PRIVATE -DLAMMPS_FFMPEG) endif() if(BUILD_SHARED_LIBS) @@ -413,7 +413,7 @@ endforeach() # packages that need defines set foreach(PKG MPIIO) if(PKG_${PKG}) - add_definitions(-DLMP_${PKG}) + target_compile_definitions(lammps PRIVATE -DLMP_${PKG}) endif() endforeach() diff --git a/cmake/Modules/MPI4WIN.cmake b/cmake/Modules/MPI4WIN.cmake index 1fe6daada3..a02adca77d 100644 --- a/cmake/Modules/MPI4WIN.cmake +++ b/cmake/Modules/MPI4WIN.cmake @@ -16,7 +16,7 @@ else() endif() ExternalProject_get_property(mpi4win_build SOURCE_DIR) -add_definitions(-DMPICH_SKIP_MPICXX) +target_compile_definitions(lammps PRIVATE -DMPICH_SKIP_MPICXX) include_directories("${SOURCE_DIR}/include") set(MPI4WIN_LIBRARIES "${SOURCE_DIR}/lib/libmpi.a") add_dependencies(lammps mpi4win_build) diff --git a/cmake/Modules/Packages/KIM.cmake b/cmake/Modules/Packages/KIM.cmake index 56fc1449fa..7d349f496b 100644 --- a/cmake/Modules/Packages/KIM.cmake +++ b/cmake/Modules/Packages/KIM.cmake @@ -3,16 +3,16 @@ if(PKG_KIM) find_package(CURL) if(CURL_FOUND) target_link_libraries(lammps PRIVATE CURL::libcurl) - add_definitions(-DLMP_KIM_CURL) + target_compile_definitions(lammps PRIVATE -DLMP_KIM_CURL) set(LMP_DEBUG_CURL OFF CACHE STRING "Set libcurl verbose mode on/off. If on, it displays a lot of verbose information about its operations.") mark_as_advanced(LMP_DEBUG_CURL) if(LMP_DEBUG_CURL) - add_definitions(-DLMP_DEBUG_CURL) + target_compile_definitions(lammps PRIVATE -DLMP_DEBUG_CURL) endif() set(LMP_NO_SSL_CHECK OFF CACHE STRING "Tell libcurl to not verify the peer. If on, the connection succeeds regardless of the names in the certificate. Insecure - Use with caution!") mark_as_advanced(LMP_NO_SSL_CHECK) if(LMP_NO_SSL_CHECK) - add_definitions(-DLMP_NO_SSL_CHECK) + target_compile_definitions(lammps PRIVATE -DLMP_NO_SSL_CHECK) endif() endif() find_package(KIM-API QUIET) diff --git a/cmake/Modules/Packages/KOKKOS.cmake b/cmake/Modules/Packages/KOKKOS.cmake index 58d2c139f6..34c924790e 100644 --- a/cmake/Modules/Packages/KOKKOS.cmake +++ b/cmake/Modules/Packages/KOKKOS.cmake @@ -18,7 +18,7 @@ if(PKG_KOKKOS) include_directories(${Kokkos_INCLUDE_DIRS}) target_link_libraries(lammps PRIVATE kokkos) endif() - add_definitions(-DLMP_KOKKOS) + target_compile_definitions(lammps PRIVATE -DLMP_KOKKOS) set(KOKKOS_PKG_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/KOKKOS) set(KOKKOS_PKG_SOURCES ${KOKKOS_PKG_SOURCES_DIR}/kokkos.cpp @@ -44,7 +44,7 @@ if(PKG_KOKKOS) ${KOKKOS_PKG_SOURCES_DIR}/remap_kokkos.cpp) if(KOKKOS_ENABLE_CUDA) if(NOT ${FFT} STREQUAL "KISS") - add_definitions(-DFFT_CUFFT) + target_compile_definitions(lammps PRIVATE -DFFT_CUFFT) target_link_libraries(lammps PRIVATE cufft) endif() endif() diff --git a/cmake/Modules/Packages/KSPACE.cmake b/cmake/Modules/Packages/KSPACE.cmake index 2a586dccf3..e2a42f3981 100644 --- a/cmake/Modules/Packages/KSPACE.cmake +++ b/cmake/Modules/Packages/KSPACE.cmake @@ -3,7 +3,7 @@ if(PKG_KSPACE) set(FFTW "FFTW3") if(FFT_SINGLE) set(FFTW "FFTW3F") - add_definitions(-DFFT_SINGLE) + target_compile_definitions(lammps PUBLIC -DFFT_SINGLE) endif() find_package(${FFTW} QUIET) if(${FFTW}_FOUND) @@ -18,7 +18,7 @@ if(PKG_KSPACE) if(FFT STREQUAL "FFTW3") find_package(${FFTW} REQUIRED) - add_definitions(-DFFT_FFTW3) + target_compile_definitions(lammps PUBLIC -DFFT_FFTW3) target_link_libraries(lammps PUBLIC ${FFTW}::${FFTW}) if(FFTW3_OMP_LIBRARY OR FFTW3F_OMP_LIBRARY) option(FFT_FFTW_THREADS "Use threaded FFTW library" ON) @@ -28,7 +28,7 @@ if(PKG_KSPACE) if(FFT_FFTW_THREADS) if(FFTW3_OMP_LIBRARY OR FFTW3F_OMP_LIBRARY) - add_definitions(-DFFT_FFTW_THREADS) + target_compile_definitions(lammps PRIVATE -DFFT_FFTW_THREADS) target_link_libraries(lammps PRIVATE ${FFTW}::${FFTW}_OMP) else() message(FATAL_ERROR "Need OpenMP enabled FFTW3 library for FFT_THREADS") @@ -36,16 +36,16 @@ if(PKG_KSPACE) endif() elseif(FFT STREQUAL "MKL") find_package(MKL REQUIRED) - add_definitions(-DFFT_MKL) + target_compile_definitions(lammps PRIVATE -DFFT_MKL) option(FFT_MKL_THREADS "Use threaded MKL FFT" ON) if(FFT_MKL_THREADS) - add_definitions(-DFFT_MKL_THREADS) + target_compile_definitions(lammps PRIVATE -DFFT_MKL_THREADS) endif() include_directories(${MKL_INCLUDE_DIRS}) target_link_libraries(lammps PRIVATE ${MKL_LIBRARIES}) else() # last option is KISSFFT - add_definitions(-DFFT_KISS) + target_compile_definitions(lammps PRIVATE -DFFT_KISS) endif() set(FFT_PACK "array" CACHE STRING "Optimization for FFT") @@ -54,6 +54,6 @@ if(PKG_KSPACE) validate_option(FFT_PACK FFT_PACK_VALUES) if(NOT FFT_PACK STREQUAL "array") string(TOUPPER ${FFT_PACK} FFT_PACK) - add_definitions(-DFFT_PACK_${FFT_PACK}) + target_compile_definitions(lammps PRIVATE -DFFT_PACK_${FFT_PACK}) endif() endif() diff --git a/cmake/Modules/Packages/PYTHON.cmake b/cmake/Modules/Packages/PYTHON.cmake index 7d6e2999f7..4611fddb98 100644 --- a/cmake/Modules/Packages/PYTHON.cmake +++ b/cmake/Modules/Packages/PYTHON.cmake @@ -1,6 +1,6 @@ if(PKG_PYTHON) find_package(PythonLibs REQUIRED) - add_definitions(-DLMP_PYTHON) + target_compile_definitions(lammps PRIVATE -DLMP_PYTHON) include_directories(${PYTHON_INCLUDE_DIR}) target_link_libraries(lammps PRIVATE ${PYTHON_LIBRARY}) endif() diff --git a/cmake/Modules/Packages/USER-INTEL.cmake b/cmake/Modules/Packages/USER-INTEL.cmake index 0a9b634bc7..96a897297f 100644 --- a/cmake/Modules/Packages/USER-INTEL.cmake +++ b/cmake/Modules/Packages/USER-INTEL.cmake @@ -4,7 +4,7 @@ if(PKG_USER-INTEL) message(FATAL_ERROR "immintrin.h header not found, Intel package won't work without it") endif() - add_definitions(-DLMP_USER_INTEL) + target_compile_definitions(lammps PRIVATE -DLMP_USER_INTEL) set(INTEL_ARCH "cpu" CACHE STRING "Architectures used by USER-INTEL (cpu or knl)") set(INTEL_ARCH_VALUES cpu knl) @@ -24,14 +24,14 @@ if(PKG_USER-INTEL) string(TOUPPER ${INTEL_LRT_MODE} INTEL_LRT_MODE) if(INTEL_LRT_MODE STREQUAL "THREADS") if(Threads_FOUND) - add_definitions(-DLMP_INTEL_USELRT) + target_compile_definitions(lammps PRIVATE -DLMP_INTEL_USELRT) target_link_libraries(lammps PRIVATE Threads::Threads) else() message(FATAL_ERROR "Must have working threads library for Long-range thread support") endif() endif() if(INTEL_LRT_MODE STREQUAL "C++11") - add_definitions(-DLMP_INTEL_USERLRT -DLMP_INTEL_LRT11) + target_compile_definitions(lammps PRIVATE -DLMP_INTEL_USERLRT -DLMP_INTEL_LRT11) endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") @@ -46,7 +46,7 @@ if(PKG_USER-INTEL) if(TBB_FOUND) target_link_libraries(lammps PRIVATE ${TBB_MALLOC_LIBRARIES}) else() - add_definitions(-DLMP_INTEL_NO_TBB) + target_compile_definitions(lammps PRIVATE -DLMP_INTEL_NO_TBB) if(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") message(WARNING "USER-INTEL with Intel compilers should use TBB malloc libraries") endif() @@ -54,7 +54,7 @@ if(PKG_USER-INTEL) find_package(MKL QUIET) if(MKL_FOUND) - add_definitions(-DLMP_USE_MKL_RNG) + target_compile_definitions(lammps PRIVATE -DLMP_USE_MKL_RNG) target_link_libraries(lammps PRIVATE ${MKL_LIBRARIES}) else() message(STATUS "Pair style dpd/intel will be faster with MKL libraries") @@ -71,7 +71,7 @@ if(PKG_USER-INTEL) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -xHost -qopenmp -qoffload") set(MIC_OPTIONS "-qoffload-option,mic,compiler,\"-fp-model fast=2 -mGLOB_default_function_attrs=\\\"gather_scatter_loop_unroll=4\\\"\"") add_compile_options(-xMIC-AVX512 -qoffload -fno-alias -ansi-alias -restrict -qoverride-limits ${MIC_OPTIONS}) - add_definitions(-DLMP_INTEL_OFFLOAD) + target_compile_definitions(lammps PRIVATE -DLMP_INTEL_OFFLOAD) else() if(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") include(CheckCXXCompilerFlag) diff --git a/cmake/Modules/Packages/USER-NETCDF.cmake b/cmake/Modules/Packages/USER-NETCDF.cmake index 8d62f5f7ec..2c12d2b799 100644 --- a/cmake/Modules/Packages/USER-NETCDF.cmake +++ b/cmake/Modules/Packages/USER-NETCDF.cmake @@ -11,14 +11,14 @@ if(PKG_USER-NETCDF) if(NETCDF_FOUND) include_directories(${NETCDF_INCLUDE_DIRS}) target_link_libraries(lammps PRIVATE ${NETCDF_LIBRARIES}) - add_definitions(-DLMP_HAS_NETCDF) + target_compile_definitions(lammps PRIVATE -DLMP_HAS_NETCDF) endif(NETCDF_FOUND) if(PNETCDF_FOUND) include_directories(${PNETCDF_INCLUDES}) target_link_libraries(lammps PRIVATE ${PNETCDF_LIBRARIES}) - add_definitions(-DLMP_HAS_PNETCDF) + target_compile_definitions(lammps PRIVATE -DLMP_HAS_PNETCDF) endif(PNETCDF_FOUND) - add_definitions(-DNC_64BIT_DATA=0x0020) + target_compile_definitions(lammps PRIVATE -DNC_64BIT_DATA=0x0020) endif() diff --git a/cmake/Modules/Packages/USER-OMP.cmake b/cmake/Modules/Packages/USER-OMP.cmake index 4b1a4b1571..91f0467a17 100644 --- a/cmake/Modules/Packages/USER-OMP.cmake +++ b/cmake/Modules/Packages/USER-OMP.cmake @@ -6,7 +6,7 @@ if(PKG_USER-OMP) ${USER-OMP_SOURCES_DIR}/fix_nh_omp.cpp ${USER-OMP_SOURCES_DIR}/fix_nh_sphere_omp.cpp ${USER-OMP_SOURCES_DIR}/domain_omp.cpp) - add_definitions(-DLMP_USER_OMP) + target_compile_definitions(lammps PRIVATE -DLMP_USER_OMP) set_property(GLOBAL PROPERTY "OMP_SOURCES" "${USER-OMP_SOURCES}") # detects styles which have USER-OMP version diff --git a/cmake/Modules/Packages/USER-PLUMED.cmake b/cmake/Modules/Packages/USER-PLUMED.cmake index a6cd20adbb..cfd187ed9d 100644 --- a/cmake/Modules/Packages/USER-PLUMED.cmake +++ b/cmake/Modules/Packages/USER-PLUMED.cmake @@ -69,12 +69,12 @@ if(PKG_USER-PLUMED) set(PLUMED_INSTALL_DIR ${INSTALL_DIR}) add_dependencies(lammps plumed_build) if(PLUMED_MODE STREQUAL "STATIC") - add_definitions(-D__PLUMED_WRAPPER_CXX=1) + target_compile_definitions(lammps PRIVATE -D__PLUMED_WRAPPER_CXX=1) target_link_libraries(lammps PRIVATE ${PLUMED_INSTALL_DIR}/lib/libplumed.a ${PLUMED_LINK_LIBS} ${CMAKE_DL_LIBS}) elseif(PLUMED_MODE STREQUAL "SHARED") target_link_libraries(lammps PRIVATE ${PLUMED_INSTALL_DIR}/lib/libplumed${CMAKE_SHARED_LIBRARY_SUFFIX} ${PLUMED_INSTALL_DIR}/lib/libplumedKernel${CMAKE_SHARED_LIBRARY_SUFFIX} ${CMAKE_DL_LIBS}) elseif(PLUMED_MODE STREQUAL "RUNTIME") - add_definitions(-D__PLUMED_HAS_DLOPEN=1 -D__PLUMED_DEFAULT_KERNEL=${PLUMED_INSTALL_DIR}/lib/libplumedKernel${CMAKE_SHARED_LIBRARY_SUFFIX}) + target_compile_definitions(lammps PRIVATE -D__PLUMED_HAS_DLOPEN=1 -D__PLUMED_DEFAULT_KERNEL=${PLUMED_INSTALL_DIR}/lib/libplumedKernel${CMAKE_SHARED_LIBRARY_SUFFIX}) target_link_libraries(lammps PRIVATE ${PLUMED_INSTALL_DIR}/lib/libplumedWrapper.a -rdynamic ${CMAKE_DL_LIBS}) endif() set(PLUMED_INCLUDE_DIRS "${PLUMED_INSTALL_DIR}/include") @@ -82,12 +82,12 @@ if(PKG_USER-PLUMED) find_package(PkgConfig REQUIRED) pkg_check_modules(PLUMED REQUIRED plumed) if(PLUMED_MODE STREQUAL "STATIC") - add_definitions(-D__PLUMED_WRAPPER_CXX=1) + target_compile_definitions(lammps PRIVATE -D__PLUMED_WRAPPER_CXX=1) include(${PLUMED_LIBDIR}/plumed/src/lib/Plumed.cmake.static) elseif(PLUMED_MODE STREQUAL "SHARED") include(${PLUMED_LIBDIR}/plumed/src/lib/Plumed.cmake.shared) elseif(PLUMED_MODE STREQUAL "RUNTIME") - add_definitions(-D__PLUMED_HAS_DLOPEN=1 -D__PLUMED_DEFAULT_KERNEL=${PLUMED_LIBDIR}/libplumedKernel${CMAKE_SHARED_LIBRARY_SUFFIX}) + target_compile_definitions(lammps PRIVATE -D__PLUMED_HAS_DLOPEN=1 -D__PLUMED_DEFAULT_KERNEL=${PLUMED_LIBDIR}/libplumedKernel${CMAKE_SHARED_LIBRARY_SUFFIX}) include(${PLUMED_LIBDIR}/plumed/src/lib/Plumed.cmake.runtime) endif() target_link_libraries(lammps PRIVATE ${PLUMED_LOAD}) diff --git a/cmake/Modules/Packages/USER-VTK.cmake b/cmake/Modules/Packages/USER-VTK.cmake index fb69f115b2..61defcbf82 100644 --- a/cmake/Modules/Packages/USER-VTK.cmake +++ b/cmake/Modules/Packages/USER-VTK.cmake @@ -1,6 +1,6 @@ if(PKG_USER-VTK) find_package(VTK REQUIRED NO_MODULE) include(${VTK_USE_FILE}) - add_definitions(-DLAMMPS_VTK) + target_compile_definitions(lammps PRIVATE -DLAMMPS_VTK) target_link_libraries(lammps PRIVATE ${VTK_LIBRARIES}) endif() -- GitLab From f2ab654662fbba0a43a3919d13bb48590d8d08a9 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 10:41:19 -0600 Subject: [PATCH 388/689] cmake: some include_directories() -> target_include_directories() --- cmake/CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index b1d90af045..aaafd9c3f6 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -165,7 +165,7 @@ endif() ###################################################### # packages with special compiler needs or external libs ###################################################### -include_directories(${LAMMPS_SOURCE_DIR}) +target_include_directories(lammps PRIVATE ${LAMMPS_SOURCE_DIR}) if(PKG_USER-ADIOS) # The search for ADIOS2 must come before MPI because @@ -200,7 +200,7 @@ else() enable_language(C) file(GLOB MPI_SOURCES ${LAMMPS_SOURCE_DIR}/STUBS/mpi.c) add_library(mpi_stubs STATIC ${MPI_SOURCES}) - include_directories(${LAMMPS_SOURCE_DIR}/STUBS) + target_include_directories(mpi_stubs PUBLIC ${LAMMPS_SOURCE_DIR}/STUBS) target_link_libraries(lammps PRIVATE mpi_stubs) endif() @@ -285,7 +285,7 @@ if(WITH_JPEG) find_package(JPEG REQUIRED) target_compile_definitions(lammps PRIVATE -DLAMMPS_JPEG) if(CMAKE_VERSION VERSION_LESS 3.12) - include_directories(${JPEG_INCLUDE_DIR}) + target_include_directories(lammps PRIVATE ${JPEG_INCLUDE_DIR}) target_link_libraries(lammps PRIVATE ${JPEG_LIBRARIES}) else() target_link_libraries(lammps PRIVATE JPEG::JPEG) @@ -404,7 +404,7 @@ foreach(PKG ${DEFAULT_PACKAGES}) RegisterStyles(${${PKG}_SOURCES_DIR}) target_sources(lammps PRIVATE ${${PKG}_SOURCES}) - include_directories(${${PKG}_SOURCES_DIR}) + target_include_directories(lammps PRIVATE ${${PKG}_SOURCES_DIR}) endif() RegisterPackages(${${PKG}_SOURCES_DIR}) @@ -504,7 +504,7 @@ set(LAMMPS_STYLE_HEADERS_DIR ${CMAKE_CURRENT_BINARY_DIR}/styles) GenerateStyleHeaders(${LAMMPS_STYLE_HEADERS_DIR}) GeneratePackagesHeaders(${LAMMPS_STYLE_HEADERS_DIR}) -include_directories(${LAMMPS_STYLE_HEADERS_DIR}) +target_include_directories(lammps PRIVATE ${LAMMPS_STYLE_HEADERS_DIR}) ###################################### # Generate lmpinstalledpkgs.h -- GitLab From 31930139c6a5ffcb956ec7da462df330590b3a77 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 10:49:13 -0600 Subject: [PATCH 389/689] USER-SMD.cmake: use Eigen3 imported target --- cmake/Modules/Packages/USER-SMD.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/Modules/Packages/USER-SMD.cmake b/cmake/Modules/Packages/USER-SMD.cmake index eed60ae8bd..9d2c48fe1d 100644 --- a/cmake/Modules/Packages/USER-SMD.cmake +++ b/cmake/Modules/Packages/USER-SMD.cmake @@ -15,7 +15,7 @@ if(PKG_USER-SMD) CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" ) ExternalProject_get_property(Eigen3_build SOURCE_DIR) - set(EIGEN3_INCLUDE_DIR ${SOURCE_DIR}) + target_include_directories(lammps ${SOURCE_DIR}) add_dependencies(lammps Eigen3_build) else() find_package(Eigen3 NO_MODULE) @@ -23,6 +23,6 @@ if(PKG_USER-SMD) if(NOT EIGEN3_FOUND) message(FATAL_ERROR "Eigen3 not found, help CMake to find it by setting EIGEN3_INCLUDE_DIR, or set DOWNLOAD_EIGEN3=ON to download it") endif() + target_link_libraries(lammps PRIVATE Eigen3::Eigen) endif() - include_directories(${EIGEN3_INCLUDE_DIR}) endif() -- GitLab From 9b244b14a6f00f14237e51b3124cda8b420d63a8 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 10:56:49 -0600 Subject: [PATCH 390/689] atc: needs lammps.h --- cmake/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index aaafd9c3f6..a93f1ee42a 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -465,6 +465,7 @@ if(PKG_USER-ATC) message(FATAL_ERROR "The USER-ATC Package is not compatible with -DLAMMPS_BIGBIG") endif() target_link_libraries(atc PRIVATE ${LAPACK_LIBRARIES}) + target_include_directories(atc PRIVATE ${LAMMPS_SOURCE_DIR}) endif() include(Packages/USER-H5MD) -- GitLab From 51eb865d6342ec32cd1262635a86d78802f75c7c Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 11:05:25 -0600 Subject: [PATCH 391/689] VORONOI.cmake: use VORO imported target --- cmake/Modules/FindVORO.cmake | 16 +++++++++++++--- cmake/Modules/Packages/VORONOI.cmake | 7 +++---- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/cmake/Modules/FindVORO.cmake b/cmake/Modules/FindVORO.cmake index b0cccbcd1d..3f0fe98ff1 100644 --- a/cmake/Modules/FindVORO.cmake +++ b/cmake/Modules/FindVORO.cmake @@ -10,13 +10,23 @@ find_path(VORO_INCLUDE_DIR voro++.hh PATH_SUFFIXES voro++) find_library(VORO_LIBRARY NAMES voro++) -set(VORO_LIBRARIES ${VORO_LIBRARY}) -set(VORO_INCLUDE_DIRS ${VORO_INCLUDE_DIR}) - include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set VORO_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(VORO DEFAULT_MSG VORO_LIBRARY VORO_INCLUDE_DIR) +# Copy the results to the output variables and target. +if(VORO_FOUND) + set(VORO_LIBRARIES ${VORO_LIBRARY}) + set(VORO_INCLUDE_DIRS ${VORO_INCLUDE_DIR}) + + if(NOT TARGET VORO::VORO) + add_library(VORO::VORO UNKNOWN IMPORTED) + set_target_properties(VORO::VORO PROPERTIES + IMPORTED_LOCATION "${VORO_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${VORO_INCLUDE_DIR}") + endif() +endif() + mark_as_advanced(VORO_INCLUDE_DIR VORO_LIBRARY ) diff --git a/cmake/Modules/Packages/VORONOI.cmake b/cmake/Modules/Packages/VORONOI.cmake index d2bb185228..e7f2b6b46d 100644 --- a/cmake/Modules/Packages/VORONOI.cmake +++ b/cmake/Modules/Packages/VORONOI.cmake @@ -29,15 +29,14 @@ if(PKG_VORONOI) BUILD_BYPRODUCTS /src/libvoro++.a ) ExternalProject_get_property(voro_build SOURCE_DIR) - set(VORO_LIBRARIES ${SOURCE_DIR}/src/libvoro++.a) - set(VORO_INCLUDE_DIRS ${SOURCE_DIR}/src) + target_link_libraries(lammps PRIVATE ${SOURCE_DIR}/src/libvoro++.a) + target_include_directories(lammps PRIVATE ${SOURCE_DIR}/src) add_dependencies(lammps voro_build) else() find_package(VORO) if(NOT VORO_FOUND) message(FATAL_ERROR "Voro++ library not found. Help CMake to find it by setting VORO_LIBRARY and VORO_INCLUDE_DIR, or set DOWNLOAD_VORO=ON to download it") endif() + target_link_libraries(lammps PRIVATE VORO::VORO) endif() - include_directories(${VORO_INCLUDE_DIRS}) - target_link_libraries(lammps PRIVATE ${VORO_LIBRARIES}) endif() -- GitLab From 4736402dd944d773a081fbf7cc6933010644da64 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 11:07:45 -0600 Subject: [PATCH 392/689] cmake: atc needs mpi itself --- cmake/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index a93f1ee42a..0001f37fce 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -202,6 +202,7 @@ else() add_library(mpi_stubs STATIC ${MPI_SOURCES}) target_include_directories(mpi_stubs PUBLIC ${LAMMPS_SOURCE_DIR}/STUBS) target_link_libraries(lammps PRIVATE mpi_stubs) + add_library(MPI::MPI_CXX ALIAS mpi_stubs) endif() set(LAMMPS_SIZES "smallbig" CACHE STRING "LAMMPS integer sizes (smallsmall: all 32-bit, smallbig: 64-bit #atoms #timesteps, bigbig: also 64-bit imageint, 64-bit atom ids)") @@ -464,7 +465,7 @@ if(PKG_USER-ATC) if(LAMMPS_SIZES STREQUAL BIGBIG) message(FATAL_ERROR "The USER-ATC Package is not compatible with -DLAMMPS_BIGBIG") endif() - target_link_libraries(atc PRIVATE ${LAPACK_LIBRARIES}) + target_link_libraries(atc PRIVATE ${LAPACK_LIBRARIES} MPI::MPI_CXX) target_include_directories(atc PRIVATE ${LAMMPS_SOURCE_DIR}) endif() -- GitLab From 33a57ed21592615a752021c789df4db142747edd Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 11:36:21 -0600 Subject: [PATCH 393/689] cmake: some more include_directories() -> target_include_directories() --- cmake/Modules/MPI4WIN.cmake | 2 +- cmake/Modules/Packages/CORESHELL.cmake | 2 +- cmake/Modules/Packages/GPU.cmake | 2 +- cmake/Modules/Packages/KIM.cmake | 2 +- cmake/Modules/Packages/KOKKOS.cmake | 4 ++-- cmake/Modules/Packages/KSPACE.cmake | 2 +- cmake/Modules/Packages/MESSAGE.cmake | 2 +- cmake/Modules/Packages/OPT.cmake | 2 +- cmake/Modules/Packages/PYTHON.cmake | 2 +- cmake/Modules/Packages/QEQ.cmake | 2 +- cmake/Modules/Packages/USER-H5MD.cmake | 1 - cmake/Modules/Packages/USER-INTEL.cmake | 2 +- cmake/Modules/Packages/USER-OMP.cmake | 2 +- cmake/Modules/Packages/USER-PLUMED.cmake | 2 +- cmake/Modules/Packages/USER-SDPD.cmake | 2 +- 15 files changed, 15 insertions(+), 16 deletions(-) diff --git a/cmake/Modules/MPI4WIN.cmake b/cmake/Modules/MPI4WIN.cmake index a02adca77d..4447289668 100644 --- a/cmake/Modules/MPI4WIN.cmake +++ b/cmake/Modules/MPI4WIN.cmake @@ -17,7 +17,7 @@ endif() ExternalProject_get_property(mpi4win_build SOURCE_DIR) target_compile_definitions(lammps PRIVATE -DMPICH_SKIP_MPICXX) -include_directories("${SOURCE_DIR}/include") +target_include_directories(lammps PRIVATE "${SOURCE_DIR}/include") set(MPI4WIN_LIBRARIES "${SOURCE_DIR}/lib/libmpi.a") add_dependencies(lammps mpi4win_build) set(LAMMPS_USE_MPI4WIN ON) diff --git a/cmake/Modules/Packages/CORESHELL.cmake b/cmake/Modules/Packages/CORESHELL.cmake index 2afe2b8c1b..e550b1989f 100644 --- a/cmake/Modules/Packages/CORESHELL.cmake +++ b/cmake/Modules/Packages/CORESHELL.cmake @@ -9,5 +9,5 @@ if(PKG_CORESHELL) get_property(CORESHELL_SOURCES GLOBAL PROPERTY CORESHELL_SOURCES) target_sources(lammps PRIVATE ${CORESHELL_SOURCES}) - include_directories(${CORESHELL_SOURCES_DIR}) + target_include_directories(lammps PRIVATE ${CORESHELL_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/GPU.cmake b/cmake/Modules/Packages/GPU.cmake index 95bb525dd5..cd359068e7 100644 --- a/cmake/Modules/Packages/GPU.cmake +++ b/cmake/Modules/Packages/GPU.cmake @@ -193,5 +193,5 @@ if(PKG_GPU) get_property(GPU_SOURCES GLOBAL PROPERTY GPU_SOURCES) target_sources(lammps PRIVATE ${GPU_SOURCES}) - include_directories(${GPU_SOURCES_DIR}) + target_include_directories(lammps PRIVATE ${GPU_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/KIM.cmake b/cmake/Modules/Packages/KIM.cmake index 7d349f496b..5a4b12956e 100644 --- a/cmake/Modules/Packages/KIM.cmake +++ b/cmake/Modules/Packages/KIM.cmake @@ -62,5 +62,5 @@ if(PKG_KIM) find_package(KIM-API ${KIM-API_MIN_VERSION} REQUIRED) endif() target_link_libraries(lammps PRIVATE "${KIM-API_LDFLAGS}") - include_directories(${KIM-API_INCLUDE_DIRS}) + target_include_directories(lammps PRIVATE ${KIM-API_INCLUDE_DIRS}) endif() diff --git a/cmake/Modules/Packages/KOKKOS.cmake b/cmake/Modules/Packages/KOKKOS.cmake index 34c924790e..083b55840c 100644 --- a/cmake/Modules/Packages/KOKKOS.cmake +++ b/cmake/Modules/Packages/KOKKOS.cmake @@ -15,7 +15,7 @@ if(PKG_KOKKOS) ${LAMMPS_LIB_KOKKOS_SRC_DIR}/containers/src ${LAMMPS_LIB_KOKKOS_SRC_DIR}/algorithms/src ${LAMMPS_LIB_KOKKOS_BIN_DIR}) - include_directories(${Kokkos_INCLUDE_DIRS}) + target_include_directories(lammps PRIVATE ${Kokkos_INCLUDE_DIRS}) target_link_libraries(lammps PRIVATE kokkos) endif() target_compile_definitions(lammps PRIVATE -DLMP_KOKKOS) @@ -70,5 +70,5 @@ if(PKG_KOKKOS) get_property(KOKKOS_PKG_SOURCES GLOBAL PROPERTY KOKKOS_PKG_SOURCES) target_sources(lammps PRIVATE ${KOKKOS_PKG_SOURCES}) - include_directories(${KOKKOS_PKG_SOURCES_DIR}) + target_include_directories(lammps PRIVATE ${KOKKOS_PKG_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/KSPACE.cmake b/cmake/Modules/Packages/KSPACE.cmake index e2a42f3981..184a70f746 100644 --- a/cmake/Modules/Packages/KSPACE.cmake +++ b/cmake/Modules/Packages/KSPACE.cmake @@ -41,7 +41,7 @@ if(PKG_KSPACE) if(FFT_MKL_THREADS) target_compile_definitions(lammps PRIVATE -DFFT_MKL_THREADS) endif() - include_directories(${MKL_INCLUDE_DIRS}) + target_include_directories(lammps PRIVATE ${MKL_INCLUDE_DIRS}) target_link_libraries(lammps PRIVATE ${MKL_LIBRARIES}) else() # last option is KISSFFT diff --git a/cmake/Modules/Packages/MESSAGE.cmake b/cmake/Modules/Packages/MESSAGE.cmake index c28c50c507..54d9f3eef7 100644 --- a/cmake/Modules/Packages/MESSAGE.cmake +++ b/cmake/Modules/Packages/MESSAGE.cmake @@ -28,5 +28,5 @@ if(PKG_MESSAGE) endif() target_link_libraries(lammps PRIVATE cslib) - include_directories(${LAMMPS_LIB_SOURCE_DIR}/message/cslib/src) + target_include_directories(lammps PRIVATE ${LAMMPS_LIB_SOURCE_DIR}/message/cslib/src) endif() diff --git a/cmake/Modules/Packages/OPT.cmake b/cmake/Modules/Packages/OPT.cmake index 02e3877c59..5d006bfd58 100644 --- a/cmake/Modules/Packages/OPT.cmake +++ b/cmake/Modules/Packages/OPT.cmake @@ -9,5 +9,5 @@ if(PKG_OPT) get_property(OPT_SOURCES GLOBAL PROPERTY OPT_SOURCES) target_sources(lammps PRIVATE ${OPT_SOURCES}) - include_directories(${OPT_SOURCES_DIR}) + target_include_directories(lammps PRIVATE ${OPT_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/PYTHON.cmake b/cmake/Modules/Packages/PYTHON.cmake index 4611fddb98..b2451ebbdf 100644 --- a/cmake/Modules/Packages/PYTHON.cmake +++ b/cmake/Modules/Packages/PYTHON.cmake @@ -1,6 +1,6 @@ if(PKG_PYTHON) find_package(PythonLibs REQUIRED) target_compile_definitions(lammps PRIVATE -DLMP_PYTHON) - include_directories(${PYTHON_INCLUDE_DIR}) + target_include_directories(lammps PRIVATE ${PYTHON_INCLUDE_DIR}) target_link_libraries(lammps PRIVATE ${PYTHON_LIBRARY}) endif() diff --git a/cmake/Modules/Packages/QEQ.cmake b/cmake/Modules/Packages/QEQ.cmake index 9b151c2610..d69fb23440 100644 --- a/cmake/Modules/Packages/QEQ.cmake +++ b/cmake/Modules/Packages/QEQ.cmake @@ -16,5 +16,5 @@ if(PKG_QEQ) get_property(QEQ_SOURCES GLOBAL PROPERTY QEQ_SOURCES) target_sources(lammps PRIVATE ${QEQ_SOURCES}) - include_directories(${QEQ_SOURCES_DIR}) + target_include_directories(lammps PRIVATE ${QEQ_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/USER-H5MD.cmake b/cmake/Modules/Packages/USER-H5MD.cmake index 1e3fcf82ce..cf5623f46d 100644 --- a/cmake/Modules/Packages/USER-H5MD.cmake +++ b/cmake/Modules/Packages/USER-H5MD.cmake @@ -4,5 +4,4 @@ if(PKG_USER-H5MD) find_package(HDF5 REQUIRED) target_link_libraries(h5md PRIVATE ${HDF5_LIBRARIES}) target_include_directories(h5md PRIVATE ${HDF5_INCLUDE_DIRS}) - include_directories(${HDF5_INCLUDE_DIRS}) endif() diff --git a/cmake/Modules/Packages/USER-INTEL.cmake b/cmake/Modules/Packages/USER-INTEL.cmake index 96a897297f..d81f793f50 100644 --- a/cmake/Modules/Packages/USER-INTEL.cmake +++ b/cmake/Modules/Packages/USER-INTEL.cmake @@ -109,5 +109,5 @@ if(PKG_USER-INTEL) endif() target_sources(lammps PRIVATE ${USER-INTEL_SOURCES}) - include_directories(${USER-INTEL_SOURCES_DIR}) + target_include_directories(lammps PRIVATE ${USER-INTEL_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/USER-OMP.cmake b/cmake/Modules/Packages/USER-OMP.cmake index 91f0467a17..42f91495d5 100644 --- a/cmake/Modules/Packages/USER-OMP.cmake +++ b/cmake/Modules/Packages/USER-OMP.cmake @@ -38,5 +38,5 @@ if(PKG_USER-OMP) endif() target_sources(lammps PRIVATE ${USER-OMP_SOURCES}) - include_directories(${USER-OMP_SOURCES_DIR}) + target_include_directories(lammps PRIVATE ${USER-OMP_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/USER-PLUMED.cmake b/cmake/Modules/Packages/USER-PLUMED.cmake index cfd187ed9d..75b2db2f93 100644 --- a/cmake/Modules/Packages/USER-PLUMED.cmake +++ b/cmake/Modules/Packages/USER-PLUMED.cmake @@ -92,5 +92,5 @@ if(PKG_USER-PLUMED) endif() target_link_libraries(lammps PRIVATE ${PLUMED_LOAD}) endif() - include_directories(${PLUMED_INCLUDE_DIRS}) + target_include_directories(lammps PRIVATE ${PLUMED_INCLUDE_DIRS}) endif() diff --git a/cmake/Modules/Packages/USER-SDPD.cmake b/cmake/Modules/Packages/USER-SDPD.cmake index 1105fbd7ce..750194bcc6 100644 --- a/cmake/Modules/Packages/USER-SDPD.cmake +++ b/cmake/Modules/Packages/USER-SDPD.cmake @@ -11,5 +11,5 @@ if(PKG_USER-SDPD) endif() set_property(GLOBAL PROPERTY FIX "${hlist}") - include_directories(${USER-SDPD_SOURCES_DIR}) + target_include_directories(lammps PRIVATE ${USER-SDPD_SOURCES_DIR}) endif() -- GitLab From d8b6d10f3b9d65f99232980510011ace2db068a6 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 11:42:36 -0600 Subject: [PATCH 394/689] MSCG.cmake: create an use imported target --- cmake/Modules/FindMSCG.cmake | 16 +++++++++++++--- cmake/Modules/Packages/MSCG.cmake | 12 ++++++++---- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/cmake/Modules/FindMSCG.cmake b/cmake/Modules/FindMSCG.cmake index 311ff78038..b301303dbe 100644 --- a/cmake/Modules/FindMSCG.cmake +++ b/cmake/Modules/FindMSCG.cmake @@ -10,13 +10,23 @@ find_path(MSCG_INCLUDE_DIR mscg.h PATH_SUFFIXES mscg) find_library(MSCG_LIBRARY NAMES mscg) -set(MSCG_LIBRARIES ${MSCG_LIBRARY}) -set(MSCG_INCLUDE_DIRS ${MSCG_INCLUDE_DIR}) - include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set MSCG_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(MSCG DEFAULT_MSG MSCG_LIBRARY MSCG_INCLUDE_DIR) +# Copy the results to the output variables and target. +if(MSCG_FOUND) + set(MSCG_LIBRARIES ${MSCG_LIBRARY}) + set(MSCG_INCLUDE_DIRS ${MSCG_INCLUDE_DIR}) + + if(NOT TARGET MSCG::MSCG) + add_library(MSCG::MSCG UNKNOWN IMPORTED) + set_target_properties(MSCG::MSCG PROPERTIES + IMPORTED_LOCATION "${MSCG_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${MSCG_INCLUDE_DIR}") + endif() +endif() + mark_as_advanced(MSCG_INCLUDE_DIR MSCG_LIBRARY ) diff --git a/cmake/Modules/Packages/MSCG.cmake b/cmake/Modules/Packages/MSCG.cmake index 2c63e69fa7..750a1a8c37 100644 --- a/cmake/Modules/Packages/MSCG.cmake +++ b/cmake/Modules/Packages/MSCG.cmake @@ -29,12 +29,17 @@ if(PKG_MSCG) BUILD_BYPRODUCTS /libmscg.a ) ExternalProject_get_property(mscg_build BINARY_DIR) - set(MSCG_LIBRARIES ${BINARY_DIR}/libmscg.a) ExternalProject_get_property(mscg_build SOURCE_DIR) set(MSCG_INCLUDE_DIRS ${SOURCE_DIR}/src) + if(NOT TARGET MSCG::MSCG) + add_library(MSCG::MSCG UNKNOWN IMPORTED) + set_target_properties(MSCG::MSCG PROPERTIES + IMPORTED_LOCATION "${BINARY_DIR}/libmscg.a" + INTERFACE_INCLUDE_DIRECTORIES "${MSCG_INCLUDE_DIRS}") + endif() add_dependencies(lammps mscg_build) if(NOT LAPACK_FOUND) - file(MAKE_DIRECTORY ${MSCG_INCLUDE_DIRS}) + file(MAKE_DIRECTORY ) add_dependencies(mscg_build linalg) endif() else() @@ -43,6 +48,5 @@ if(PKG_MSCG) message(FATAL_ERROR "MSCG not found, help CMake to find it by setting MSCG_LIBRARY and MSCG_INCLUDE_DIRS, or set DOWNLOAD_MSCG=ON to download it") endif() endif() - target_link_libraries(lammps PRIVATE ${MSCG_LIBRARIES} GSL::gsl ${LAPACK_LIBRARIES}) - include_directories(${MSCG_INCLUDE_DIRS}) + target_link_libraries(lammps PRIVATE MSCG::MSCG GSL::gsl ${LAPACK_LIBRARIES}) endif() -- GitLab From 72c94f0fbf7c70c18fb44820247fe2b83667efb6 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 11:49:24 -0600 Subject: [PATCH 395/689] USER-SCAFACOS.cmake: use imported pkg-config target --- cmake/Modules/Packages/USER-SCAFACOS.cmake | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cmake/Modules/Packages/USER-SCAFACOS.cmake b/cmake/Modules/Packages/USER-SCAFACOS.cmake index ebd750c04b..6725472c07 100644 --- a/cmake/Modules/Packages/USER-SCAFACOS.cmake +++ b/cmake/Modules/Packages/USER-SCAFACOS.cmake @@ -46,7 +46,7 @@ if(PKG_USER-SCAFACOS) ) ExternalProject_get_property(scafacos_build INSTALL_DIR) set(SCAFACOS_BUILD_DIR ${INSTALL_DIR}) - set(SCAFACOS_INCLUDE_DIRS ${SCAFACOS_BUILD_DIR}/include) + target_include_directories(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/include) add_dependencies(lammps scafacos_build) # list and order from pkg_config file of ScaFaCoS build target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs.a) @@ -69,8 +69,7 @@ if(PKG_USER-SCAFACOS) target_link_libraries(lammps PRIVATE ${MPI_C_LIBRARIES}) else() find_package(PkgConfig REQUIRED) - pkg_check_modules(SCAFACOS REQUIRED scafacos) - target_link_libraries(lammps PRIVATE ${SCAFACOS_LDFLAGS}) + pkg_check_modules(SCAFACOS REQUIRED IMPORTED_TARGET scafacos) + target_link_libraries(lammps PRIVATE PkgConfig::SCAFACOS) endif() - include_directories(${SCAFACOS_INCLUDE_DIRS}) endif() -- GitLab From d19f112c754e8345813e23d1743bca837c87d27b Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 12:18:10 -0600 Subject: [PATCH 396/689] MSCG.cmake: fix up imported target --- cmake/Modules/Packages/MSCG.cmake | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/cmake/Modules/Packages/MSCG.cmake b/cmake/Modules/Packages/MSCG.cmake index 750a1a8c37..f4bac7d422 100644 --- a/cmake/Modules/Packages/MSCG.cmake +++ b/cmake/Modules/Packages/MSCG.cmake @@ -31,15 +31,11 @@ if(PKG_MSCG) ExternalProject_get_property(mscg_build BINARY_DIR) ExternalProject_get_property(mscg_build SOURCE_DIR) set(MSCG_INCLUDE_DIRS ${SOURCE_DIR}/src) - if(NOT TARGET MSCG::MSCG) - add_library(MSCG::MSCG UNKNOWN IMPORTED) - set_target_properties(MSCG::MSCG PROPERTIES - IMPORTED_LOCATION "${BINARY_DIR}/libmscg.a" - INTERFACE_INCLUDE_DIRECTORIES "${MSCG_INCLUDE_DIRS}") - endif() + target_include_directories(lammps PRIVATE ${MSCG_INCLUDE_DIRS}) + target_link_libraries(lammps PRIVATE "${BINARY_DIR}/libmscg.a") add_dependencies(lammps mscg_build) if(NOT LAPACK_FOUND) - file(MAKE_DIRECTORY ) + file(MAKE_DIRECTORY ${MSCG_INCLUDE_DIRS}) add_dependencies(mscg_build linalg) endif() else() @@ -47,6 +43,7 @@ if(PKG_MSCG) if(NOT MSCG_FOUND) message(FATAL_ERROR "MSCG not found, help CMake to find it by setting MSCG_LIBRARY and MSCG_INCLUDE_DIRS, or set DOWNLOAD_MSCG=ON to download it") endif() + target_link_libraries(lammps PRIVATE MSCG::MSCG) endif() - target_link_libraries(lammps PRIVATE MSCG::MSCG GSL::gsl ${LAPACK_LIBRARIES}) + target_link_libraries(lammps PRIVATE GSL::gsl ${LAPACK_LIBRARIES}) endif() -- GitLab From f5279a291e93195054e4099ef0fec0ccb5f61093 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 12:23:39 -0600 Subject: [PATCH 397/689] USER-QUIP.cmake: create and use imported target --- cmake/Modules/FindQUIP.cmake | 13 +++++++++++-- cmake/Modules/Packages/USER-QUIP.cmake | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/cmake/Modules/FindQUIP.cmake b/cmake/Modules/FindQUIP.cmake index b6d87d11fa..277cfae49e 100644 --- a/cmake/Modules/FindQUIP.cmake +++ b/cmake/Modules/FindQUIP.cmake @@ -7,12 +7,21 @@ find_library(QUIP_LIBRARY NAMES quip) -set(QUIP_LIBRARIES ${QUIP_LIBRARY}) - include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set QUIP_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(QUIP DEFAULT_MSG QUIP_LIBRARY) +# Copy the results to the output variables and target. +if(QUIP_FOUND) + set(QUIP_LIBRARIES ${QUIP_LIBRARY}) + + if(NOT TARGET QUIP::QUIP) + add_library(QUIP::QUIP UNKNOWN IMPORTED) + set_target_properties(QUIP::QUIP PROPERTIES + IMPORTED_LOCATION "${QUIP_LIBRARY}") + endif() +endif() + mark_as_advanced(QUIP_LIBRARY) diff --git a/cmake/Modules/Packages/USER-QUIP.cmake b/cmake/Modules/Packages/USER-QUIP.cmake index 52ba7e9c47..4f41f9ef98 100644 --- a/cmake/Modules/Packages/USER-QUIP.cmake +++ b/cmake/Modules/Packages/USER-QUIP.cmake @@ -1,5 +1,5 @@ if(PKG_USER-QUIP) enable_language(Fortran) find_package(QUIP REQUIRED) - target_link_libraries(lammps PRIVATE ${LAPACK_LIBRARIES}) + target_link_libraries(lammps PRIVATE QUIP::QUIP ${LAPACK_LIBRARIES}) endif() -- GitLab From 99d4a226b5d0f74927b118dbd1bb4b90edaa7606 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 12:33:36 -0600 Subject: [PATCH 398/689] USER-NETCDF.cmake: create and use imported targets --- cmake/Modules/FindNetCDF.cmake | 16 ++++++++++++++-- cmake/Modules/FindPNetCDF.cmake | 9 +++++++++ cmake/Modules/Packages/USER-NETCDF.cmake | 6 ++---- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/cmake/Modules/FindNetCDF.cmake b/cmake/Modules/FindNetCDF.cmake index 2a992b6b3b..7f0ee93520 100644 --- a/cmake/Modules/FindNetCDF.cmake +++ b/cmake/Modules/FindNetCDF.cmake @@ -112,11 +112,23 @@ NetCDF_check_interface (F90 netcdf.mod netcdff) #export accumulated results to internal varS that rest of project can depend on list (APPEND NetCDF_libs "${NETCDF_C_LIBRARIES}") -set (NETCDF_LIBRARIES ${NetCDF_libs}) -set (NETCDF_INCLUDE_DIRS ${NetCDF_includes}) # handle the QUIETLY and REQUIRED arguments and set NETCDF_FOUND to TRUE if # all listed variables are TRUE include (FindPackageHandleStandardArgs) find_package_handle_standard_args (NetCDF DEFAULT_MSG NETCDF_LIBRARIES NETCDF_INCLUDE_DIRS NETCDF_HAS_INTERFACES) + +# Copy the results to the output variables and target. +if(NetCDF_FOUND) + set (NETCDF_LIBRARIES ${NetCDF_libs}) + set (NETCDF_INCLUDE_DIRS ${NetCDF_includes}) + + if(NOT TARGET NetCDF::NetCDF) + add_library(NetCDF::NetCDF UNKNOWN IMPORTED) + set_target_properties(NetCDF::NetCDF PROPERTIES + IMPORTED_LOCATION "${NETCDF_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${NetCDF_includes}" + INTERFACE_LINK_LIBRARIES "${NETCDF_LIBRARIES}") + endif() +endif() diff --git a/cmake/Modules/FindPNetCDF.cmake b/cmake/Modules/FindPNetCDF.cmake index bc3a5f9538..e501e9af49 100644 --- a/cmake/Modules/FindPNetCDF.cmake +++ b/cmake/Modules/FindPNetCDF.cmake @@ -53,3 +53,12 @@ include (FindPackageHandleStandardArgs) find_package_handle_standard_args (PNetCDF DEFAULT_MSG PNETCDF_LIBRARIES PNETCDF_INCLUDES) mark_as_advanced (PNETCDF_LIBRARIES PNETCDF_INCLUDES) + +if(PNetCDF_FOUND) + if(NOT TARGET PNetCDF::PNetCDF) + add_library(PNetCDF::PNetCDF UNKNOWN IMPORTED) + set_target_properties(PNetCDF::PNetCDF PROPERTIES + IMPORTED_LOCATION "${PNETCDF_LIBRARIES}" + INTERFACE_INCLUDE_DIRECTORIES "${PNETCDF_INCLUDES}") + endif() +endif() diff --git a/cmake/Modules/Packages/USER-NETCDF.cmake b/cmake/Modules/Packages/USER-NETCDF.cmake index 2c12d2b799..a149c7357d 100644 --- a/cmake/Modules/Packages/USER-NETCDF.cmake +++ b/cmake/Modules/Packages/USER-NETCDF.cmake @@ -9,14 +9,12 @@ if(PKG_USER-NETCDF) endif(NETCDF_FOUND) if(NETCDF_FOUND) - include_directories(${NETCDF_INCLUDE_DIRS}) - target_link_libraries(lammps PRIVATE ${NETCDF_LIBRARIES}) + target_link_libraries(lammps PRIVATE NetCDF::NetCDF) target_compile_definitions(lammps PRIVATE -DLMP_HAS_NETCDF) endif(NETCDF_FOUND) if(PNETCDF_FOUND) - include_directories(${PNETCDF_INCLUDES}) - target_link_libraries(lammps PRIVATE ${PNETCDF_LIBRARIES}) + target_link_libraries(lammps PRIVATE PNetCDF::PNetCDF) target_compile_definitions(lammps PRIVATE -DLMP_HAS_PNETCDF) endif(PNETCDF_FOUND) -- GitLab From 5eb77f2e9a2c3045f0b5c080ce7ef07a6eb903d2 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 14:29:14 -0600 Subject: [PATCH 399/689] FindNetCDF.cmake: fix target --- cmake/Modules/FindNetCDF.cmake | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cmake/Modules/FindNetCDF.cmake b/cmake/Modules/FindNetCDF.cmake index 7f0ee93520..5c8caa9208 100644 --- a/cmake/Modules/FindNetCDF.cmake +++ b/cmake/Modules/FindNetCDF.cmake @@ -112,6 +112,8 @@ NetCDF_check_interface (F90 netcdf.mod netcdff) #export accumulated results to internal varS that rest of project can depend on list (APPEND NetCDF_libs "${NETCDF_C_LIBRARIES}") +set (NETCDF_LIBRARIES ${NetCDF_libs}) +set (NETCDF_INCLUDE_DIRS ${NetCDF_includes}) # handle the QUIETLY and REQUIRED arguments and set NETCDF_FOUND to TRUE if # all listed variables are TRUE @@ -121,14 +123,11 @@ find_package_handle_standard_args (NetCDF # Copy the results to the output variables and target. if(NetCDF_FOUND) - set (NETCDF_LIBRARIES ${NetCDF_libs}) - set (NETCDF_INCLUDE_DIRS ${NetCDF_includes}) - if(NOT TARGET NetCDF::NetCDF) add_library(NetCDF::NetCDF UNKNOWN IMPORTED) set_target_properties(NetCDF::NetCDF PROPERTIES IMPORTED_LOCATION "${NETCDF_LIBRARY}" - INTERFACE_INCLUDE_DIRECTORIES "${NetCDF_includes}" + INTERFACE_INCLUDE_DIRECTORIES "${NETCDF_INCLUDE_DIRS}" INTERFACE_LINK_LIBRARIES "${NETCDF_LIBRARIES}") endif() endif() -- GitLab From 0da108f06fe2b7372a0ade40378b4368edbaa257 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 14:50:38 -0600 Subject: [PATCH 400/689] cmake: remove last include_directories() call --- cmake/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 0001f37fce..3569ffc555 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -188,7 +188,6 @@ if(BUILD_MPI) include(MPI4WIN) else() find_package(MPI REQUIRED) - include_directories(${MPI_CXX_INCLUDE_PATH}) target_compile_definitions(lammps PRIVATE -DMPICH_SKIP_MPICXX -DOMPI_SKIP_MPICXX=1) target_link_libraries(lammps PUBLIC MPI::MPI_CXX) option(LAMMPS_LONGLONG_TO_LONG "Workaround if your system or MPI version does not recognize 'long long' data types" OFF) -- GitLab From 0f35c1d009b70258c3c967e51abbd11e923c6f30 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Tue, 24 Mar 2020 18:43:20 -0400 Subject: [PATCH 401/689] Update ubuntu package name to libpng-dev --- doc/src/Howto_bash.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/Howto_bash.rst b/doc/src/Howto_bash.rst index 02322e5e1c..98cc6c0dff 100644 --- a/doc/src/Howto_bash.rst +++ b/doc/src/Howto_bash.rst @@ -103,7 +103,7 @@ needed for various LAMMPS features: .. code-block:: bash - sudo apt install -y build-essential ccache gfortran openmpi-bin libopenmpi-dev libfftw3-dev libjpeg-dev libpng12-dev python-dev python-virtualenv libblas-dev liblapack-dev libhdf5-serial-dev hdf5-tools + sudo apt install -y build-essential ccache gfortran openmpi-bin libopenmpi-dev libfftw3-dev libjpeg-dev libpng-dev python-dev python-virtualenv libblas-dev liblapack-dev libhdf5-serial-dev hdf5-tools Files in Ubuntu on Windows ^^^^^^^^^^^^^^^^^^^^^^^^^^ -- GitLab From 431647d943d64001e2e2d6a6e01294c2903c42d7 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Tue, 24 Mar 2020 18:52:05 -0400 Subject: [PATCH 402/689] Add link to official WSL docs --- doc/src/Howto_bash.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/src/Howto_bash.rst b/doc/src/Howto_bash.rst index 98cc6c0dff..b452f579d0 100644 --- a/doc/src/Howto_bash.rst +++ b/doc/src/Howto_bash.rst @@ -12,6 +12,10 @@ via apt-get and all files are accessible in both the Windows Explorer and your Linux shell (bash). This avoids switching to a different operating system or installing a virtual machine. Everything runs on Windows. +.. seealso:: + + You can find more detailed information at the `Windows Subsystem for Linux Installation Guide for Windows 10 `_. + Installing Bash on Windows -------------------------- -- GitLab From 398c030925e8175f6e15177f2d9b3194fca9524a Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 25 Mar 2020 06:52:37 -0400 Subject: [PATCH 403/689] whitespace cleanup --- src/KOKKOS/sna_kokkos_impl.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/KOKKOS/sna_kokkos_impl.h b/src/KOKKOS/sna_kokkos_impl.h index e6c34a245b..dcedf333e5 100644 --- a/src/KOKKOS/sna_kokkos_impl.h +++ b/src/KOKKOS/sna_kokkos_impl.h @@ -382,7 +382,7 @@ void SNAKokkos::compute_ui(const typename Kokkos::TeamPolicy 0)?rootpq2*buf1[jjup_shared_idx-1]:SNAcomplex(0.,0.); //const SNAcomplex u_up2 = (ma > 0)?rootpq2*ulist(jjup_index-1,iatom,jnbor):SNAcomplex(0.,0.); caconjxpy(b, u_up2, u_accum); - + // VMK recursion relation: grab contribution which is multiplied by a* const double rootpq1 = rootpqarray(j - ma, j - mb); const SNAcomplex u_up1 = (ma < j)?rootpq1*buf1[jjup_shared_idx]:SNAcomplex(0.,0.); @@ -399,12 +399,12 @@ void SNAKokkos::compute_ui(const typename Kokkos::TeamPolicy physical j integer), last element maps to self, skip - //if (!(m == total_iters - 1 && j % 2 == 0)) { + //if (!(m == total_iters - 1 && j % 2 == 0)) { if (m < total_iters - 1 || j % 2 == 1) { const int sign_factor = (((ma+mb)%2==0)?1:-1); const int jju_shared_flip = (j+1-mb)*(j+1)-(ma+1); const int jjup_flip = jju + jju_shared_flip; // jju+(j+1-mb)*(j+1)-(ma+1); - + if (sign_factor == 1) { u_accum.im = -u_accum.im; @@ -419,12 +419,12 @@ void SNAKokkos::compute_ui(const typename Kokkos::TeamPolicy::compute_fused_deidrj(const typename Kokkos::TeamPoli // copy left side to right side with inversion symmetry VMK 4.4(2) // u[ma-j][mb-j] = (-1)^(ma-mb)*Conj([u[ma][mb]) if (j%2==1 && mb+1==n_mb) { - int sign_factor = (((ma+mb)%2==0)?1:-1); + int sign_factor = (((ma+mb)%2==0)?1:-1); //const int jjup_flip = jju+(j+1-mb)*(j+1)-(ma+1); // no longer needed b/c we don't update dulist const int jju_shared_flip = (j+1-mb)*(j+1)-(ma+1); @@ -787,18 +787,18 @@ void SNAKokkos::compute_fused_deidrj(const typename Kokkos::TeamPoli auto tmp = ulist_buf1; ulist_buf1 = ulist_buf2; ulist_buf2 = tmp; tmp = dulist_buf1; dulist_buf1 = dulist_buf2; dulist_buf2 = tmp; - // Accumulate dedr. This "should" be in a single, but + // Accumulate dedr. This "should" be in a single, but // a Kokkos::single call implies a warp sync, and we may // as well avoid that. This does no harm as long as the // final assignment is in a single block. //Kokkos::single(Kokkos::PerThread(team), [=]() { - dedr_full_sum += dedr_sum; + dedr_full_sum += dedr_sum; //}); } // Store the accumulated dedr. Kokkos::single(Kokkos::PerThread(team), [&] () { - dedr(iatom,jnbor,dir) = dedr_full_sum*2.0; + dedr(iatom,jnbor,dir) = dedr_full_sum*2.0; }); } -- GitLab From 1192845ad58327cee3c3e4608596baf8f848b1e7 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 25 Mar 2020 08:19:24 -0400 Subject: [PATCH 404/689] avoid segmentation faults in universe/uloop variable increment --- src/variable.cpp | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/variable.cpp b/src/variable.cpp index 1093ce9066..0fc53f8074 100644 --- a/src/variable.cpp +++ b/src/variable.cpp @@ -661,6 +661,8 @@ int Variable::next(int narg, char **arg) } else if (istyle == UNIVERSE || istyle == ULOOP) { + uloop_again: + // wait until lock file can be created and owned by proc 0 of this world // rename() is not atomic in practice, but no known simple fix // means multiple procs can read/write file at the same time (bad!) @@ -669,7 +671,7 @@ int Variable::next(int narg, char **arg) // delay for random fraction of 1 second before subsequent tries // when successful, read next available index and Bcast it within my world - int nextindex; + int nextindex = -1; if (me == 0) { int seed = 12345 + universe->me + which[find(arg[0])]; RanMars *random = new RanMars(lmp,seed); @@ -682,10 +684,33 @@ int Variable::next(int narg, char **arg) } delete random; - FILE *fp = fopen("tmp.lammps.variable.lock","r"); - fscanf(fp,"%d",&nextindex); + // if the file cannot be found, we may have a race with some + // other MPI rank that has called rename at the same time + // and we have to start over. + // if the read is short (we need at least one byte) we try reading again. + + FILE *fp; + char buf[64]; + for (int loopmax = 0; loopmax < 100; ++loopmax) { + fp = fopen("tmp.lammps.variable.lock","r"); + if (fp == NULL) goto uloop_again; + + buf[0] = buf[1] = '\0'; + fread(buf,1,64,fp); + fclose(fp); + + if (strlen(buf) > 0) { + nextindex = atoi(buf); + break; + } + delay = (int) (1000000*random->uniform()); + usleep(delay); + } + if (nextindex < 0) + error->one(FLERR,"Unexpected error while incrementing uloop " + "style variable. Please contact LAMMPS developers."); + //printf("READ %d %d\n",universe->me,nextindex); - fclose(fp); fp = fopen("tmp.lammps.variable.lock","w"); fprintf(fp,"%d\n",nextindex+1); //printf("WRITE %d %d\n",universe->me,nextindex+1); -- GitLab From b8464da71ffbe6c1697b2c2071924d75c2ea30d0 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Wed, 25 Mar 2020 07:45:21 -0600 Subject: [PATCH 405/689] cmake: remove FindLAMMPS.cmake --- cmake/CMakeLists.txt | 2 -- cmake/FindLAMMPS.cmake.in | 48 --------------------------------------- 2 files changed, 50 deletions(-) delete mode 100644 cmake/FindLAMMPS.cmake.in diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 3569ffc555..02d7b50f1b 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -584,8 +584,6 @@ if(BUILD_LIB) install(FILES ${LAMMPS_CXX_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/lammps) configure_file(pkgconfig/liblammps.pc.in ${CMAKE_CURRENT_BINARY_DIR}/liblammps${LAMMPS_LIB_SUFFIX}.pc @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/liblammps${LAMMPS_LIB_SUFFIX}.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) - configure_file(FindLAMMPS.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FindLAMMPS${LAMMPS_LIB_SUFFIX}.cmake @ONLY) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/FindLAMMPS${LAMMPS_LIB_SUFFIX}.cmake DESTINATION ${CMAKE_INSTALL_DATADIR}/cmake/Modules) endif() if(BUILD_EXE) diff --git a/cmake/FindLAMMPS.cmake.in b/cmake/FindLAMMPS.cmake.in deleted file mode 100644 index 586df83c2d..0000000000 --- a/cmake/FindLAMMPS.cmake.in +++ /dev/null @@ -1,48 +0,0 @@ -# - Find liblammps -# Find the native liblammps headers and libraries. -# -# The following variables will set: -# LAMMPS_INCLUDE_DIRS - where to find lammps/library.h, etc. -# LAMMPS_LIBRARIES - List of libraries when using lammps. -# LAMMPS_API_DEFINES - lammps library api defines -# LAMMPS_VERSION - lammps library version -# LAMMPS_FOUND - True if liblammps found. -# -# In addition a LAMMPS::LAMMPS imported target is getting created. -# -# LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator -# http://lammps.sandia.gov, Sandia National Laboratories -# Steve Plimpton, sjplimp@sandia.gov -# -# Copyright (2003) Sandia Corporation. Under the terms of Contract -# DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains -# certain rights in this software. This software is distributed under -# the GNU General Public License. -# -# See the README file in the top-level LAMMPS directory. -# - -find_package(PkgConfig) - -pkg_check_modules(PC_LAMMPS liblammps@LAMMPS_LIB_SUFFIX@) -find_path(LAMMPS_INCLUDE_DIR lammps/library.h HINTS ${PC_LAMMPS_INCLUDE_DIRS} @CMAKE_INSTALL_FULL_INCLUDEDIR@) - -set(LAMMPS_VERSION @LAMMPS_VERSION@) -set(LAMMPS_API_DEFINES @LAMMPS_API_DEFINES@) - -find_library(LAMMPS_LIBRARY NAMES lammps@LAMMPS_LIB_SUFFIX@ HINTS ${PC_LAMMPS_LIBRARY_DIRS} @CMAKE_INSTALL_FULL_LIBDIR@) - -set(LAMMPS_INCLUDE_DIRS "${LAMMPS_INCLUDE_DIR}") -set(LAMMPS_LIBRARIES "${LAMMPS_LIBRARY}") - -include(FindPackageHandleStandardArgs) -# handle the QUIETLY and REQUIRED arguments and set LAMMPS_FOUND to TRUE -# if all listed variables are TRUE -find_package_handle_standard_args(LAMMPS REQUIRED_VARS LAMMPS_LIBRARY LAMMPS_INCLUDE_DIR VERSION_VAR LAMMPS_VERSION) - -mark_as_advanced(LAMMPS_INCLUDE_DIR LAMMPS_LIBRARY) - -if(LAMMPS_FOUND AND NOT TARGET LAMMPS::LAMMPS) - add_library(LAMMPS::LAMMPS UNKNOWN IMPORTED) - set_target_properties(LAMMPS::LAMMPS PROPERTIES IMPORTED_LOCATION "${LAMMPS_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${LAMMPS_INCLUDE_DIR}" INTERFACE_COMPILE_DEFINITIONS "${LAMMPS_API_DEFINES}") -endif() -- GitLab From 0e9f65e0219b86d959ba66c948a6951c8003d80b Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Wed, 25 Mar 2020 08:43:57 -0600 Subject: [PATCH 406/689] cmake: add exported target --- cmake/CMakeLists.txt | 9 +++++++-- cmake/LAMMPSConfig.cmake.in | 5 +++++ cmake/pkgconfig/liblammps.pc.in | 8 +------- 3 files changed, 13 insertions(+), 9 deletions(-) create mode 100644 cmake/LAMMPSConfig.cmake.in diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 02d7b50f1b..97bb00e250 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -26,7 +26,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Modules) include(LAMMPSUtils) -get_lammps_version(${LAMMPS_SOURCE_DIR}/version.h LAMMPS_VERSION) +get_lammps_version(${LAMMPS_SOURCE_DIR}/version.h PROJECT_VERSION) include(PreventInSourceBuilds) @@ -579,11 +579,16 @@ if(BUILD_LIB) set_target_properties(lammps PROPERTIES OUTPUT_NAME lammps${LAMMPS_LIB_SUFFIX}) set_target_properties(lammps PROPERTIES SOVERSION ${SOVERSION}) - install(TARGETS lammps LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS lammps EXPORT LAMMPS_Targets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(FILES ${LAMMPS_SOURCE_DIR}/library.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/lammps) install(FILES ${LAMMPS_CXX_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/lammps) configure_file(pkgconfig/liblammps.pc.in ${CMAKE_CURRENT_BINARY_DIR}/liblammps${LAMMPS_LIB_SUFFIX}.pc @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/liblammps${LAMMPS_LIB_SUFFIX}.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + install(EXPORT LAMMPS_Targets FILE LAMMPS_Targets.cmake NAMESPACE LAMMPS:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/LAMMPS) + include(CMakePackageConfigHelpers) + configure_file(LAMMPSConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/LAMMPSConfig.cmake @ONLY) + write_basic_package_version_file("LAMMPSConfigVersion.cmake" VERSION ${PROJECT_VERSION} COMPATIBILITY ExactVersion) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/LAMMPSConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/LAMMPSConfigVersion.cmake" DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/LAMMPS) endif() if(BUILD_EXE) diff --git a/cmake/LAMMPSConfig.cmake.in b/cmake/LAMMPSConfig.cmake.in new file mode 100644 index 0000000000..0dacfc2089 --- /dev/null +++ b/cmake/LAMMPSConfig.cmake.in @@ -0,0 +1,5 @@ +include(CMakeFindDependencyMacro) +if(@BUILD_MPI@) + find_dependency(MPI REQUIRED CXX) +endif() +include("${CMAKE_CURRENT_LIST_DIR}/LAMMPS_Targets.cmake") diff --git a/cmake/pkgconfig/liblammps.pc.in b/cmake/pkgconfig/liblammps.pc.in index a89f992c4a..96dab89161 100644 --- a/cmake/pkgconfig/liblammps.pc.in +++ b/cmake/pkgconfig/liblammps.pc.in @@ -18,12 +18,6 @@ # myapp_CFLAGS = $(LAMMPS_CFLAGS) # myapp_LDADD = $(LAMMPS_LIBS) -# Use this in CMake: -# CMakeLists.txt: -# find_package(PkgConfig) -# pkg_check_modules(LAMMPS IMPORTED_TARGET lammps) -# target_link_libraries( PRIVATE PkgConfig::LAMMPS) - prefix=@CMAKE_INSTALL_PREFIX@ libdir=@CMAKE_INSTALL_FULL_LIBDIR@ includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ @@ -31,7 +25,7 @@ includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ Name: liblammps@LAMMPS_MACHINE@ Description: Large-scale Atomic/Molecular Massively Parallel Simulator Library URL: http://lammps.sandia.gov -Version: @LAMMPS_VERSION@ +Version: @PROJECT_VERSION@ Requires: Libs: -L${libdir} -llammps@LAMMPS_LIB_SUFFIX@ Libs.private: -lm -- GitLab From ee3249676e726d5173d8b1efdf1f63c6b72ea2e3 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Wed, 25 Mar 2020 09:09:59 -0600 Subject: [PATCH 407/689] cmake: use OpenMP imported target --- cmake/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 97bb00e250..befbe4ecda 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -255,8 +255,7 @@ if(BUILD_OMP) if(NOT HAVE_OMP_H_INCLUDE) message(FATAL_ERROR "Cannot find required 'omp.h' header file") endif() - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + target_link_libraries(lammps PRIVATE OpenMP::OpenMP_CXX) endif() if(PKG_MSCG OR PKG_USER-ATC OR PKG_USER-AWPMD OR PKG_USER-QUIP OR PKG_LATTE) -- GitLab From 58c9c4c64bc02d279b163cfb766ca6a4060f107d Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Wed, 25 Mar 2020 10:14:42 -0600 Subject: [PATCH 408/689] USER-H5MD.cmake: make hdf5 incldir public --- cmake/Modules/Packages/USER-H5MD.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Modules/Packages/USER-H5MD.cmake b/cmake/Modules/Packages/USER-H5MD.cmake index cf5623f46d..2893f7903c 100644 --- a/cmake/Modules/Packages/USER-H5MD.cmake +++ b/cmake/Modules/Packages/USER-H5MD.cmake @@ -3,5 +3,5 @@ if(PKG_USER-H5MD) find_package(HDF5 REQUIRED) target_link_libraries(h5md PRIVATE ${HDF5_LIBRARIES}) - target_include_directories(h5md PRIVATE ${HDF5_INCLUDE_DIRS}) + target_include_directories(h5md PUBLIC ${HDF5_INCLUDE_DIRS}) endif() -- GitLab From 2571b6058e82315fc7031b083b34fb05b9da06cc Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Wed, 25 Mar 2020 11:26:19 -0600 Subject: [PATCH 409/689] LATTE.cmake: create and use imported target --- cmake/Modules/FindLATTE.cmake | 13 +++++++++++-- cmake/Modules/Packages/LATTE.cmake | 10 +++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/cmake/Modules/FindLATTE.cmake b/cmake/Modules/FindLATTE.cmake index 74d5173bf0..ac5c639b79 100644 --- a/cmake/Modules/FindLATTE.cmake +++ b/cmake/Modules/FindLATTE.cmake @@ -7,12 +7,21 @@ find_library(LATTE_LIBRARY NAMES latte) -set(LATTE_LIBRARIES ${LATTE_LIBRARY}) - include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set LATTE_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(LATTE DEFAULT_MSG LATTE_LIBRARY) +# Copy the results to the output variables and target. +if(LATTE_FOUND) + set(LATTE_LIBRARIES ${LATTE_LIBRARY}) + + if(NOT TARGET LATTE::latte) + add_library(LATTE::latte UNKNOWN IMPORTED) + set_target_properties(LATTE::latte PROPERTIES + IMPORTED_LOCATION "${LATTE_LIBRARY}") + endif() +endif() + mark_as_advanced(LATTE_LIBRARY) diff --git a/cmake/Modules/Packages/LATTE.cmake b/cmake/Modules/Packages/LATTE.cmake index abadd1cd97..20944db1a9 100644 --- a/cmake/Modules/Packages/LATTE.cmake +++ b/cmake/Modules/Packages/LATTE.cmake @@ -26,15 +26,15 @@ if(PKG_LATTE) ) add_dependencies(lammps latte_build) ExternalProject_get_property(latte_build INSTALL_DIR) - set(LATTE_LIBRARIES ${INSTALL_DIR}/${_LATTE_LIBDIR}/liblatte.a) + target_link_libraries(lammps PRIVATE ${INSTALL_DIR}/${_LATTE_LIBDIR}/liblatte.a ${LAPACK_LIBRARIES}) + if(NOT LAPACK_FOUND) + add_dependencies(latte_build linalg) + endif() else() find_package(LATTE) if(NOT LATTE_FOUND) message(FATAL_ERROR "LATTE library not found, help CMake to find it by setting LATTE_LIBRARY, or set DOWNLOAD_LATTE=ON to download it") endif() + target_link_libraries(lammps PRIVATE LATTE::latte) endif() - if(NOT LAPACK_FOUND) - add_dependencies(latte_build linalg) - endif() - target_link_libraries(lammps PRIVATE ${LATTE_LIBRARIES} ${LAPACK_LIBRARIES}) endif() -- GitLab From 299f79c91932edbb870ae8f14df5f5f1610344ff Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Wed, 25 Mar 2020 13:55:31 -0600 Subject: [PATCH 410/689] Remove deprecated Kokkos code --- src/KOKKOS/comm_kokkos.cpp | 42 +++++++++++++++--------------- src/KOKKOS/fft3d_kokkos.cpp | 8 +++--- src/KOKKOS/gridcomm_kokkos.cpp | 8 +++--- src/KOKKOS/kokkos_type.h | 2 +- src/KOKKOS/pack_kokkos.h | 16 ++++++------ src/KOKKOS/pair_kokkos.h | 18 ++++++++----- src/KOKKOS/pair_snap_kokkos_impl.h | 7 +++-- src/KOKKOS/remap_kokkos.cpp | 4 +-- 8 files changed, 57 insertions(+), 48 deletions(-) diff --git a/src/KOKKOS/comm_kokkos.cpp b/src/KOKKOS/comm_kokkos.cpp index a1ece37efd..628b0b668a 100644 --- a/src/KOKKOS/comm_kokkos.cpp +++ b/src/KOKKOS/comm_kokkos.cpp @@ -205,7 +205,7 @@ void CommKokkos::forward_comm_device(int dummy) } n = avec->pack_comm_kokkos(sendnum[iswap],k_sendlist, iswap,k_buf_send,pbc_flag[iswap],pbc[iswap]); - DeviceType::fence(); + DeviceType().fence(); if (n) { MPI_Send(k_buf_send.view().data(), n,MPI_DOUBLE,sendproc[iswap],0,world); @@ -224,14 +224,14 @@ void CommKokkos::forward_comm_device(int dummy) } n = avec->pack_comm_vel_kokkos(sendnum[iswap],k_sendlist,iswap, k_buf_send,pbc_flag[iswap],pbc[iswap]); - DeviceType::fence(); + DeviceType().fence(); if (n) { MPI_Send(k_buf_send.view().data(),n, MPI_DOUBLE,sendproc[iswap],0,world); } if (size_forward_recv[iswap]) MPI_Wait(&request,MPI_STATUS_IGNORE); avec->unpack_comm_vel_kokkos(recvnum[iswap],firstrecv[iswap],k_buf_recv); - DeviceType::fence(); + DeviceType().fence(); } else { if (size_forward_recv[iswap]) MPI_Irecv(k_buf_recv.view().data(), @@ -239,26 +239,26 @@ void CommKokkos::forward_comm_device(int dummy) recvproc[iswap],0,world,&request); n = avec->pack_comm_kokkos(sendnum[iswap],k_sendlist,iswap, k_buf_send,pbc_flag[iswap],pbc[iswap]); - DeviceType::fence(); + DeviceType().fence(); if (n) MPI_Send(k_buf_send.view().data(),n, MPI_DOUBLE,sendproc[iswap],0,world); if (size_forward_recv[iswap]) MPI_Wait(&request,MPI_STATUS_IGNORE); avec->unpack_comm_kokkos(recvnum[iswap],firstrecv[iswap],k_buf_recv); - DeviceType::fence(); + DeviceType().fence(); } } else { if (!ghost_velocity) { if (sendnum[iswap]) n = avec->pack_comm_self(sendnum[iswap],k_sendlist,iswap, firstrecv[iswap],pbc_flag[iswap],pbc[iswap]); - DeviceType::fence(); + DeviceType().fence(); } else { n = avec->pack_comm_vel_kokkos(sendnum[iswap],k_sendlist,iswap, k_buf_send,pbc_flag[iswap],pbc[iswap]); - DeviceType::fence(); + DeviceType().fence(); avec->unpack_comm_vel_kokkos(recvnum[iswap],firstrecv[iswap],k_buf_send); - DeviceType::fence(); + DeviceType().fence(); } } } @@ -334,7 +334,7 @@ void CommKokkos::reverse_comm_device() size_reverse_recv[iswap],MPI_DOUBLE, sendproc[iswap],0,world,&request); n = avec->pack_reverse_kokkos(recvnum[iswap],firstrecv[iswap],k_buf_send); - DeviceType::fence(); + DeviceType().fence(); if (n) MPI_Send(k_buf_send.view().data(),n, MPI_DOUBLE,recvproc[iswap],0,world); @@ -342,7 +342,7 @@ void CommKokkos::reverse_comm_device() } avec->unpack_reverse_kokkos(sendnum[iswap],k_sendlist,iswap, k_buf_recv); - DeviceType::fence(); + DeviceType().fence(); } else { if (sendnum[iswap]) n = avec->unpack_reverse_self(sendnum[iswap],k_sendlist,iswap, @@ -410,7 +410,7 @@ void CommKokkos::forward_comm_pair_device(Pair *pair) n = pairKKBase->pack_forward_comm_kokkos(sendnum[iswap],k_sendlist, iswap,k_buf_send_pair,pbc_flag[iswap],pbc[iswap]); - DeviceType::fence(); + DeviceType().fence(); // exchange with another proc // if self, set recv buffer to send buffer @@ -445,7 +445,7 @@ void CommKokkos::forward_comm_pair_device(Pair *pair) // unpack buffer pairKKBase->unpack_forward_comm_kokkos(recvnum[iswap],firstrecv[iswap],k_buf_recv_pair); - DeviceType::fence(); + DeviceType().fence(); } } @@ -647,7 +647,7 @@ void CommKokkos::exchange_device() k_exchange_sendlist,k_exchange_copylist, ExecutionSpaceFromDevice::space, dim,lo,hi); - DeviceType::fence(); + DeviceType().fence(); } else { while (i < nlocal) { if (x[i][dim] < lo || x[i][dim] >= hi) { @@ -671,7 +671,7 @@ void CommKokkos::exchange_device() atom->nlocal=avec-> unpack_exchange_kokkos(k_buf_send,nrecv,atom->nlocal,dim,lo,hi, ExecutionSpaceFromDevice::space); - DeviceType::fence(); + DeviceType().fence(); } } else { MPI_Sendrecv(&nsend,1,MPI_INT,procneigh[dim][0],0, @@ -704,7 +704,7 @@ void CommKokkos::exchange_device() atom->nlocal = avec-> unpack_exchange_kokkos(k_buf_recv,nrecv,atom->nlocal,dim,lo,hi, ExecutionSpaceFromDevice::space); - DeviceType::fence(); + DeviceType().fence(); } } @@ -964,13 +964,13 @@ void CommKokkos::borders_device() { n = avec-> pack_border_vel_kokkos(nsend,k_sendlist,k_buf_send,iswap, pbc_flag[iswap],pbc[iswap],exec_space); - DeviceType::fence(); + DeviceType().fence(); } else { n = avec-> pack_border_kokkos(nsend,k_sendlist,k_buf_send,iswap, pbc_flag[iswap],pbc[iswap],exec_space); - DeviceType::fence(); + DeviceType().fence(); } // swap atoms with other proc @@ -1000,21 +1000,21 @@ void CommKokkos::borders_device() { if (sendproc[iswap] != me) { avec->unpack_border_vel_kokkos(nrecv,atom->nlocal+atom->nghost, k_buf_recv,exec_space); - DeviceType::fence(); + DeviceType().fence(); } else { avec->unpack_border_vel_kokkos(nrecv,atom->nlocal+atom->nghost, k_buf_send,exec_space); - DeviceType::fence(); + DeviceType().fence(); } } else { if (sendproc[iswap] != me) { avec->unpack_border_kokkos(nrecv,atom->nlocal+atom->nghost, k_buf_recv,exec_space); - DeviceType::fence(); + DeviceType().fence(); } else { avec->unpack_border_kokkos(nrecv,atom->nlocal+atom->nghost, k_buf_send,exec_space); - DeviceType::fence(); + DeviceType().fence(); } } // set all pointers & counters diff --git a/src/KOKKOS/fft3d_kokkos.cpp b/src/KOKKOS/fft3d_kokkos.cpp index 26e6e93ad9..bedd15df93 100644 --- a/src/KOKKOS/fft3d_kokkos.cpp +++ b/src/KOKKOS/fft3d_kokkos.cpp @@ -230,7 +230,7 @@ void FFT3dKokkos::fft_3d_kokkos(typename FFT_AT::t_FFT_DATA_1d d_in, cufftExec(plan->plan_fast,d_data.data(),d_data.data(),flag); #else typename FFT_AT::t_FFT_DATA_1d d_tmp = - typename FFT_AT::t_FFT_DATA_1d(Kokkos::view_alloc("fft_3d:tmp",Kokkos::WithoutInitializing),d_in.dimension_0()); + typename FFT_AT::t_FFT_DATA_1d(Kokkos::view_alloc("fft_3d:tmp",Kokkos::WithoutInitializing),d_in.extent(0)); kiss_fft_functor f; if (flag == -1) f = kiss_fft_functor(d_data,d_tmp,plan->cfg_fast_forward,length); @@ -238,7 +238,7 @@ void FFT3dKokkos::fft_3d_kokkos(typename FFT_AT::t_FFT_DATA_1d d_in, f = kiss_fft_functor(d_data,d_tmp,plan->cfg_fast_backward,length); Kokkos::parallel_for(total/length,f); d_data = d_tmp; - d_tmp = typename FFT_AT::t_FFT_DATA_1d(Kokkos::view_alloc("fft_3d:tmp",Kokkos::WithoutInitializing),d_in.dimension_0()); + d_tmp = typename FFT_AT::t_FFT_DATA_1d(Kokkos::view_alloc("fft_3d:tmp",Kokkos::WithoutInitializing),d_in.extent(0)); #endif @@ -281,7 +281,7 @@ void FFT3dKokkos::fft_3d_kokkos(typename FFT_AT::t_FFT_DATA_1d d_in, f = kiss_fft_functor(d_data,d_tmp,plan->cfg_mid_backward,length); Kokkos::parallel_for(total/length,f); d_data = d_tmp; - d_tmp = typename FFT_AT::t_FFT_DATA_1d(Kokkos::view_alloc("fft_3d:tmp",Kokkos::WithoutInitializing),d_in.dimension_0()); + d_tmp = typename FFT_AT::t_FFT_DATA_1d(Kokkos::view_alloc("fft_3d:tmp",Kokkos::WithoutInitializing),d_in.extent(0)); #endif // 2nd mid-remap to prepare for 3rd FFTs @@ -864,7 +864,7 @@ void FFT3dKokkos::fft_3d_1d_only_kokkos(typename FFT_AT::t_FFT_DATA_ cufftExec(plan->plan_slow,d_data.data(),d_data.data(),flag); #else kiss_fft_functor f; - typename FFT_AT::t_FFT_DATA_1d d_tmp = typename FFT_AT::t_FFT_DATA_1d("fft_3d:tmp",d_data.dimension_0()); + typename FFT_AT::t_FFT_DATA_1d d_tmp = typename FFT_AT::t_FFT_DATA_1d("fft_3d:tmp",d_data.extent(0)); if (flag == -1) { f = kiss_fft_functor(d_data,d_tmp,plan->cfg_fast_forward,length1); Kokkos::parallel_for(total1/length1,f); diff --git a/src/KOKKOS/gridcomm_kokkos.cpp b/src/KOKKOS/gridcomm_kokkos.cpp index f1ccffe20d..bdf816b647 100644 --- a/src/KOKKOS/gridcomm_kokkos.cpp +++ b/src/KOKKOS/gridcomm_kokkos.cpp @@ -524,7 +524,7 @@ void GridCommKokkos::forward_comm(KSpace *kspace, int which) kspaceKKBase->pack_forward_kspace_kokkos(which,k_buf2,swap[m].npack,k_packlist,m); else kspaceKKBase->pack_forward_kspace_kokkos(which,k_buf1,swap[m].npack,k_packlist,m); - DeviceType::fence(); + DeviceType().fence(); if (swap[m].sendproc != me) { FFT_SCALAR* buf1; @@ -552,7 +552,7 @@ void GridCommKokkos::forward_comm(KSpace *kspace, int which) } kspaceKKBase->unpack_forward_kspace_kokkos(which,k_buf2,swap[m].nunpack,k_unpacklist,m); - DeviceType::fence(); + DeviceType().fence(); } } @@ -574,7 +574,7 @@ void GridCommKokkos::reverse_comm(KSpace *kspace, int which) kspaceKKBase->pack_reverse_kspace_kokkos(which,k_buf2,swap[m].nunpack,k_unpacklist,m); else kspaceKKBase->pack_reverse_kspace_kokkos(which,k_buf1,swap[m].nunpack,k_unpacklist,m); - DeviceType::fence(); + DeviceType().fence(); if (swap[m].recvproc != me) { FFT_SCALAR* buf1; @@ -602,7 +602,7 @@ void GridCommKokkos::reverse_comm(KSpace *kspace, int which) } kspaceKKBase->unpack_reverse_kspace_kokkos(which,k_buf2,swap[m].npack,k_packlist,m); - DeviceType::fence(); + DeviceType().fence(); } } diff --git a/src/KOKKOS/kokkos_type.h b/src/KOKKOS/kokkos_type.h index d21b9eecd2..2e68cc0405 100644 --- a/src/KOKKOS/kokkos_type.h +++ b/src/KOKKOS/kokkos_type.h @@ -1012,7 +1012,7 @@ void memset_kokkos (ViewType &view) { #else Kokkos::parallel_for(view.span()*sizeof(typename ViewType::value_type)/4, f); #endif - ViewType::execution_space::fence(); + ViewType::execution_space().fence(); } struct params_lj_coul { diff --git a/src/KOKKOS/pack_kokkos.h b/src/KOKKOS/pack_kokkos.h index 62e7960999..400048b1f0 100644 --- a/src/KOKKOS/pack_kokkos.h +++ b/src/KOKKOS/pack_kokkos.h @@ -86,7 +86,7 @@ static void pack_3d(typename FFT_AT::t_FFT_SCALAR_1d_um d_data, int data_offset, const int nfast = plan->nfast; pack_3d_functor f(d_buf,buf_offset,d_data,data_offset,plan); Kokkos::parallel_for(nslow*nmid*nfast,f); - DeviceType::fence(); + DeviceType().fence(); } /* ---------------------------------------------------------------------- @@ -140,7 +140,7 @@ static void unpack_3d(typename FFT_AT::t_FFT_SCALAR_1d_um d_buf, int buf_offset, const int nfast = plan->nfast; unpack_3d_functor f(d_buf,buf_offset,d_data,data_offset,plan); Kokkos::parallel_for(nslow*nmid*nfast,f); - DeviceType::fence(); + DeviceType().fence(); } /* ---------------------------------------------------------------------- @@ -195,7 +195,7 @@ static void unpack_3d_permute1_1(typename FFT_AT::t_FFT_SCALAR_1d_um d_buf, int const int nfast = plan->nfast; unpack_3d_permute1_1_functor f(d_buf,buf_offset,d_data,data_offset,plan); Kokkos::parallel_for(nslow*nmid*nfast,f); - DeviceType::fence(); + DeviceType().fence(); } /* ---------------------------------------------------------------------- unpack from buf -> data, one axis permutation, 2 values/element @@ -249,7 +249,7 @@ static void unpack_3d_permute1_2(typename FFT_AT::t_FFT_SCALAR_1d_um d_buf, int const int nfast = plan->nfast; unpack_3d_permute1_2_functor f(d_buf,buf_offset,d_data,data_offset,plan); Kokkos::parallel_for(nslow*nmid*nfast,f); - DeviceType::fence(); + DeviceType().fence(); } /* ---------------------------------------------------------------------- @@ -305,7 +305,7 @@ static void unpack_3d_permute1_n(typename FFT_AT::t_FFT_SCALAR_1d_um d_buf, int const int nfast = plan->nfast; unpack_3d_permute1_n_functor f(d_buf,buf_offset,d_data,data_offset,plan); Kokkos::parallel_for(nslow*nmid*nfast,f); - DeviceType::fence(); + DeviceType().fence(); } /* ---------------------------------------------------------------------- @@ -358,7 +358,7 @@ static void unpack_3d_permute2_1(typename FFT_AT::t_FFT_SCALAR_1d_um d_buf, int const int nfast = plan->nfast; unpack_3d_permute2_1_functor f(d_buf,buf_offset,d_data,data_offset,plan); Kokkos::parallel_for(nslow*nmid*nfast,f); - DeviceType::fence(); + DeviceType().fence(); } /* ---------------------------------------------------------------------- @@ -412,7 +412,7 @@ static void unpack_3d_permute2_2(typename FFT_AT::t_FFT_SCALAR_1d_um d_buf, int const int nfast = plan->nfast; unpack_3d_permute2_2_functor f(d_buf,buf_offset,d_data,data_offset,plan); Kokkos::parallel_for(nslow*nmid*nfast,f); - DeviceType::fence(); + DeviceType().fence(); } /* ---------------------------------------------------------------------- unpack from buf -> data, two axis permutation, nqty values/element @@ -466,7 +466,7 @@ static void unpack_3d_permute2_n(typename FFT_AT::t_FFT_SCALAR_1d_um d_buf, int const int nfast = plan->nfast; unpack_3d_permute2_n_functor f(d_buf,buf_offset,d_data,data_offset,plan); Kokkos::parallel_for(nslow*nmid*nfast,f); - DeviceType::fence(); + DeviceType().fence(); } }; diff --git a/src/KOKKOS/pair_kokkos.h b/src/KOKKOS/pair_kokkos.h index 52a05b3991..d501324960 100644 --- a/src/KOKKOS/pair_kokkos.h +++ b/src/KOKKOS/pair_kokkos.h @@ -444,7 +444,7 @@ struct PairComputeFunctor { ev.evdwl += fev.evdwl; if (c.eflag_atom) - d_eatom(i,0) += fev.evdwl; + d_eatom(i) += fev.evdwl; if (c.vflag_global) { ev.v[0] += fev.v[0]; @@ -554,7 +554,7 @@ struct PairComputeFunctor { } if (c.eflag_atom) - d_eatom(i,0) += fev.evdwl + fev.ecoul; + d_eatom(i) += fev.evdwl + fev.ecoul; if (c.vflag_global) { ev.v[0] += fev.v[0]; @@ -850,8 +850,14 @@ EV_FLOAT pair_compute_neighlist (PairStyle* fpair, typename Kokkos::Impl::enable } template -int GetTeamSize(FunctorStyle& functor, int team_size, int vector_length) { - int team_size_max = Kokkos::TeamPolicy<>::team_size_max(functor); +int GetTeamSize(FunctorStyle& functor, int inum, int reduce_flag, int team_size, int vector_length) { + int team_size_max; + if (reduce_flag) { + EV_FLOAT ev; + team_size_max = Kokkos::TeamPolicy<>(inum,Kokkos::AUTO).team_size_max(functor,ev,Kokkos::ParallelReduceTag()); + } else { + team_size_max = Kokkos::TeamPolicy<>(inum,Kokkos::AUTO).team_size_max(functor,Kokkos::ParallelForTag()); + } #ifdef KOKKOS_ENABLE_CUDA if(team_size*vector_length > team_size_max) @@ -877,13 +883,13 @@ EV_FLOAT pair_compute_neighlist (PairStyle* fpair, typename Kokkos::Impl::enable if(fpair->atom->ntypes > MAX_TYPES_STACKPARAMS) { PairComputeFunctor ff(fpair,list); - atoms_per_team = GetTeamSize(ff, atoms_per_team, vector_length); + atoms_per_team = GetTeamSize(ff, list->inum, (fpair->eflag || fpair->vflag), atoms_per_team, vector_length); Kokkos::TeamPolicy > policy(list->inum,atoms_per_team,vector_length); if (fpair->eflag || fpair->vflag) Kokkos::parallel_reduce(policy,ff,ev); else Kokkos::parallel_for(policy,ff); } else { PairComputeFunctor ff(fpair,list); - atoms_per_team = GetTeamSize(ff, atoms_per_team, vector_length); + atoms_per_team = GetTeamSize(ff, list->inum, (fpair->eflag || fpair->vflag), atoms_per_team, vector_length); Kokkos::TeamPolicy > policy(list->inum,atoms_per_team,vector_length); if (fpair->eflag || fpair->vflag) Kokkos::parallel_reduce(policy,ff,ev); else Kokkos::parallel_for(policy,ff); diff --git a/src/KOKKOS/pair_snap_kokkos_impl.h b/src/KOKKOS/pair_snap_kokkos_impl.h index d807f149a9..d4e5535614 100644 --- a/src/KOKKOS/pair_snap_kokkos_impl.h +++ b/src/KOKKOS/pair_snap_kokkos_impl.h @@ -182,11 +182,14 @@ void PairSNAPKokkos::compute(int eflag_in, int vflag_in) if (max_neighs(k_list), Kokkos::Experimental::Max(max_neighs)); + Kokkos::parallel_reduce("PairSNAPKokkos::find_max_neighs",inum, FindMaxNumNeighs(k_list), Kokkos::Max(max_neighs)); + + int chunk_size = MIN(2000,inum); + chunk_offset = 0; int vector_length = 1; int team_size = 1; - int team_size_max = Kokkos::TeamPolicy::team_size_max(*this); + int team_size_max = Kokkos::TeamPolicy(chunk_size,Kokkos::AUTO).team_size_max(*this,Kokkos::ParallelForTag()); #ifdef KOKKOS_ENABLE_CUDA team_size = 32;//max_neighs; if (team_size*vector_length > team_size_max) diff --git a/src/KOKKOS/remap_kokkos.cpp b/src/KOKKOS/remap_kokkos.cpp index c809aa034c..0d1ce46d7d 100644 --- a/src/KOKKOS/remap_kokkos.cpp +++ b/src/KOKKOS/remap_kokkos.cpp @@ -120,7 +120,7 @@ void RemapKokkos::remap_3d_kokkos(typename FFT_AT::t_FFT_SCALAR_1d d // post all recvs into scratch space for (irecv = 0; irecv < plan->nrecv; irecv++) { - FFT_SCALAR* scratch = d_scratch.ptr_on_device() + plan->recv_bufloc[irecv]; + FFT_SCALAR* scratch = d_scratch.data() + plan->recv_bufloc[irecv]; MPI_Irecv(scratch,plan->recv_size[irecv], MPI_FFT_SCALAR,plan->recv_proc[irecv],0, plan->comm,&plan->request[irecv]); @@ -132,7 +132,7 @@ void RemapKokkos::remap_3d_kokkos(typename FFT_AT::t_FFT_SCALAR_1d d int in_offset = plan->send_offset[isend]; plan->pack(d_in,in_offset, plan->d_sendbuf,0,&plan->packplan[isend]); - MPI_Send(plan->d_sendbuf.ptr_on_device(),plan->send_size[isend],MPI_FFT_SCALAR, + MPI_Send(plan->d_sendbuf.data(),plan->send_size[isend],MPI_FFT_SCALAR, plan->send_proc[isend],0,plan->comm); } -- GitLab From 7a09636f9a80c486aa7f7afbc55c78d28664ce03 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Wed, 5 Feb 2020 14:36:39 -0700 Subject: [PATCH 411/689] Fix compile issue in pair_kokkos.h --- src/KOKKOS/pair_kokkos.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/KOKKOS/pair_kokkos.h b/src/KOKKOS/pair_kokkos.h index d501324960..c9f375de4b 100644 --- a/src/KOKKOS/pair_kokkos.h +++ b/src/KOKKOS/pair_kokkos.h @@ -852,12 +852,11 @@ EV_FLOAT pair_compute_neighlist (PairStyle* fpair, typename Kokkos::Impl::enable template int GetTeamSize(FunctorStyle& functor, int inum, int reduce_flag, int team_size, int vector_length) { int team_size_max; - if (reduce_flag) { - EV_FLOAT ev; - team_size_max = Kokkos::TeamPolicy<>(inum,Kokkos::AUTO).team_size_max(functor,ev,Kokkos::ParallelReduceTag()); - } else { + + if (reduce_flag) + team_size_max = Kokkos::TeamPolicy<>(inum,Kokkos::AUTO).team_size_max(functor,Kokkos::ParallelReduceTag()); + else team_size_max = Kokkos::TeamPolicy<>(inum,Kokkos::AUTO).team_size_max(functor,Kokkos::ParallelForTag()); - } #ifdef KOKKOS_ENABLE_CUDA if(team_size*vector_length > team_size_max) -- GitLab From 4eebcdfc0db5b6afbf6fa9a7dffb5f6ebd0e11d3 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Wed, 5 Feb 2020 16:35:43 -0700 Subject: [PATCH 412/689] Fix runtime issue in Kokkos --- src/KOKKOS/atom_vec_angle_kokkos.cpp | 6 +++--- src/KOKKOS/atom_vec_atomic_kokkos.cpp | 6 +++--- src/KOKKOS/atom_vec_bond_kokkos.cpp | 6 +++--- src/KOKKOS/atom_vec_charge_kokkos.cpp | 6 +++--- src/KOKKOS/atom_vec_dpd_kokkos.cpp | 6 +++--- src/KOKKOS/atom_vec_full_kokkos.cpp | 6 +++--- src/KOKKOS/atom_vec_molecular_kokkos.cpp | 6 +++--- src/KOKKOS/atom_vec_sphere_kokkos.cpp | 6 +++--- 8 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/KOKKOS/atom_vec_angle_kokkos.cpp b/src/KOKKOS/atom_vec_angle_kokkos.cpp index 736e1c1fca..5b934e2434 100644 --- a/src/KOKKOS/atom_vec_angle_kokkos.cpp +++ b/src/KOKKOS/atom_vec_angle_kokkos.cpp @@ -74,9 +74,9 @@ void AtomVecAngleKokkos::grow(int n) memoryKK->grow_kokkos(atomKK->k_mask,atomKK->mask,nmax,"atom:mask"); memoryKK->grow_kokkos(atomKK->k_image,atomKK->image,nmax,"atom:image"); - memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,3,"atom:x"); - memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,3,"atom:v"); - memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,3,"atom:f"); + memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,"atom:x"); + memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,"atom:v"); + memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,"atom:f"); memoryKK->grow_kokkos(atomKK->k_molecule,atomKK->molecule,nmax,"atom:molecule"); memoryKK->grow_kokkos(atomKK->k_nspecial,atomKK->nspecial,nmax,3,"atom:nspecial"); diff --git a/src/KOKKOS/atom_vec_atomic_kokkos.cpp b/src/KOKKOS/atom_vec_atomic_kokkos.cpp index 4fec5740d6..df30b50dd0 100644 --- a/src/KOKKOS/atom_vec_atomic_kokkos.cpp +++ b/src/KOKKOS/atom_vec_atomic_kokkos.cpp @@ -70,9 +70,9 @@ void AtomVecAtomicKokkos::grow(int n) memoryKK->grow_kokkos(atomKK->k_mask,atomKK->mask,nmax,"atom:mask"); memoryKK->grow_kokkos(atomKK->k_image,atomKK->image,nmax,"atom:image"); - memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,3,"atom:x"); - memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,3,"atom:v"); - memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,3,"atom:f"); + memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,"atom:x"); + memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,"atom:v"); + memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,"atom:f"); grow_reset(); atomKK->sync(Host,ALL_MASK); diff --git a/src/KOKKOS/atom_vec_bond_kokkos.cpp b/src/KOKKOS/atom_vec_bond_kokkos.cpp index 4475131d77..b614d94bce 100644 --- a/src/KOKKOS/atom_vec_bond_kokkos.cpp +++ b/src/KOKKOS/atom_vec_bond_kokkos.cpp @@ -73,9 +73,9 @@ void AtomVecBondKokkos::grow(int n) memoryKK->grow_kokkos(atomKK->k_mask,atomKK->mask,nmax,"atom:mask"); memoryKK->grow_kokkos(atomKK->k_image,atomKK->image,nmax,"atom:image"); - memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,3,"atom:x"); - memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,3,"atom:v"); - memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,3,"atom:f"); + memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,"atom:x"); + memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,"atom:v"); + memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,"atom:f"); memoryKK->grow_kokkos(atomKK->k_molecule,atomKK->molecule,nmax,"atom:molecule"); memoryKK->grow_kokkos(atomKK->k_nspecial,atomKK->nspecial,nmax,3,"atom:nspecial"); diff --git a/src/KOKKOS/atom_vec_charge_kokkos.cpp b/src/KOKKOS/atom_vec_charge_kokkos.cpp index 3f26b1e9ea..a9cee3aca8 100644 --- a/src/KOKKOS/atom_vec_charge_kokkos.cpp +++ b/src/KOKKOS/atom_vec_charge_kokkos.cpp @@ -73,9 +73,9 @@ void AtomVecChargeKokkos::grow(int n) memoryKK->grow_kokkos(atomKK->k_mask,atomKK->mask,nmax,"atom:mask"); memoryKK->grow_kokkos(atomKK->k_image,atomKK->image,nmax,"atom:image"); - memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,3,"atom:x"); - memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,3,"atom:v"); - memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,3,"atom:f"); + memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,"atom:x"); + memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,"atom:v"); + memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,"atom:f"); memoryKK->grow_kokkos(atomKK->k_q,atomKK->q,nmax,"atom:q"); diff --git a/src/KOKKOS/atom_vec_dpd_kokkos.cpp b/src/KOKKOS/atom_vec_dpd_kokkos.cpp index 144ef26f19..dfc122b1ef 100644 --- a/src/KOKKOS/atom_vec_dpd_kokkos.cpp +++ b/src/KOKKOS/atom_vec_dpd_kokkos.cpp @@ -75,9 +75,9 @@ void AtomVecDPDKokkos::grow(int n) memoryKK->grow_kokkos(atomKK->k_mask,atomKK->mask,nmax,"atom:mask"); memoryKK->grow_kokkos(atomKK->k_image,atomKK->image,nmax,"atom:image"); - memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,3,"atom:x"); - memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,3,"atom:v"); - memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,3,"atom:f"); + memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,"atom:x"); + memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,"atom:v"); + memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,"atom:f"); memoryKK->grow_kokkos(atomKK->k_rho,atomKK->rho,nmax,"atom:rho"); diff --git a/src/KOKKOS/atom_vec_full_kokkos.cpp b/src/KOKKOS/atom_vec_full_kokkos.cpp index 1fdbcbec8c..b5239867fb 100644 --- a/src/KOKKOS/atom_vec_full_kokkos.cpp +++ b/src/KOKKOS/atom_vec_full_kokkos.cpp @@ -73,9 +73,9 @@ void AtomVecFullKokkos::grow(int n) memoryKK->grow_kokkos(atomKK->k_mask,atomKK->mask,nmax,"atom:mask"); memoryKK->grow_kokkos(atomKK->k_image,atomKK->image,nmax,"atom:image"); - memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,3,"atom:x"); - memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,3,"atom:v"); - memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,3,"atom:f"); + memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,"atom:x"); + memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,"atom:v"); + memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,"atom:f"); memoryKK->grow_kokkos(atomKK->k_q,atomKK->q,nmax,"atom:q"); memoryKK->grow_kokkos(atomKK->k_molecule,atomKK->molecule,nmax,"atom:molecule"); diff --git a/src/KOKKOS/atom_vec_molecular_kokkos.cpp b/src/KOKKOS/atom_vec_molecular_kokkos.cpp index f3b4ae98ca..fec0183971 100644 --- a/src/KOKKOS/atom_vec_molecular_kokkos.cpp +++ b/src/KOKKOS/atom_vec_molecular_kokkos.cpp @@ -73,9 +73,9 @@ void AtomVecMolecularKokkos::grow(int n) memoryKK->grow_kokkos(atomKK->k_mask,atomKK->mask,nmax,"atom:mask"); memoryKK->grow_kokkos(atomKK->k_image,atomKK->image,nmax,"atom:image"); - memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,3,"atom:x"); - memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,3,"atom:v"); - memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,3,"atom:f"); + memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,"atom:x"); + memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,"atom:v"); + memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,"atom:f"); memoryKK->grow_kokkos(atomKK->k_molecule,atomKK->molecule,nmax,"atom:molecule"); memoryKK->grow_kokkos(atomKK->k_nspecial,atomKK->nspecial,nmax,3,"atom:nspecial"); diff --git a/src/KOKKOS/atom_vec_sphere_kokkos.cpp b/src/KOKKOS/atom_vec_sphere_kokkos.cpp index 67aaa32c21..31f8180b4c 100644 --- a/src/KOKKOS/atom_vec_sphere_kokkos.cpp +++ b/src/KOKKOS/atom_vec_sphere_kokkos.cpp @@ -107,9 +107,9 @@ void AtomVecSphereKokkos::grow(int n) memoryKK->grow_kokkos(atomKK->k_mask,atomKK->mask,nmax,"atom:mask"); memoryKK->grow_kokkos(atomKK->k_image,atomKK->image,nmax,"atom:image"); - memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,3,"atom:x"); - memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,3,"atom:v"); - memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,3,"atom:f"); + memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,"atom:x"); + memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,"atom:v"); + memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,"atom:f"); memoryKK->grow_kokkos(atomKK->k_radius,atomKK->radius,nmax,"atom:radius"); memoryKK->grow_kokkos(atomKK->k_rmass,atomKK->rmass,nmax,"atom:rmass"); memoryKK->grow_kokkos(atomKK->k_omega,atomKK->omega,nmax,3,"atom:omega"); -- GitLab From 1e7e9369dab0d5310d80e7c26458fa9fa78911e6 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Thu, 6 Feb 2020 08:44:58 -0700 Subject: [PATCH 413/689] Fix runtime error in Kokkos package --- src/KOKKOS/kokkos_type.h | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/KOKKOS/kokkos_type.h b/src/KOKKOS/kokkos_type.h index 2e68cc0405..3ba6318d41 100644 --- a/src/KOKKOS/kokkos_type.h +++ b/src/KOKKOS/kokkos_type.h @@ -980,17 +980,9 @@ typedef struct ArrayTypes HAT; template void buffer_view(BufferView &buf, DualView &view, const size_t n0, - const size_t n1 = 0, - const size_t n2 = 0, - const size_t n3 = 0, - const size_t n4 = 0, - const size_t n5 = 0, - const size_t n6 = 0, - const size_t n7 = 0) { - - buf = BufferView( - view.template view().data(), - n0,n1,n2,n3,n4,n5,n6,n7); + const size_t n1) { + + buf = BufferView(view.template view().data(),n0,n1); } -- GitLab From 0025dfe1e3fd79bb557048143ccb48296549337c Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Thu, 6 Feb 2020 09:35:04 -0700 Subject: [PATCH 414/689] Update Kokkos CUDA minimum verison --- doc/src/Speed_kokkos.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/Speed_kokkos.rst b/doc/src/Speed_kokkos.rst index 6658957006..ab8444b845 100644 --- a/doc/src/Speed_kokkos.rst +++ b/doc/src/Speed_kokkos.rst @@ -38,7 +38,7 @@ compatible with specific hardware. .. note:: To build with Kokkos support for NVIDIA GPUs, NVIDIA CUDA - software version 7.5 or later must be installed on your system. See + software version 9.0 or later must be installed on your system. See the discussion for the :doc:`GPU package ` for details of how to check and do this. -- GitLab From e298978da0f758b44644d82859cd701ae7923469 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Wed, 25 Mar 2020 13:58:12 -0600 Subject: [PATCH 415/689] Change Kokkos::Impl to std namespace --- src/KOKKOS/atom_kokkos.h | 16 ++++++++-------- src/KOKKOS/fix_qeq_reax_kokkos.cpp | 6 +++--- src/KOKKOS/fix_rx_kokkos.cpp | 6 +++--- src/KOKKOS/fix_shardlow_kokkos.cpp | 6 +++--- src/KOKKOS/pair_buck_coul_cut_kokkos.cpp | 6 +++--- src/KOKKOS/pair_buck_coul_long_kokkos.cpp | 6 +++--- src/KOKKOS/pair_buck_kokkos.cpp | 6 +++--- src/KOKKOS/pair_coul_cut_kokkos.cpp | 6 +++--- src/KOKKOS/pair_coul_debye_kokkos.cpp | 6 +++--- src/KOKKOS/pair_coul_dsf_kokkos.cpp | 6 +++--- src/KOKKOS/pair_coul_long_kokkos.cpp | 6 +++--- src/KOKKOS/pair_coul_wolf_kokkos.cpp | 6 +++--- src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp | 12 ++++++------ src/KOKKOS/pair_eam_alloy_kokkos.cpp | 6 +++--- src/KOKKOS/pair_eam_fs_kokkos.cpp | 6 +++--- src/KOKKOS/pair_eam_kokkos.cpp | 6 +++--- src/KOKKOS/pair_exp6_rx_kokkos.cpp | 6 +++--- src/KOKKOS/pair_gran_hooke_history_kokkos.cpp | 6 +++--- src/KOKKOS/pair_kokkos.h | 4 ++-- ...air_lj_charmm_coul_charmm_implicit_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_charmm_coul_charmm_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_charmm_coul_long_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_class2_coul_cut_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_class2_coul_long_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_class2_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_cut_coul_cut_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_cut_coul_debye_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_cut_coul_dsf_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_cut_coul_long_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_cut_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_expand_kokkos.cpp | 6 +++--- .../pair_lj_gromacs_coul_gromacs_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_gromacs_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_sdk_kokkos.cpp | 6 +++--- src/KOKKOS/pair_morse_kokkos.cpp | 6 +++--- src/KOKKOS/pair_multi_lucy_rx_kokkos.cpp | 6 +++--- src/KOKKOS/pair_reaxc_kokkos.cpp | 6 +++--- src/KOKKOS/pair_snap_kokkos_impl.h | 6 +++--- src/KOKKOS/pair_sw_kokkos.cpp | 6 +++--- src/KOKKOS/pair_table_kokkos.cpp | 6 +++--- src/KOKKOS/pair_table_rx_kokkos.cpp | 6 +++--- src/KOKKOS/pair_tersoff_kokkos.cpp | 6 +++--- src/KOKKOS/pair_tersoff_mod_kokkos.cpp | 6 +++--- src/KOKKOS/pair_tersoff_zbl_kokkos.cpp | 6 +++--- src/KOKKOS/pair_vashishta_kokkos.cpp | 6 +++--- src/KOKKOS/pair_yukawa_kokkos.cpp | 6 +++--- src/KOKKOS/pair_zbl_kokkos.cpp | 6 +++--- src/KOKKOS/sna_kokkos_impl.h | 2 +- 48 files changed, 149 insertions(+), 149 deletions(-) diff --git a/src/KOKKOS/atom_kokkos.h b/src/KOKKOS/atom_kokkos.h index a83b299ebd..0ae032032a 100644 --- a/src/KOKKOS/atom_kokkos.h +++ b/src/KOKKOS/atom_kokkos.h @@ -83,32 +83,32 @@ class SortFunctor { ViewType source; Kokkos::View dest; IndexView index; - SortFunctor(ViewType src, typename Kokkos::Impl::enable_if::type ind):source(src),index(ind){ + SortFunctor(ViewType src, typename std::enable_if::type ind):source(src),index(ind){ dest = Kokkos::View("",src.extent(0)); } - SortFunctor(ViewType src, typename Kokkos::Impl::enable_if::type ind):source(src),index(ind){ + SortFunctor(ViewType src, typename std::enable_if::type ind):source(src),index(ind){ dest = Kokkos::View("",src.extent(0),src.extent(1)); } - SortFunctor(ViewType src, typename Kokkos::Impl::enable_if::type ind):source(src),index(ind){ + SortFunctor(ViewType src, typename std::enable_if::type ind):source(src),index(ind){ dest = Kokkos::View("",src.extent(0),src.extent(1),src.extent(2)); } - SortFunctor(ViewType src, typename Kokkos::Impl::enable_if::type ind):source(src),index(ind){ + SortFunctor(ViewType src, typename std::enable_if::type ind):source(src),index(ind){ dest = Kokkos::View("",src.extent(0),src.extent(1),src.extent(2),src.extent(3)); } KOKKOS_INLINE_FUNCTION - void operator()(const typename Kokkos::Impl::enable_if::type& i) { + void operator()(const typename std::enable_if::type& i) { dest(i) = source(index(i)); } - void operator()(const typename Kokkos::Impl::enable_if::type& i) { + void operator()(const typename std::enable_if::type& i) { for(int j=0;j::type& i) { + void operator()(const typename std::enable_if::type& i) { for(int j=0;j::type& i) { + void operator()(const typename std::enable_if::type& i) { for(int j=0;j::init() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->fix = 1; diff --git a/src/KOKKOS/fix_rx_kokkos.cpp b/src/KOKKOS/fix_rx_kokkos.cpp index e06fc14585..dcb1ac0b71 100644 --- a/src/KOKKOS/fix_rx_kokkos.cpp +++ b/src/KOKKOS/fix_rx_kokkos.cpp @@ -146,10 +146,10 @@ void FixRxKokkos::init() int neighflag = lmp->kokkos->neighflag; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/fix_shardlow_kokkos.cpp b/src/KOKKOS/fix_shardlow_kokkos.cpp index 9bd8594341..c6ad47501a 100644 --- a/src/KOKKOS/fix_shardlow_kokkos.cpp +++ b/src/KOKKOS/fix_shardlow_kokkos.cpp @@ -132,10 +132,10 @@ void FixShardlowKokkos::init() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; // neighbor->requests[irequest]->pair = 0; // neighbor->requests[irequest]->fix = 1; diff --git a/src/KOKKOS/pair_buck_coul_cut_kokkos.cpp b/src/KOKKOS/pair_buck_coul_cut_kokkos.cpp index 2a72617525..97154f7604 100644 --- a/src/KOKKOS/pair_buck_coul_cut_kokkos.cpp +++ b/src/KOKKOS/pair_buck_coul_cut_kokkos.cpp @@ -296,10 +296,10 @@ void PairBuckCoulCutKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_buck_coul_long_kokkos.cpp b/src/KOKKOS/pair_buck_coul_long_kokkos.cpp index fdf395684a..a55c6b25f6 100644 --- a/src/KOKKOS/pair_buck_coul_long_kokkos.cpp +++ b/src/KOKKOS/pair_buck_coul_long_kokkos.cpp @@ -456,10 +456,10 @@ void PairBuckCoulLongKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_buck_kokkos.cpp b/src/KOKKOS/pair_buck_kokkos.cpp index 375d0dc1ea..76ff246be4 100644 --- a/src/KOKKOS/pair_buck_kokkos.cpp +++ b/src/KOKKOS/pair_buck_kokkos.cpp @@ -218,10 +218,10 @@ void PairBuckKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_coul_cut_kokkos.cpp b/src/KOKKOS/pair_coul_cut_kokkos.cpp index 5a1a6eefac..210144040c 100644 --- a/src/KOKKOS/pair_coul_cut_kokkos.cpp +++ b/src/KOKKOS/pair_coul_cut_kokkos.cpp @@ -220,10 +220,10 @@ void PairCoulCutKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_coul_debye_kokkos.cpp b/src/KOKKOS/pair_coul_debye_kokkos.cpp index 8dd7e4f3d2..46a7df7cb1 100644 --- a/src/KOKKOS/pair_coul_debye_kokkos.cpp +++ b/src/KOKKOS/pair_coul_debye_kokkos.cpp @@ -265,10 +265,10 @@ void PairCoulDebyeKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_coul_dsf_kokkos.cpp b/src/KOKKOS/pair_coul_dsf_kokkos.cpp index 836b12ba39..f7bf8fb5d1 100644 --- a/src/KOKKOS/pair_coul_dsf_kokkos.cpp +++ b/src/KOKKOS/pair_coul_dsf_kokkos.cpp @@ -202,10 +202,10 @@ void PairCoulDSFKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_coul_long_kokkos.cpp b/src/KOKKOS/pair_coul_long_kokkos.cpp index 84b89c6373..19a40dad0b 100644 --- a/src/KOKKOS/pair_coul_long_kokkos.cpp +++ b/src/KOKKOS/pair_coul_long_kokkos.cpp @@ -416,10 +416,10 @@ void PairCoulLongKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_coul_wolf_kokkos.cpp b/src/KOKKOS/pair_coul_wolf_kokkos.cpp index 3ca8f16a79..f3ffdc6069 100644 --- a/src/KOKKOS/pair_coul_wolf_kokkos.cpp +++ b/src/KOKKOS/pair_coul_wolf_kokkos.cpp @@ -203,10 +203,10 @@ void PairCoulWolfKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp b/src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp index 21fd32a2c8..1ddf950fd7 100644 --- a/src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp +++ b/src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp @@ -87,10 +87,10 @@ void PairDPDfdtEnergyKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; @@ -125,10 +125,10 @@ void PairDPDfdtEnergyKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_eam_alloy_kokkos.cpp b/src/KOKKOS/pair_eam_alloy_kokkos.cpp index 48bf63386a..87bb5dddf2 100644 --- a/src/KOKKOS/pair_eam_alloy_kokkos.cpp +++ b/src/KOKKOS/pair_eam_alloy_kokkos.cpp @@ -302,10 +302,10 @@ void PairEAMAlloyKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_eam_fs_kokkos.cpp b/src/KOKKOS/pair_eam_fs_kokkos.cpp index 6536dd745a..37fab42d4b 100644 --- a/src/KOKKOS/pair_eam_fs_kokkos.cpp +++ b/src/KOKKOS/pair_eam_fs_kokkos.cpp @@ -302,10 +302,10 @@ void PairEAMFSKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_eam_kokkos.cpp b/src/KOKKOS/pair_eam_kokkos.cpp index 3358fe709c..06e26301a4 100644 --- a/src/KOKKOS/pair_eam_kokkos.cpp +++ b/src/KOKKOS/pair_eam_kokkos.cpp @@ -296,10 +296,10 @@ void PairEAMKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_exp6_rx_kokkos.cpp b/src/KOKKOS/pair_exp6_rx_kokkos.cpp index f3f63c98b2..4d72c85029 100644 --- a/src/KOKKOS/pair_exp6_rx_kokkos.cpp +++ b/src/KOKKOS/pair_exp6_rx_kokkos.cpp @@ -118,10 +118,10 @@ void PairExp6rxKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_gran_hooke_history_kokkos.cpp b/src/KOKKOS/pair_gran_hooke_history_kokkos.cpp index 5071bae32f..9e65c0589e 100644 --- a/src/KOKKOS/pair_gran_hooke_history_kokkos.cpp +++ b/src/KOKKOS/pair_gran_hooke_history_kokkos.cpp @@ -86,10 +86,10 @@ void PairGranHookeHistoryKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == HALF || neighflag == HALFTHREAD) { neighbor->requests[irequest]->full = 0; diff --git a/src/KOKKOS/pair_kokkos.h b/src/KOKKOS/pair_kokkos.h index c9f375de4b..41922b7349 100644 --- a/src/KOKKOS/pair_kokkos.h +++ b/src/KOKKOS/pair_kokkos.h @@ -841,7 +841,7 @@ struct PairComputeFunctor { // pair_compute_neighlist will match - either the dummy version // or the real one further below. template -EV_FLOAT pair_compute_neighlist (PairStyle* fpair, typename Kokkos::Impl::enable_if*>::type list) { +EV_FLOAT pair_compute_neighlist (PairStyle* fpair, typename std::enable_if*>::type list) { EV_FLOAT ev; (void) fpair; (void) list; @@ -869,7 +869,7 @@ int GetTeamSize(FunctorStyle& functor, int inum, int reduce_flag, int team_size, // Submit ParallelFor for NEIGHFLAG=HALF,HALFTHREAD,FULL,N2 template -EV_FLOAT pair_compute_neighlist (PairStyle* fpair, typename Kokkos::Impl::enable_if<(NEIGHFLAG&PairStyle::EnabledNeighFlags) != 0, NeighListKokkos*>::type list) { +EV_FLOAT pair_compute_neighlist (PairStyle* fpair, typename std::enable_if<(NEIGHFLAG&PairStyle::EnabledNeighFlags) != 0, NeighListKokkos*>::type list) { EV_FLOAT ev; if (!fpair->lmp->kokkos->neigh_thread_set) diff --git a/src/KOKKOS/pair_lj_charmm_coul_charmm_implicit_kokkos.cpp b/src/KOKKOS/pair_lj_charmm_coul_charmm_implicit_kokkos.cpp index ae6cb61b60..86786be6f2 100644 --- a/src/KOKKOS/pair_lj_charmm_coul_charmm_implicit_kokkos.cpp +++ b/src/KOKKOS/pair_lj_charmm_coul_charmm_implicit_kokkos.cpp @@ -462,10 +462,10 @@ void PairLJCharmmCoulCharmmImplicitKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_charmm_coul_charmm_kokkos.cpp b/src/KOKKOS/pair_lj_charmm_coul_charmm_kokkos.cpp index 9cdef267e2..3bc7cf5425 100644 --- a/src/KOKKOS/pair_lj_charmm_coul_charmm_kokkos.cpp +++ b/src/KOKKOS/pair_lj_charmm_coul_charmm_kokkos.cpp @@ -464,10 +464,10 @@ void PairLJCharmmCoulCharmmKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_charmm_coul_long_kokkos.cpp b/src/KOKKOS/pair_lj_charmm_coul_long_kokkos.cpp index 441070248d..4285d16bed 100644 --- a/src/KOKKOS/pair_lj_charmm_coul_long_kokkos.cpp +++ b/src/KOKKOS/pair_lj_charmm_coul_long_kokkos.cpp @@ -471,10 +471,10 @@ void PairLJCharmmCoulLongKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_class2_coul_cut_kokkos.cpp b/src/KOKKOS/pair_lj_class2_coul_cut_kokkos.cpp index 1f7642e965..f338575ff6 100644 --- a/src/KOKKOS/pair_lj_class2_coul_cut_kokkos.cpp +++ b/src/KOKKOS/pair_lj_class2_coul_cut_kokkos.cpp @@ -298,10 +298,10 @@ void PairLJClass2CoulCutKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_class2_coul_long_kokkos.cpp b/src/KOKKOS/pair_lj_class2_coul_long_kokkos.cpp index c88ff9378e..3e62b57fdc 100644 --- a/src/KOKKOS/pair_lj_class2_coul_long_kokkos.cpp +++ b/src/KOKKOS/pair_lj_class2_coul_long_kokkos.cpp @@ -453,10 +453,10 @@ void PairLJClass2CoulLongKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_class2_kokkos.cpp b/src/KOKKOS/pair_lj_class2_kokkos.cpp index 9900e7361f..76406c4410 100644 --- a/src/KOKKOS/pair_lj_class2_kokkos.cpp +++ b/src/KOKKOS/pair_lj_class2_kokkos.cpp @@ -236,10 +236,10 @@ void PairLJClass2Kokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_cut_coul_cut_kokkos.cpp b/src/KOKKOS/pair_lj_cut_coul_cut_kokkos.cpp index 1601e4a4b2..094c25471c 100644 --- a/src/KOKKOS/pair_lj_cut_coul_cut_kokkos.cpp +++ b/src/KOKKOS/pair_lj_cut_coul_cut_kokkos.cpp @@ -289,10 +289,10 @@ void PairLJCutCoulCutKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_cut_coul_debye_kokkos.cpp b/src/KOKKOS/pair_lj_cut_coul_debye_kokkos.cpp index 6e7d1eeb8b..8d1f650061 100644 --- a/src/KOKKOS/pair_lj_cut_coul_debye_kokkos.cpp +++ b/src/KOKKOS/pair_lj_cut_coul_debye_kokkos.cpp @@ -318,10 +318,10 @@ void PairLJCutCoulDebyeKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_cut_coul_dsf_kokkos.cpp b/src/KOKKOS/pair_lj_cut_coul_dsf_kokkos.cpp index b7dc7cc26d..bd1754df9a 100644 --- a/src/KOKKOS/pair_lj_cut_coul_dsf_kokkos.cpp +++ b/src/KOKKOS/pair_lj_cut_coul_dsf_kokkos.cpp @@ -311,10 +311,10 @@ void PairLJCutCoulDSFKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_cut_coul_long_kokkos.cpp b/src/KOKKOS/pair_lj_cut_coul_long_kokkos.cpp index 122d59af82..fa53850b07 100644 --- a/src/KOKKOS/pair_lj_cut_coul_long_kokkos.cpp +++ b/src/KOKKOS/pair_lj_cut_coul_long_kokkos.cpp @@ -452,10 +452,10 @@ void PairLJCutCoulLongKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_cut_kokkos.cpp b/src/KOKKOS/pair_lj_cut_kokkos.cpp index df750b7524..3770e8f816 100644 --- a/src/KOKKOS/pair_lj_cut_kokkos.cpp +++ b/src/KOKKOS/pair_lj_cut_kokkos.cpp @@ -230,10 +230,10 @@ void PairLJCutKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_expand_kokkos.cpp b/src/KOKKOS/pair_lj_expand_kokkos.cpp index 38bebc364f..c46e0d47e4 100644 --- a/src/KOKKOS/pair_lj_expand_kokkos.cpp +++ b/src/KOKKOS/pair_lj_expand_kokkos.cpp @@ -238,10 +238,10 @@ void PairLJExpandKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_gromacs_coul_gromacs_kokkos.cpp b/src/KOKKOS/pair_lj_gromacs_coul_gromacs_kokkos.cpp index a46a5c0441..1bef3f0a27 100644 --- a/src/KOKKOS/pair_lj_gromacs_coul_gromacs_kokkos.cpp +++ b/src/KOKKOS/pair_lj_gromacs_coul_gromacs_kokkos.cpp @@ -447,10 +447,10 @@ void PairLJGromacsCoulGromacsKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_gromacs_kokkos.cpp b/src/KOKKOS/pair_lj_gromacs_kokkos.cpp index 23ed5e5595..cfc65c883b 100644 --- a/src/KOKKOS/pair_lj_gromacs_kokkos.cpp +++ b/src/KOKKOS/pair_lj_gromacs_kokkos.cpp @@ -285,10 +285,10 @@ void PairLJGromacsKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_sdk_kokkos.cpp b/src/KOKKOS/pair_lj_sdk_kokkos.cpp index 25f081d255..cb99de3cd9 100644 --- a/src/KOKKOS/pair_lj_sdk_kokkos.cpp +++ b/src/KOKKOS/pair_lj_sdk_kokkos.cpp @@ -268,10 +268,10 @@ void PairLJSDKKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_morse_kokkos.cpp b/src/KOKKOS/pair_morse_kokkos.cpp index d3e3042a34..799278bf9e 100644 --- a/src/KOKKOS/pair_morse_kokkos.cpp +++ b/src/KOKKOS/pair_morse_kokkos.cpp @@ -247,10 +247,10 @@ void PairMorseKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_multi_lucy_rx_kokkos.cpp b/src/KOKKOS/pair_multi_lucy_rx_kokkos.cpp index 75247859ed..3b7a738026 100644 --- a/src/KOKKOS/pair_multi_lucy_rx_kokkos.cpp +++ b/src/KOKKOS/pair_multi_lucy_rx_kokkos.cpp @@ -99,10 +99,10 @@ void PairMultiLucyRXKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_reaxc_kokkos.cpp b/src/KOKKOS/pair_reaxc_kokkos.cpp index d0ad1f1b09..18144bb653 100644 --- a/src/KOKKOS/pair_reaxc_kokkos.cpp +++ b/src/KOKKOS/pair_reaxc_kokkos.cpp @@ -147,10 +147,10 @@ void PairReaxCKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_snap_kokkos_impl.h b/src/KOKKOS/pair_snap_kokkos_impl.h index d4e5535614..ad850981cc 100644 --- a/src/KOKKOS/pair_snap_kokkos_impl.h +++ b/src/KOKKOS/pair_snap_kokkos_impl.h @@ -91,10 +91,10 @@ void PairSNAPKokkos::init_style() int irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == HALF || neighflag == HALFTHREAD) { // still need atomics, even though using a full neigh list neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_sw_kokkos.cpp b/src/KOKKOS/pair_sw_kokkos.cpp index e85afa362f..3ce99fe629 100644 --- a/src/KOKKOS/pair_sw_kokkos.cpp +++ b/src/KOKKOS/pair_sw_kokkos.cpp @@ -610,10 +610,10 @@ void PairSWKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; // always request a full neighbor list diff --git a/src/KOKKOS/pair_table_kokkos.cpp b/src/KOKKOS/pair_table_kokkos.cpp index 5ee24ad479..7311e4ec05 100644 --- a/src/KOKKOS/pair_table_kokkos.cpp +++ b/src/KOKKOS/pair_table_kokkos.cpp @@ -514,10 +514,10 @@ void PairTableKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_table_rx_kokkos.cpp b/src/KOKKOS/pair_table_rx_kokkos.cpp index daebeda8db..cd7aa373ed 100644 --- a/src/KOKKOS/pair_table_rx_kokkos.cpp +++ b/src/KOKKOS/pair_table_rx_kokkos.cpp @@ -1268,10 +1268,10 @@ void PairTableRXKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_tersoff_kokkos.cpp b/src/KOKKOS/pair_tersoff_kokkos.cpp index b360b20ef3..d068ac0412 100644 --- a/src/KOKKOS/pair_tersoff_kokkos.cpp +++ b/src/KOKKOS/pair_tersoff_kokkos.cpp @@ -88,10 +88,10 @@ void PairTersoffKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) error->all(FLERR,"Cannot (yet) use full neighbor list style with tersoff/kk"); diff --git a/src/KOKKOS/pair_tersoff_mod_kokkos.cpp b/src/KOKKOS/pair_tersoff_mod_kokkos.cpp index 81ef486999..5eb23d498a 100644 --- a/src/KOKKOS/pair_tersoff_mod_kokkos.cpp +++ b/src/KOKKOS/pair_tersoff_mod_kokkos.cpp @@ -88,10 +88,10 @@ void PairTersoffMODKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) error->all(FLERR,"Cannot (yet) use full neighbor list style with tersoff/mod/kk"); diff --git a/src/KOKKOS/pair_tersoff_zbl_kokkos.cpp b/src/KOKKOS/pair_tersoff_zbl_kokkos.cpp index 4593f32e36..2648689fad 100644 --- a/src/KOKKOS/pair_tersoff_zbl_kokkos.cpp +++ b/src/KOKKOS/pair_tersoff_zbl_kokkos.cpp @@ -101,10 +101,10 @@ void PairTersoffZBLKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) error->all(FLERR,"Cannot (yet) use full neighbor list style with tersoff/zbl/kk"); diff --git a/src/KOKKOS/pair_vashishta_kokkos.cpp b/src/KOKKOS/pair_vashishta_kokkos.cpp index 614d3334d5..ddb0688e03 100644 --- a/src/KOKKOS/pair_vashishta_kokkos.cpp +++ b/src/KOKKOS/pair_vashishta_kokkos.cpp @@ -585,10 +585,10 @@ void PairVashishtaKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; // always request a full neighbor list diff --git a/src/KOKKOS/pair_yukawa_kokkos.cpp b/src/KOKKOS/pair_yukawa_kokkos.cpp index 6dfffd4a54..a1838c9ef6 100644 --- a/src/KOKKOS/pair_yukawa_kokkos.cpp +++ b/src/KOKKOS/pair_yukawa_kokkos.cpp @@ -120,10 +120,10 @@ void PairYukawaKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_zbl_kokkos.cpp b/src/KOKKOS/pair_zbl_kokkos.cpp index 5697dd5b00..7a476e4a14 100644 --- a/src/KOKKOS/pair_zbl_kokkos.cpp +++ b/src/KOKKOS/pair_zbl_kokkos.cpp @@ -92,10 +92,10 @@ void PairZBLKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/sna_kokkos_impl.h b/src/KOKKOS/sna_kokkos_impl.h index dcedf333e5..c6c8bbb421 100644 --- a/src/KOKKOS/sna_kokkos_impl.h +++ b/src/KOKKOS/sna_kokkos_impl.h @@ -1643,7 +1643,7 @@ double SNAKokkos::memory_usage() } #endif bytes += natom * idxu_max * sizeof(double) * 2; // ulisttot - if (!Kokkos::Impl::is_same::value) + if (!std::is_same::value) bytes += natom * idxu_max * sizeof(double) * 2; // ulisttot_lr bytes += natom * idxz_max * sizeof(double) * 2; // zlist -- GitLab From 0252d8c21073512b6dd8b85d8c21cef8eeabd175 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Wed, 11 Mar 2020 12:17:53 -0600 Subject: [PATCH 416/689] Fix compile for UVM --- src/KOKKOS/angle_charmm_kokkos.h | 6 +-- src/KOKKOS/angle_class2_kokkos.cpp | 6 +-- src/KOKKOS/angle_cosine_kokkos.cpp | 6 +-- src/KOKKOS/angle_harmonic_kokkos.cpp | 6 +-- src/KOKKOS/bond_class2_kokkos.h | 6 +-- src/KOKKOS/bond_fene_kokkos.cpp | 6 +-- src/KOKKOS/bond_harmonic_kokkos.h | 6 +-- src/KOKKOS/dihedral_charmm_kokkos.cpp | 2 +- src/KOKKOS/dihedral_charmm_kokkos.h | 8 ++-- src/KOKKOS/dihedral_class2_kokkos.cpp | 6 +-- src/KOKKOS/dihedral_harmonic_kokkos.cpp | 6 +-- src/KOKKOS/dihedral_opls_kokkos.cpp | 6 +-- src/KOKKOS/fix_qeq_reax_kokkos.h | 4 +- src/KOKKOS/fix_rx_kokkos.cpp | 6 +-- src/KOKKOS/improper_class2_kokkos.cpp | 8 ++-- src/KOKKOS/improper_class2_kokkos.h | 2 +- src/KOKKOS/improper_harmonic_kokkos.h | 6 +-- src/KOKKOS/kokkos_type.h | 14 +++++++ src/KOKKOS/pair_coul_dsf_kokkos.cpp | 8 ++-- src/KOKKOS/pair_coul_wolf_kokkos.cpp | 8 ++-- src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp | 12 +++--- src/KOKKOS/pair_eam_alloy_kokkos.h | 16 ++++---- src/KOKKOS/pair_eam_fs_kokkos.h | 16 ++++---- src/KOKKOS/pair_eam_kokkos.h | 16 ++++---- src/KOKKOS/pair_exp6_rx_kokkos.cpp | 16 ++++---- src/KOKKOS/pair_gran_hooke_history_kokkos.cpp | 6 +-- src/KOKKOS/pair_kokkos.h | 12 +++--- src/KOKKOS/pair_multi_lucy_rx_kokkos.cpp | 8 ++-- src/KOKKOS/pair_reaxc_kokkos.cpp | 10 ++--- src/KOKKOS/pair_reaxc_kokkos.h | 38 +++++++++---------- src/KOKKOS/pair_snap_kokkos.h | 8 ++-- src/KOKKOS/pair_sw_kokkos.h | 12 +++--- src/KOKKOS/pair_table_rx_kokkos.cpp | 26 +++++++------ src/KOKKOS/pair_tersoff_kokkos.h | 12 +++--- src/KOKKOS/pair_tersoff_mod_kokkos.h | 12 +++--- src/KOKKOS/pair_tersoff_zbl_kokkos.h | 12 +++--- src/KOKKOS/pair_vashishta_kokkos.cpp | 10 ++--- src/KOKKOS/pppm_kokkos.cpp | 2 +- src/KOKKOS/sna_kokkos.h | 4 +- 39 files changed, 195 insertions(+), 179 deletions(-) diff --git a/src/KOKKOS/angle_charmm_kokkos.h b/src/KOKKOS/angle_charmm_kokkos.h index e168160562..865439b83a 100644 --- a/src/KOKKOS/angle_charmm_kokkos.h +++ b/src/KOKKOS/angle_charmm_kokkos.h @@ -63,13 +63,13 @@ class AngleCharmmKokkos : public AngleCharmm { typedef ArrayTypes AT; typename AT::t_x_array_randomread x; - typename Kokkos::View > f; + typename Kokkos::View::value,Kokkos::MemoryTraits > f; typename AT::t_int_2d anglelist; Kokkos::DualView k_eatom; Kokkos::DualView k_vatom; - Kokkos::View > d_eatom; - Kokkos::View > d_vatom; + Kokkos::View::value,Kokkos::MemoryTraits > d_eatom; + Kokkos::View::value,Kokkos::MemoryTraits > d_vatom; int nlocal,newton_bond; int eflag,vflag; diff --git a/src/KOKKOS/angle_class2_kokkos.cpp b/src/KOKKOS/angle_class2_kokkos.cpp index 809ce7e7dd..57563b959f 100644 --- a/src/KOKKOS/angle_class2_kokkos.cpp +++ b/src/KOKKOS/angle_class2_kokkos.cpp @@ -158,7 +158,7 @@ KOKKOS_INLINE_FUNCTION void AngleClass2Kokkos::operator()(TagAngleClass2Compute, const int &n, EV_FLOAT& ev) const { // The f array is atomic - Kokkos::View > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; const int i1 = anglelist(n,0); const int i2 = anglelist(n,1); @@ -495,8 +495,8 @@ void AngleClass2Kokkos::ev_tally(EV_FLOAT &ev, const int i, const in F_FLOAT v[6]; // The eatom and vatom arrays are atomic - Kokkos::View > v_eatom = k_eatom.template view(); - Kokkos::View > v_vatom = k_vatom.template view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_eatom = k_eatom.template view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_vatom = k_vatom.template view(); if (eflag_either) { if (eflag_global) { diff --git a/src/KOKKOS/angle_cosine_kokkos.cpp b/src/KOKKOS/angle_cosine_kokkos.cpp index da0ff398f1..65c4c1475a 100644 --- a/src/KOKKOS/angle_cosine_kokkos.cpp +++ b/src/KOKKOS/angle_cosine_kokkos.cpp @@ -141,7 +141,7 @@ KOKKOS_INLINE_FUNCTION void AngleCosineKokkos::operator()(TagAngleCosineCompute, const int &n, EV_FLOAT& ev) const { // The f array is atomic - Kokkos::View > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; const int i1 = anglelist(n,0); const int i2 = anglelist(n,1); @@ -284,8 +284,8 @@ void AngleCosineKokkos::ev_tally(EV_FLOAT &ev, const int i, const in F_FLOAT v[6]; // The eatom and vatom arrays are atomic - Kokkos::View > v_eatom = k_eatom.template view(); - Kokkos::View > v_vatom = k_vatom.template view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_eatom = k_eatom.template view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_vatom = k_vatom.template view(); if (eflag_either) { if (eflag_global) { diff --git a/src/KOKKOS/angle_harmonic_kokkos.cpp b/src/KOKKOS/angle_harmonic_kokkos.cpp index fc274bb894..4b8a87ece7 100644 --- a/src/KOKKOS/angle_harmonic_kokkos.cpp +++ b/src/KOKKOS/angle_harmonic_kokkos.cpp @@ -142,7 +142,7 @@ KOKKOS_INLINE_FUNCTION void AngleHarmonicKokkos::operator()(TagAngleHarmonicCompute, const int &n, EV_FLOAT& ev) const { // The f array is atomic - Kokkos::View > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; const int i1 = anglelist(n,0); const int i2 = anglelist(n,1); @@ -302,8 +302,8 @@ void AngleHarmonicKokkos::ev_tally(EV_FLOAT &ev, const int i, const F_FLOAT v[6]; // The eatom and vatom arrays are atomic - Kokkos::View > v_eatom = k_eatom.template view(); - Kokkos::View > v_vatom = k_vatom.template view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_eatom = k_eatom.template view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_vatom = k_vatom.template view(); if (eflag_either) { if (eflag_global) { diff --git a/src/KOKKOS/bond_class2_kokkos.h b/src/KOKKOS/bond_class2_kokkos.h index a31ae4b8ae..b3c1d5f682 100644 --- a/src/KOKKOS/bond_class2_kokkos.h +++ b/src/KOKKOS/bond_class2_kokkos.h @@ -63,13 +63,13 @@ class BondClass2Kokkos : public BondClass2 { class NeighborKokkos *neighborKK; typename AT::t_x_array_randomread x; - typename Kokkos::View > f; + typename Kokkos::View::value,Kokkos::MemoryTraits > f; typename AT::t_int_2d bondlist; Kokkos::DualView k_eatom; Kokkos::DualView k_vatom; - Kokkos::View > d_eatom; - Kokkos::View > d_vatom; + Kokkos::View::value,Kokkos::MemoryTraits > d_eatom; + Kokkos::View::value,Kokkos::MemoryTraits > d_vatom; int nlocal,newton_bond; int eflag,vflag; diff --git a/src/KOKKOS/bond_fene_kokkos.cpp b/src/KOKKOS/bond_fene_kokkos.cpp index 361bb61f7e..5f1e9d3ddc 100644 --- a/src/KOKKOS/bond_fene_kokkos.cpp +++ b/src/KOKKOS/bond_fene_kokkos.cpp @@ -166,7 +166,7 @@ void BondFENEKokkos::operator()(TagBondFENECompute > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; const int i1 = bondlist(n,0); const int i2 = bondlist(n,1); @@ -320,8 +320,8 @@ void BondFENEKokkos::ev_tally(EV_FLOAT &ev, const int &i, const int F_FLOAT v[6]; // The eatom and vatom arrays are atomic - Kokkos::View > v_eatom = k_eatom.view(); - Kokkos::View > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_vatom = k_vatom.view(); if (eflag_either) { if (eflag_global) { diff --git a/src/KOKKOS/bond_harmonic_kokkos.h b/src/KOKKOS/bond_harmonic_kokkos.h index 2bf12f3766..b5bee7e909 100644 --- a/src/KOKKOS/bond_harmonic_kokkos.h +++ b/src/KOKKOS/bond_harmonic_kokkos.h @@ -63,13 +63,13 @@ class BondHarmonicKokkos : public BondHarmonic { typedef ArrayTypes AT; typename AT::t_x_array_randomread x; - typename Kokkos::View > f; + typename Kokkos::View::value,Kokkos::MemoryTraits > f; typename AT::t_int_2d bondlist; Kokkos::DualView k_eatom; Kokkos::DualView k_vatom; - Kokkos::View > d_eatom; - Kokkos::View > d_vatom; + Kokkos::View::value,Kokkos::MemoryTraits > d_eatom; + Kokkos::View::value,Kokkos::MemoryTraits > d_vatom; int nlocal,newton_bond; int eflag,vflag; diff --git a/src/KOKKOS/dihedral_charmm_kokkos.cpp b/src/KOKKOS/dihedral_charmm_kokkos.cpp index 94fd0b9bb7..939834d096 100644 --- a/src/KOKKOS/dihedral_charmm_kokkos.cpp +++ b/src/KOKKOS/dihedral_charmm_kokkos.cpp @@ -201,7 +201,7 @@ KOKKOS_INLINE_FUNCTION void DihedralCharmmKokkos::operator()(TagDihedralCharmmCompute, const int &n, EVM_FLOAT& evm) const { // The f array is atomic - Kokkos::View > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; const int i1 = dihedrallist(n,0); const int i2 = dihedrallist(n,1); diff --git a/src/KOKKOS/dihedral_charmm_kokkos.h b/src/KOKKOS/dihedral_charmm_kokkos.h index 449f934533..21bb6fd2e1 100644 --- a/src/KOKKOS/dihedral_charmm_kokkos.h +++ b/src/KOKKOS/dihedral_charmm_kokkos.h @@ -134,13 +134,13 @@ class DihedralCharmmKokkos : public DihedralCharmm { Kokkos::DualView k_eatom; Kokkos::DualView k_vatom; - Kokkos::View > d_eatom; - Kokkos::View > d_vatom; + Kokkos::View::value,Kokkos::MemoryTraits > d_eatom; + Kokkos::View::value,Kokkos::MemoryTraits > d_vatom; Kokkos::DualView k_eatom_pair; Kokkos::DualView k_vatom_pair; - Kokkos::View > d_eatom_pair; - Kokkos::View > d_vatom_pair; + Kokkos::View::value,Kokkos::MemoryTraits > d_eatom_pair; + Kokkos::View::value,Kokkos::MemoryTraits > d_vatom_pair; int nlocal,newton_bond; int eflag,vflag; diff --git a/src/KOKKOS/dihedral_class2_kokkos.cpp b/src/KOKKOS/dihedral_class2_kokkos.cpp index 0310053b5e..60daca3137 100644 --- a/src/KOKKOS/dihedral_class2_kokkos.cpp +++ b/src/KOKKOS/dihedral_class2_kokkos.cpp @@ -197,7 +197,7 @@ KOKKOS_INLINE_FUNCTION void DihedralClass2Kokkos::operator()(TagDihedralClass2Compute, const int &n, EV_FLOAT& ev) const { // The f array is atomic - Kokkos::View > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; const int i1 = dihedrallist(n,0); const int i2 = dihedrallist(n,1); @@ -1015,8 +1015,8 @@ void DihedralClass2Kokkos::ev_tally(EV_FLOAT &ev, const int i1, cons F_FLOAT v[6]; // The eatom and vatom arrays are atomic - Kokkos::View > v_eatom = k_eatom.view(); - Kokkos::View > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_vatom = k_vatom.view(); if (eflag_either) { if (eflag_global) { diff --git a/src/KOKKOS/dihedral_harmonic_kokkos.cpp b/src/KOKKOS/dihedral_harmonic_kokkos.cpp index dd77bc605b..0ed739ef38 100644 --- a/src/KOKKOS/dihedral_harmonic_kokkos.cpp +++ b/src/KOKKOS/dihedral_harmonic_kokkos.cpp @@ -158,7 +158,7 @@ KOKKOS_INLINE_FUNCTION void DihedralHarmonicKokkos::operator()(TagDihedralHarmonicCompute, const int &n, EV_FLOAT& ev) const { // The f array is atomic - Kokkos::View > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; const int i1 = dihedrallist(n,0); const int i2 = dihedrallist(n,1); @@ -414,8 +414,8 @@ void DihedralHarmonicKokkos::ev_tally(EV_FLOAT &ev, const int i1, co F_FLOAT v[6]; // The eatom and vatom arrays are atomic - Kokkos::View > v_eatom = k_eatom.view(); - Kokkos::View > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_vatom = k_vatom.view(); if (eflag_either) { if (eflag_global) { diff --git a/src/KOKKOS/dihedral_opls_kokkos.cpp b/src/KOKKOS/dihedral_opls_kokkos.cpp index 825d106e04..0f510e01ad 100644 --- a/src/KOKKOS/dihedral_opls_kokkos.cpp +++ b/src/KOKKOS/dihedral_opls_kokkos.cpp @@ -157,7 +157,7 @@ KOKKOS_INLINE_FUNCTION void DihedralOPLSKokkos::operator()(TagDihedralOPLSCompute, const int &n, EV_FLOAT& ev) const { // The f array is atomic - Kokkos::View > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; const int i1 = dihedrallist(n,0); const int i2 = dihedrallist(n,1); @@ -419,8 +419,8 @@ void DihedralOPLSKokkos::ev_tally(EV_FLOAT &ev, const int i1, const F_FLOAT v[6]; // The eatom and vatom arrays are atomic - Kokkos::View > v_eatom = k_eatom.view(); - Kokkos::View > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_vatom = k_vatom.view(); if (eflag_either) { if (eflag_global) { diff --git a/src/KOKKOS/fix_qeq_reax_kokkos.h b/src/KOKKOS/fix_qeq_reax_kokkos.h index cd69aa9283..55dec64d33 100644 --- a/src/KOKKOS/fix_qeq_reax_kokkos.h +++ b/src/KOKKOS/fix_qeq_reax_kokkos.h @@ -200,8 +200,8 @@ class FixQEqReaxKokkos : public FixQEqReax { HAT::t_ffloat_2d h_s_hist, h_t_hist; typename AT::t_ffloat_2d_randomread r_s_hist, r_t_hist; - Kokkos::Experimental::ScatterView dup_o; - Kokkos::Experimental::ScatterView ndup_o; + Kokkos::Experimental::ScatterView::value, Kokkos::Experimental::ScatterSum, Kokkos::Experimental::ScatterDuplicated> dup_o; + Kokkos::Experimental::ScatterView::value, Kokkos::Experimental::ScatterSum, Kokkos::Experimental::ScatterNonDuplicated> ndup_o; void init_shielding_k(); void init_hist(); diff --git a/src/KOKKOS/fix_rx_kokkos.cpp b/src/KOKKOS/fix_rx_kokkos.cpp index dcb1ac0b71..9271cf1b88 100644 --- a/src/KOKKOS/fix_rx_kokkos.cpp +++ b/src/KOKKOS/fix_rx_kokkos.cpp @@ -1908,7 +1908,7 @@ void FixRxKokkos::operator()(Tag_FixRxKokkos_firstPairOperator::value> > AtomicViewType; + typedef Kokkos::View< E_FLOAT*, typename DAT::t_efloat_1d::array_layout, typename KKDevice::value, Kokkos::MemoryTraits< AtomicF< NEIGHFLAG >::value> > AtomicViewType; AtomicViewType a_dpdThetaLocal = d_dpdThetaLocal; AtomicViewType a_sumWeights = d_sumWeights; @@ -2083,8 +2083,8 @@ void FixRxKokkos::computeLocalTemperature() { // Create an atomic view of sumWeights and dpdThetaLocal. Only needed // for Half/thread scenarios. - //typedef Kokkos::View< E_FLOAT*, typename DAT::t_efloat_1d::array_layout, DeviceType, Kokkos::MemoryTraits< AtomicF< NEIGHFLAG >::value> > AtomicViewType; - typedef Kokkos::View< E_FLOAT*, typename DAT::t_efloat_1d::array_layout, DeviceType, Kokkos::MemoryTraits< AtomicF< NEIGHFLAG >::value> > AtomicViewType; + //typedef Kokkos::View< E_FLOAT*, typename DAT::t_efloat_1d::array_layout, typename KKDevice::value, Kokkos::MemoryTraits< AtomicF< NEIGHFLAG >::value> > AtomicViewType; + typedef Kokkos::View< E_FLOAT*, typename DAT::t_efloat_1d::array_layout, typename KKDevice::value, Kokkos::MemoryTraits< AtomicF< NEIGHFLAG >::value> > AtomicViewType; AtomicViewType a_dpdThetaLocal = d_dpdThetaLocal; AtomicViewType a_sumWeights = d_sumWeights; diff --git a/src/KOKKOS/improper_class2_kokkos.cpp b/src/KOKKOS/improper_class2_kokkos.cpp index defd5e16f5..888f526c76 100644 --- a/src/KOKKOS/improper_class2_kokkos.cpp +++ b/src/KOKKOS/improper_class2_kokkos.cpp @@ -188,7 +188,7 @@ KOKKOS_INLINE_FUNCTION void ImproperClass2Kokkos::operator()(TagImproperClass2Compute, const int &n, EV_FLOAT& ev) const { // The f array is atomic - Kokkos::View > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; int i, j, k; F_FLOAT delr[3][3],rmag[3],rinvmag[3],rmag2[3]; @@ -660,7 +660,7 @@ KOKKOS_INLINE_FUNCTION void ImproperClass2Kokkos::operator()(TagImproperClass2AngleAngle, const int &n, EV_FLOAT& ev) const { // The f array is atomic - Kokkos::View > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; int i,j,k; F_FLOAT eimproper; @@ -1010,8 +1010,8 @@ void ImproperClass2Kokkos::ev_tally(EV_FLOAT &ev, const int i1, cons F_FLOAT v[6]; // The eatom and vatom arrays are atomic - Kokkos::View > v_eatom = k_eatom.view(); - Kokkos::View > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_vatom = k_vatom.view(); if (eflag_either) { if (eflag_global) { diff --git a/src/KOKKOS/improper_class2_kokkos.h b/src/KOKKOS/improper_class2_kokkos.h index 0fbfab2beb..11212249e7 100644 --- a/src/KOKKOS/improper_class2_kokkos.h +++ b/src/KOKKOS/improper_class2_kokkos.h @@ -75,7 +75,7 @@ class ImproperClass2Kokkos : public ImproperClass2 { class NeighborKokkos *neighborKK; typename AT::t_x_array_randomread x; - typename Kokkos::View > f; + typename Kokkos::View::value,Kokkos::MemoryTraits > f; typename AT::t_int_2d improperlist; DAT::tdual_efloat_1d k_eatom; diff --git a/src/KOKKOS/improper_harmonic_kokkos.h b/src/KOKKOS/improper_harmonic_kokkos.h index 23ae0c7110..fb44081928 100644 --- a/src/KOKKOS/improper_harmonic_kokkos.h +++ b/src/KOKKOS/improper_harmonic_kokkos.h @@ -64,13 +64,13 @@ class ImproperHarmonicKokkos : public ImproperHarmonic { class NeighborKokkos *neighborKK; typename AT::t_x_array_randomread x; - typename Kokkos::View > f; + typename Kokkos::View::value,Kokkos::MemoryTraits > f; typename AT::t_int_2d improperlist; Kokkos::DualView k_eatom; Kokkos::DualView k_vatom; - Kokkos::View > d_eatom; - Kokkos::View > d_vatom; + Kokkos::View::value,Kokkos::MemoryTraits > d_eatom; + Kokkos::View::value,Kokkos::MemoryTraits > d_vatom; int nlocal,newton_bond; int eflag,vflag; diff --git a/src/KOKKOS/kokkos_type.h b/src/KOKKOS/kokkos_type.h index 3ba6318d41..b1d17b45c3 100644 --- a/src/KOKKOS/kokkos_type.h +++ b/src/KOKKOS/kokkos_type.h @@ -163,6 +163,20 @@ t_scalar3 operator * typedef Kokkos::DefaultExecutionSpace LMPDeviceType; typedef Kokkos::HostSpace::execution_space LMPHostType; + +// Need to use Cuda UVM memory space for Host execution space + +template +class KKDevice { +public: +#if defined(KOKKOS_ENABLE_CUDA) && defined(KOKKOS_ENABLE_CUDA_UVM) + typedef Kokkos::Device value; +#else + typedef Kokkos::Device value; +#endif +}; + + // set ExecutionSpace stuct with variable "space" template diff --git a/src/KOKKOS/pair_coul_dsf_kokkos.cpp b/src/KOKKOS/pair_coul_dsf_kokkos.cpp index f7bf8fb5d1..cabdcfd455 100644 --- a/src/KOKKOS/pair_coul_dsf_kokkos.cpp +++ b/src/KOKKOS/pair_coul_dsf_kokkos.cpp @@ -227,8 +227,8 @@ KOKKOS_INLINE_FUNCTION void PairCoulDSFKokkos::operator()(TagPairCoulDSFKernelA, const int &ii, EV_FLOAT& ev) const { // The f array is atomic for Half/Thread neighbor style - Kokkos::View::value> > a_f = f; - Kokkos::View::value> > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_eatom = k_eatom.view(); const int i = d_ilist[ii]; const X_FLOAT xtmp = x(i,0); @@ -323,8 +323,8 @@ void PairCoulDSFKokkos::ev_tally(EV_FLOAT &ev, const int &i, const i const int VFLAG = vflag_either; // The eatom and vatom arrays are atomic for Half/Thread neighbor style - Kokkos::View::value> > v_eatom = k_eatom.view(); - Kokkos::View::value> > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_vatom = k_vatom.view(); if (EFLAG) { if (eflag_atom) { diff --git a/src/KOKKOS/pair_coul_wolf_kokkos.cpp b/src/KOKKOS/pair_coul_wolf_kokkos.cpp index f3ffdc6069..45c4ec3f22 100644 --- a/src/KOKKOS/pair_coul_wolf_kokkos.cpp +++ b/src/KOKKOS/pair_coul_wolf_kokkos.cpp @@ -228,8 +228,8 @@ KOKKOS_INLINE_FUNCTION void PairCoulWolfKokkos::operator()(TagPairCoulWolfKernelA, const int &ii, EV_FLOAT& ev) const { // The f array is atomic for Half/Thread neighbor style - Kokkos::View::value> > a_f = f; - Kokkos::View::value> > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_eatom = k_eatom.view(); const int i = d_ilist[ii]; const X_FLOAT xtmp = x(i,0); @@ -325,8 +325,8 @@ void PairCoulWolfKokkos::ev_tally(EV_FLOAT &ev, const int &i, const const int VFLAG = vflag_either; // The eatom and vatom arrays are atomic for Half/Thread neighbor style - Kokkos::View::value> > v_eatom = k_eatom.view(); - Kokkos::View::value> > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_vatom = k_vatom.view(); if (EFLAG) { if (eflag_atom) { diff --git a/src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp b/src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp index 1ddf950fd7..3a1e02037a 100644 --- a/src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp +++ b/src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp @@ -389,7 +389,7 @@ KOKKOS_INLINE_FUNCTION void PairDPDfdtEnergyKokkos::operator()(TagPairDPDfdtEnergyComputeSplit, const int &ii, EV_FLOAT& ev) const { // The f array is atomic for Half/Thread neighbor style - Kokkos::View::value> > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_f = f; int i,j,jj,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; @@ -473,9 +473,9 @@ KOKKOS_INLINE_FUNCTION void PairDPDfdtEnergyKokkos::operator()(TagPairDPDfdtEnergyComputeNoSplit, const int &ii, EV_FLOAT& ev) const { // These array are atomic for Half/Thread neighbor style - Kokkos::View::value> > a_f = f; - Kokkos::View::value> > a_duCond = d_duCond; - Kokkos::View::value> > a_duMech = d_duMech; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_duCond = d_duCond; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_duMech = d_duMech; int i,j,jj,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; @@ -697,8 +697,8 @@ void PairDPDfdtEnergyKokkos::ev_tally(EV_FLOAT &ev, const int &i, co const int VFLAG = vflag_either; // The eatom and vatom arrays are atomic for Half/Thread neighbor style - Kokkos::View::value> > v_eatom = k_eatom.view(); - Kokkos::View::value> > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_vatom = k_vatom.view(); if (EFLAG) { if (eflag_atom) { diff --git a/src/KOKKOS/pair_eam_alloy_kokkos.h b/src/KOKKOS/pair_eam_alloy_kokkos.h index e1dd9ab47d..5796bdd1d4 100644 --- a/src/KOKKOS/pair_eam_alloy_kokkos.h +++ b/src/KOKKOS/pair_eam_alloy_kokkos.h @@ -129,14 +129,14 @@ class PairEAMAlloyKokkos : public PairEAM, public KokkosBase { typename ArrayTypes::t_virial_array d_vatom; int need_dup; - Kokkos::Experimental::ScatterView dup_rho; - Kokkos::Experimental::ScatterView dup_f; - Kokkos::Experimental::ScatterView dup_eatom; - Kokkos::Experimental::ScatterView dup_vatom; - Kokkos::Experimental::ScatterView ndup_rho; - Kokkos::Experimental::ScatterView ndup_f; - Kokkos::Experimental::ScatterView ndup_eatom; - Kokkos::Experimental::ScatterView ndup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_rho; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_rho; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_vatom; DAT::tdual_ffloat_1d k_rho; DAT::tdual_ffloat_1d k_fp; diff --git a/src/KOKKOS/pair_eam_fs_kokkos.h b/src/KOKKOS/pair_eam_fs_kokkos.h index e93977869e..64e1c78d56 100644 --- a/src/KOKKOS/pair_eam_fs_kokkos.h +++ b/src/KOKKOS/pair_eam_fs_kokkos.h @@ -129,14 +129,14 @@ class PairEAMFSKokkos : public PairEAM, public KokkosBase { typename ArrayTypes::t_virial_array d_vatom; int need_dup; - Kokkos::Experimental::ScatterView dup_rho; - Kokkos::Experimental::ScatterView dup_f; - Kokkos::Experimental::ScatterView dup_eatom; - Kokkos::Experimental::ScatterView dup_vatom; - Kokkos::Experimental::ScatterView ndup_rho; - Kokkos::Experimental::ScatterView ndup_f; - Kokkos::Experimental::ScatterView ndup_eatom; - Kokkos::Experimental::ScatterView ndup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_rho; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_rho; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_vatom; DAT::tdual_ffloat_1d k_rho; DAT::tdual_ffloat_1d k_fp; diff --git a/src/KOKKOS/pair_eam_kokkos.h b/src/KOKKOS/pair_eam_kokkos.h index 3bf89c549a..20bac4ed16 100644 --- a/src/KOKKOS/pair_eam_kokkos.h +++ b/src/KOKKOS/pair_eam_kokkos.h @@ -126,14 +126,14 @@ class PairEAMKokkos : public PairEAM, public KokkosBase { typename ArrayTypes::t_virial_array d_vatom; int need_dup; - Kokkos::Experimental::ScatterView dup_rho; - Kokkos::Experimental::ScatterView dup_f; - Kokkos::Experimental::ScatterView dup_eatom; - Kokkos::Experimental::ScatterView dup_vatom; - Kokkos::Experimental::ScatterView ndup_rho; - Kokkos::Experimental::ScatterView ndup_f; - Kokkos::Experimental::ScatterView ndup_eatom; - Kokkos::Experimental::ScatterView ndup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_rho; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_rho; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_vatom; DAT::tdual_ffloat_1d k_rho; DAT::tdual_ffloat_1d k_fp; diff --git a/src/KOKKOS/pair_exp6_rx_kokkos.cpp b/src/KOKKOS/pair_exp6_rx_kokkos.cpp index 4d72c85029..800ea81fa5 100644 --- a/src/KOKKOS/pair_exp6_rx_kokkos.cpp +++ b/src/KOKKOS/pair_exp6_rx_kokkos.cpp @@ -442,9 +442,9 @@ void PairExp6rxKokkos::operator()(TagPairExp6rxCompute::value> > a_f = f; - Kokkos::View::value> > a_uCG = uCG; - Kokkos::View::value> > a_uCGnew = uCGnew; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_uCG = uCG; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_uCGnew = uCGnew; int i,jj,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,evdwlOld,fpair; @@ -1183,9 +1183,9 @@ KOKKOS_INLINE_FUNCTION void PairExp6rxKokkos::vectorized_operator(const int &ii, EV_FLOAT& ev) const { // These arrays are atomic for Half/Thread neighbor style - Kokkos::View::value> > a_f = f; - Kokkos::View::value> > a_uCG = uCG; - Kokkos::View::value> > a_uCGnew = uCGnew; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_uCG = uCG; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_uCGnew = uCGnew; int tid = 0; #ifndef KOKKOS_ENABLE_CUDA @@ -2562,8 +2562,8 @@ void PairExp6rxKokkos::ev_tally(EV_FLOAT &ev, const int &i, const in const int VFLAG = vflag_either; // The eatom and vatom arrays are atomic for Half/Thread neighbor style - Kokkos::View::value> > v_eatom = k_eatom.view(); - Kokkos::View::value> > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_vatom = k_vatom.view(); if (EFLAG) { if (eflag_atom) { diff --git a/src/KOKKOS/pair_gran_hooke_history_kokkos.cpp b/src/KOKKOS/pair_gran_hooke_history_kokkos.cpp index 9e65c0589e..8797aab71e 100644 --- a/src/KOKKOS/pair_gran_hooke_history_kokkos.cpp +++ b/src/KOKKOS/pair_gran_hooke_history_kokkos.cpp @@ -320,8 +320,8 @@ KOKKOS_INLINE_FUNCTION void PairGranHookeHistoryKokkos::operator()(TagPairGranHookeHistoryCompute, const int ii, EV_FLOAT &ev) const { // The f and torque arrays are atomic for Half/Thread neighbor style - Kokkos::View::value> > a_f = f; - Kokkos::View::value> > a_torque = torque; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_torque = torque; const int i = d_ilist[ii]; const X_FLOAT xtmp = x(i,0); @@ -549,7 +549,7 @@ void PairGranHookeHistoryKokkos::ev_tally_xyz_atom(EV_FLOAT &ev, int F_FLOAT fx, F_FLOAT fy, F_FLOAT fz, X_FLOAT delx, X_FLOAT dely, X_FLOAT delz) const { - Kokkos::View::value> > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_vatom = k_vatom.view(); F_FLOAT v[6]; diff --git a/src/KOKKOS/pair_kokkos.h b/src/KOKKOS/pair_kokkos.h index 41922b7349..54035c54eb 100644 --- a/src/KOKKOS/pair_kokkos.h +++ b/src/KOKKOS/pair_kokkos.h @@ -66,17 +66,17 @@ struct PairComputeFunctor { // The force array is atomic for Half/Thread neighbor style //Kokkos::View::value> > f; - Kokkos::Experimental::ScatterView::value > dup_f; + // typename KKDevice::value,Kokkos::MemoryTraits::value> > f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,NeedDup::value > dup_f; // The eatom and vatom arrays are atomic for Half/Thread neighbor style //Kokkos::View::value> > eatom; - Kokkos::Experimental::ScatterView::value > dup_eatom; + // typename KKDevice::value,Kokkos::MemoryTraits::value> > eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,NeedDup::value > dup_eatom; //Kokkos::View::value> > vatom; - Kokkos::Experimental::ScatterView::value > dup_vatom; + // typename KKDevice::value,Kokkos::MemoryTraits::value> > vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,NeedDup::value > dup_vatom; diff --git a/src/KOKKOS/pair_multi_lucy_rx_kokkos.cpp b/src/KOKKOS/pair_multi_lucy_rx_kokkos.cpp index 3b7a738026..1c125b4dc0 100644 --- a/src/KOKKOS/pair_multi_lucy_rx_kokkos.cpp +++ b/src/KOKKOS/pair_multi_lucy_rx_kokkos.cpp @@ -270,7 +270,7 @@ KOKKOS_INLINE_FUNCTION void PairMultiLucyRXKokkos::operator()(TagPairMultiLucyRXCompute, const int &ii, EV_FLOAT& ev) const { // The f array is atomic for Half/Thread neighbor style - Kokkos::View::value> > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_f = f; int i,jj,jnum,itype,jtype,itable; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,evdwlOld,fpair; @@ -532,7 +532,7 @@ void PairMultiLucyRXKokkos::operator()(TagPairMultiLucyRXComputeLoca // The rho array is atomic for Half/Thread neighbor style - Kokkos::View::value> > a_rho = rho; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_rho = rho; const int i = d_ilist[ii]; @@ -771,8 +771,8 @@ void PairMultiLucyRXKokkos::ev_tally(EV_FLOAT &ev, const int &i, con const int VFLAG = vflag_either; // The eatom and vatom arrays are atomic for Half/Thread neighbor style - Kokkos::View::value> > v_eatom = k_eatom.view(); - Kokkos::View::value> > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_vatom = k_vatom.view(); if (EFLAG) { if (eflag_atom) { diff --git a/src/KOKKOS/pair_reaxc_kokkos.cpp b/src/KOKKOS/pair_reaxc_kokkos.cpp index 18144bb653..302ecbafd9 100644 --- a/src/KOKKOS/pair_reaxc_kokkos.cpp +++ b/src/KOKKOS/pair_reaxc_kokkos.cpp @@ -2477,7 +2477,7 @@ void PairReaxCKokkos::operator()(PairReaxComputeAngular::value,decltype(dup_f),decltype(ndup_f)>::get(dup_f,ndup_f); auto a_f = v_f.template access::value>(); - Kokkos::View::value> > a_Cdbo = d_Cdbo; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_Cdbo = d_Cdbo; auto v_CdDelta = ScatterViewHelper::value,decltype(dup_CdDelta),decltype(ndup_CdDelta)>::get(dup_CdDelta,ndup_CdDelta); auto a_CdDelta = v_CdDelta.template access::value>(); @@ -2792,7 +2792,7 @@ void PairReaxCKokkos::operator()(PairReaxComputeTorsion::value,decltype(dup_CdDelta),decltype(ndup_CdDelta)>::get(dup_CdDelta,ndup_CdDelta); auto a_CdDelta = v_CdDelta.template access::value>(); - Kokkos::View::value> > a_Cdbo = d_Cdbo; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_Cdbo = d_Cdbo; //auto a_Cdbo = dup_Cdbo.template access::value>(); // in reaxc_torsion_angles: j = i, k = j, i = k; @@ -3311,9 +3311,9 @@ template KOKKOS_INLINE_FUNCTION void PairReaxCKokkos::operator()(PairReaxUpdateBond, const int &ii) const { - Kokkos::View::value> > a_Cdbo = d_Cdbo; - Kokkos::View::value> > a_Cdbopi = d_Cdbopi; - Kokkos::View::value> > a_Cdbopi2 = d_Cdbopi2; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_Cdbo = d_Cdbo; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_Cdbopi = d_Cdbopi; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_Cdbopi2 = d_Cdbopi2; //auto a_Cdbo = dup_Cdbo.template access::value>(); //auto a_Cdbopi = dup_Cdbopi.template access::value>(); //auto a_Cdbopi2 = dup_Cdbopi2.template access::value>(); diff --git a/src/KOKKOS/pair_reaxc_kokkos.h b/src/KOKKOS/pair_reaxc_kokkos.h index 783ea33c4e..93ca4468ec 100644 --- a/src/KOKKOS/pair_reaxc_kokkos.h +++ b/src/KOKKOS/pair_reaxc_kokkos.h @@ -399,25 +399,25 @@ class PairReaxCKokkos : public PairReaxC { typename AT::t_ffloat_2d_dl d_C1dbopi2, d_C2dbopi2, d_C3dbopi2, d_C4dbopi2; typename AT::t_ffloat_2d_dl d_Cdbo, d_Cdbopi, d_Cdbopi2, d_dDeltap_self; - Kokkos::Experimental::ScatterView dup_total_bo; - Kokkos::Experimental::ScatterView dup_CdDelta; - Kokkos::Experimental::ScatterView dup_eatom; - Kokkos::Experimental::ScatterView dup_f; - Kokkos::Experimental::ScatterView dup_vatom; - Kokkos::Experimental::ScatterView dup_dDeltap_self; - Kokkos::Experimental::ScatterView dup_Cdbo; - Kokkos::Experimental::ScatterView dup_Cdbopi; - Kokkos::Experimental::ScatterView dup_Cdbopi2; - - Kokkos::Experimental::ScatterView ndup_total_bo; - Kokkos::Experimental::ScatterView ndup_CdDelta; - Kokkos::Experimental::ScatterView ndup_eatom; - Kokkos::Experimental::ScatterView ndup_f; - Kokkos::Experimental::ScatterView ndup_vatom; - Kokkos::Experimental::ScatterView ndup_dDeltap_self; - Kokkos::Experimental::ScatterView ndup_Cdbo; - Kokkos::Experimental::ScatterView ndup_Cdbopi; - Kokkos::Experimental::ScatterView ndup_Cdbopi2; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_total_bo; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_CdDelta; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_dDeltap_self; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_Cdbo; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_Cdbopi; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_Cdbopi2; + + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_total_bo; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_CdDelta; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_dDeltap_self; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_Cdbo; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_Cdbopi; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_Cdbopi2; int need_dup; diff --git a/src/KOKKOS/pair_snap_kokkos.h b/src/KOKKOS/pair_snap_kokkos.h index b57ef2d9e5..1fbb537f35 100644 --- a/src/KOKKOS/pair_snap_kokkos.h +++ b/src/KOKKOS/pair_snap_kokkos.h @@ -181,10 +181,10 @@ inline double dist2(double* x,double* y); typename AT::t_int_1d_randomread type; int need_dup; - Kokkos::Experimental::ScatterView dup_f; - Kokkos::Experimental::ScatterView dup_vatom; - Kokkos::Experimental::ScatterView ndup_f; - Kokkos::Experimental::ScatterView ndup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_vatom; friend void pair_virial_fdotr_compute(PairSNAPKokkos*); diff --git a/src/KOKKOS/pair_sw_kokkos.h b/src/KOKKOS/pair_sw_kokkos.h index 1a3f0b862f..2fc7f93c12 100644 --- a/src/KOKKOS/pair_sw_kokkos.h +++ b/src/KOKKOS/pair_sw_kokkos.h @@ -135,12 +135,12 @@ class PairSWKokkos : public PairSW { typename AT::t_virial_array d_vatom; int need_dup; - Kokkos::Experimental::ScatterView dup_f; - Kokkos::Experimental::ScatterView dup_eatom; - Kokkos::Experimental::ScatterView dup_vatom; - Kokkos::Experimental::ScatterView ndup_f; - Kokkos::Experimental::ScatterView ndup_eatom; - Kokkos::Experimental::ScatterView ndup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_vatom; typename AT::t_int_1d_randomread d_type2frho; typename AT::t_int_2d_randomread d_type2rhor; diff --git a/src/KOKKOS/pair_table_rx_kokkos.cpp b/src/KOKKOS/pair_table_rx_kokkos.cpp index cd7aa373ed..687489791e 100644 --- a/src/KOKKOS/pair_table_rx_kokkos.cpp +++ b/src/KOKKOS/pair_table_rx_kokkos.cpp @@ -284,11 +284,11 @@ ev_tally( F_FLOAT delx, F_FLOAT dely, F_FLOAT delz, Kokkos::View::t_virial_array::array_layout, - DeviceType, + typename KKDevice::value, Kokkos::MemoryTraits::value> > const& v_vatom, Kokkos::View::t_efloat_1d::array_layout, - DeviceType, + typename KKDevice::value, Kokkos::MemoryTraits::value> > const& v_eatom) { if (eflag) { @@ -399,15 +399,15 @@ compute_item( typename ArrayTypes::t_ffloat_2d const& d_cutsq, Kokkos::View::t_f_array::array_layout, - DeviceType, + typename KKDevice::value, Kokkos::MemoryTraits::value> > const& f, Kokkos::View::t_efloat_1d::array_layout, - DeviceType, + typename KKDevice::value, Kokkos::MemoryTraits::value> > const& uCG, Kokkos::View::t_efloat_1d::array_layout, - DeviceType, + typename KKDevice::value, Kokkos::MemoryTraits::value> > const& uCGnew, int isite1, int isite2, typename PairTableRXKokkos::TableDeviceConst const& d_table_const, @@ -418,11 +418,11 @@ compute_item( int vflag_atom, Kokkos::View::t_virial_array::array_layout, - DeviceType, + typename KKDevice::value, Kokkos::MemoryTraits::value> > const& v_vatom, Kokkos::View::t_efloat_1d::array_layout, - DeviceType, + typename KKDevice::value, Kokkos::MemoryTraits::value> > const& v_eatom) { EV_FLOAT ev; auto i = d_ilist(ii); @@ -544,14 +544,16 @@ static void compute_all_items( typename ArrayTypes::t_ffloat_2d d_cutsq, Kokkos::View::t_f_array::array_layout, - DeviceType, + typename KKDevice::value, Kokkos::MemoryTraits::value> > f, Kokkos::View::t_efloat_1d::array_layout, - DeviceType,Kokkos::MemoryTraits::value> > uCG, + typename KKDevice::value, + Kokkos::MemoryTraits::value> > uCG, Kokkos::View::t_efloat_1d::array_layout, - DeviceType,Kokkos::MemoryTraits::value> > uCGnew, + typename KKDevice::value, + Kokkos::MemoryTraits::value> > uCGnew, int isite1, int isite2, typename PairTableRXKokkos::TableDeviceConst d_table_const, int eflag, @@ -561,11 +563,11 @@ static void compute_all_items( int vflag_atom, Kokkos::View::t_virial_array::array_layout, - DeviceType, + typename KKDevice::value, Kokkos::MemoryTraits::value> > v_vatom, Kokkos::View::t_efloat_1d::array_layout, - DeviceType, + typename KKDevice::value, Kokkos::MemoryTraits::value> > v_eatom) { if (eflag || vflag) { Kokkos::parallel_reduce(inum, diff --git a/src/KOKKOS/pair_tersoff_kokkos.h b/src/KOKKOS/pair_tersoff_kokkos.h index 7d41fe2346..0c57e21a6c 100644 --- a/src/KOKKOS/pair_tersoff_kokkos.h +++ b/src/KOKKOS/pair_tersoff_kokkos.h @@ -202,12 +202,12 @@ class PairTersoffKokkos : public PairTersoff { typename ArrayTypes::t_virial_array d_vatom; int need_dup; - Kokkos::Experimental::ScatterView dup_f; - Kokkos::Experimental::ScatterView dup_eatom; - Kokkos::Experimental::ScatterView dup_vatom; - Kokkos::Experimental::ScatterView ndup_f; - Kokkos::Experimental::ScatterView ndup_eatom; - Kokkos::Experimental::ScatterView ndup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_vatom; typedef Kokkos::DualView tdual_ffloat_2d_n7; typedef typename tdual_ffloat_2d_n7::t_dev_const_randomread t_ffloat_2d_n7_randomread; diff --git a/src/KOKKOS/pair_tersoff_mod_kokkos.h b/src/KOKKOS/pair_tersoff_mod_kokkos.h index 889e1eadfa..b47f11e029 100644 --- a/src/KOKKOS/pair_tersoff_mod_kokkos.h +++ b/src/KOKKOS/pair_tersoff_mod_kokkos.h @@ -202,12 +202,12 @@ class PairTersoffMODKokkos : public PairTersoffMOD { typename ArrayTypes::t_virial_array d_vatom; int need_dup; - Kokkos::Experimental::ScatterView dup_f; - Kokkos::Experimental::ScatterView dup_eatom; - Kokkos::Experimental::ScatterView dup_vatom; - Kokkos::Experimental::ScatterView ndup_f; - Kokkos::Experimental::ScatterView ndup_eatom; - Kokkos::Experimental::ScatterView ndup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_vatom; typedef Kokkos::DualView tdual_ffloat_2d_n7; typedef typename tdual_ffloat_2d_n7::t_dev_const_randomread t_ffloat_2d_n7_randomread; diff --git a/src/KOKKOS/pair_tersoff_zbl_kokkos.h b/src/KOKKOS/pair_tersoff_zbl_kokkos.h index 0c7fa2e963..bed2564da5 100644 --- a/src/KOKKOS/pair_tersoff_zbl_kokkos.h +++ b/src/KOKKOS/pair_tersoff_zbl_kokkos.h @@ -207,12 +207,12 @@ class PairTersoffZBLKokkos : public PairTersoffZBL { typename ArrayTypes::t_virial_array d_vatom; int need_dup; - Kokkos::Experimental::ScatterView dup_f; - Kokkos::Experimental::ScatterView dup_eatom; - Kokkos::Experimental::ScatterView dup_vatom; - Kokkos::Experimental::ScatterView ndup_f; - Kokkos::Experimental::ScatterView ndup_eatom; - Kokkos::Experimental::ScatterView ndup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_vatom; typedef Kokkos::DualView tdual_ffloat_2d_n7; typedef typename tdual_ffloat_2d_n7::t_dev_const_randomread t_ffloat_2d_n7_randomread; diff --git a/src/KOKKOS/pair_vashishta_kokkos.cpp b/src/KOKKOS/pair_vashishta_kokkos.cpp index ddb0688e03..84887fa1f0 100644 --- a/src/KOKKOS/pair_vashishta_kokkos.cpp +++ b/src/KOKKOS/pair_vashishta_kokkos.cpp @@ -234,7 +234,7 @@ void PairVashishtaKokkos::operator()(TagPairVashishtaComputeHalf::value> > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_f = f; F_FLOAT delr1[3],delr2[3],fj[3],fk[3]; F_FLOAT evdwl = 0.0; @@ -780,8 +780,8 @@ void PairVashishtaKokkos::ev_tally(EV_FLOAT &ev, const int &i, const // The eatom and vatom arrays are atomic for half/thread neighbor list - Kokkos::View::value> > v_eatom = k_eatom.view(); - Kokkos::View::value> > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_vatom = k_vatom.view(); if (eflag_atom) { @@ -856,8 +856,8 @@ void PairVashishtaKokkos::ev_tally3(EV_FLOAT &ev, const int &i, cons // The eatom and vatom arrays are atomic for half/thread neighbor list - Kokkos::View::value> > v_eatom = k_eatom.view(); - Kokkos::View::value> > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_vatom = k_vatom.view(); if (eflag_atom) { epairthird = THIRD * (evdwl + ecoul); diff --git a/src/KOKKOS/pppm_kokkos.cpp b/src/KOKKOS/pppm_kokkos.cpp index 08a0c18f9c..b0f6f393cf 100644 --- a/src/KOKKOS/pppm_kokkos.cpp +++ b/src/KOKKOS/pppm_kokkos.cpp @@ -1670,7 +1670,7 @@ KOKKOS_INLINE_FUNCTION void PPPMKokkos::operator()(TagPPPM_make_rho_atomic, const int &i) const { // The density_brick array is atomic for Half/Thread neighbor style - Kokkos::View > a_density_brick = d_density_brick; + Kokkos::View::value,Kokkos::MemoryTraits > a_density_brick = d_density_brick; int nx = d_part2grid(i,0); int ny = d_part2grid(i,1); diff --git a/src/KOKKOS/sna_kokkos.h b/src/KOKKOS/sna_kokkos.h index a6d9db3218..b7162cf8d6 100644 --- a/src/KOKKOS/sna_kokkos.h +++ b/src/KOKKOS/sna_kokkos.h @@ -89,7 +89,7 @@ class SNAKokkos { public: typedef Kokkos::View t_sna_1i; typedef Kokkos::View t_sna_1d; - typedef Kokkos::View > t_sna_1d_atomic; + typedef Kokkos::View::value, Kokkos::MemoryTraits > t_sna_1d_atomic; typedef Kokkos::View t_sna_2i; typedef Kokkos::View t_sna_2d; typedef Kokkos::View t_sna_2d_ll; @@ -99,7 +99,7 @@ public: typedef Kokkos::View t_sna_5d; typedef Kokkos::View t_sna_1c; - typedef Kokkos::View > t_sna_1c_atomic; + typedef Kokkos::View::value, Kokkos::MemoryTraits > t_sna_1c_atomic; typedef Kokkos::View t_sna_2c; typedef Kokkos::View t_sna_2c_ll; typedef Kokkos::View t_sna_2c_lr; -- GitLab From 60864e38d1d5f34db0ff379bf71eab0da0ca1ed0 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Wed, 25 Mar 2020 14:08:39 -0600 Subject: [PATCH 417/689] Update Kokkos library in LAMMPS to v3.0 --- lib/kokkos/BUILD.md | 323 + lib/kokkos/CHANGELOG.md | 40 + lib/kokkos/CMakeLists.txt | 327 +- lib/kokkos/CONTRIBUTING.md | 14 + lib/kokkos/Copyright.txt | 11 +- lib/kokkos/LICENSE | 11 +- lib/kokkos/Makefile.kokkos | 132 +- lib/kokkos/Makefile.targets | 2 + lib/kokkos/README | 193 - lib/kokkos/README.md | 299 + lib/kokkos/algorithms/CMakeLists.txt | 24 +- lib/kokkos/algorithms/src/CMakeLists.txt | 27 +- lib/kokkos/algorithms/src/Kokkos_Random.hpp | 2683 ++++---- lib/kokkos/algorithms/src/Kokkos_Sort.hpp | 667 +- .../algorithms/unit_tests/CMakeLists.txt | 39 +- lib/kokkos/algorithms/unit_tests/TestCuda.cpp | 55 +- lib/kokkos/algorithms/unit_tests/TestHPX.cpp | 53 +- .../algorithms/unit_tests/TestOpenMP.cpp | 51 +- lib/kokkos/algorithms/unit_tests/TestROCm.cpp | 62 +- .../algorithms/unit_tests/TestRandom.hpp | 511 +- .../algorithms/unit_tests/TestSerial.cpp | 54 +- lib/kokkos/algorithms/unit_tests/TestSort.hpp | 298 +- .../algorithms/unit_tests/TestThreads.cpp | 54 +- .../algorithms/unit_tests/UnitTestMain.cpp | 16 +- lib/kokkos/benchmarks/atomic/main.cpp | 202 +- .../benchmarks/bytes_and_flops/bench.hpp | 72 +- .../bytes_and_flops/bench_stride.hpp | 121 +- .../bytes_and_flops/bench_unroll_stride.hpp | 181 +- .../benchmarks/bytes_and_flops/main.cpp | 54 +- lib/kokkos/benchmarks/gather/gather.hpp | 55 +- .../benchmarks/gather/gather_unroll.hpp | 202 +- lib/kokkos/benchmarks/gather/main.cpp | 54 +- lib/kokkos/benchmarks/gups/gups-kokkos.cc | 11 +- .../benchmarks/policy_performance/main.cpp | 179 +- .../policy_performance/policy_perf_test.hpp | 570 +- .../policy_performance/script_sample_usage.sh | 2 +- lib/kokkos/benchmarks/stream/stream-kokkos.cc | 11 +- lib/kokkos/bin/hpcbind | 2 +- lib/kokkos/bin/nvcc_wrapper | 77 +- lib/kokkos/cm_generate_makefile.bash | 339 + lib/kokkos/cmake/KokkosConfig.cmake.in | 26 +- lib/kokkos/cmake/KokkosConfigCommon.cmake.in | 87 + lib/kokkos/cmake/KokkosCore_config.h.in | 89 + .../cmake/Makefile.generate_cmake_settings | 8 - lib/kokkos/cmake/Modules/FindHWLOC.cmake | 20 - lib/kokkos/cmake/Modules/FindMemkind.cmake | 20 - lib/kokkos/cmake/Modules/FindQthreads.cmake | 20 - lib/kokkos/cmake/Modules/FindTPLCUDA.cmake | 13 + lib/kokkos/cmake/Modules/FindTPLHPX.cmake | 15 + lib/kokkos/cmake/Modules/FindTPLHWLOC.cmake | 1 + lib/kokkos/cmake/Modules/FindTPLLIBDL.cmake | 1 + lib/kokkos/cmake/Modules/FindTPLLIBNUMA.cmake | 1 + lib/kokkos/cmake/Modules/FindTPLLIBRT.cmake | 1 + lib/kokkos/cmake/Modules/FindTPLMEMKIND.cmake | 1 + lib/kokkos/cmake/Modules/FindTPLPTHREAD.cmake | 17 + lib/kokkos/cmake/README.md | 331 + lib/kokkos/cmake/compile_tests/clang_omp.cpp | 9 + lib/kokkos/cmake/compile_tests/pthread.cpp | 10 + lib/kokkos/cmake/cray.cmake | 9 + lib/kokkos/cmake/deps/CUDA.cmake | 2 +- lib/kokkos/cmake/deps/CUSPARSE.cmake | 2 +- lib/kokkos/cmake/deps/HWLOC.cmake | 2 +- lib/kokkos/cmake/deps/Pthread.cmake | 4 +- lib/kokkos/cmake/deps/QTHREADS.cmake | 69 - lib/kokkos/cmake/fake_tribits.cmake | 338 + lib/kokkos/cmake/gnu.cmake | 23 + lib/kokkos/cmake/intel.cmake | 30 + lib/kokkos/cmake/kokkos_arch.cmake | 438 ++ lib/kokkos/cmake/kokkos_build.cmake | 261 - lib/kokkos/cmake/kokkos_compiler_id.cmake | 80 + lib/kokkos/cmake/kokkos_corner_cases.cmake | 35 + lib/kokkos/cmake/kokkos_enable_devices.cmake | 61 + lib/kokkos/cmake/kokkos_enable_options.cmake | 92 + lib/kokkos/cmake/kokkos_functions.cmake | 1033 ++- lib/kokkos/cmake/kokkos_install.cmake | 42 + lib/kokkos/cmake/kokkos_options.cmake | 419 -- lib/kokkos/cmake/kokkos_pick_cxx_std.cmake | 46 + lib/kokkos/cmake/kokkos_settings.cmake | 259 - lib/kokkos/cmake/kokkos_test_cxx_std.cmake | 144 + lib/kokkos/cmake/kokkos_tpls.cmake | 47 + lib/kokkos/cmake/kokkos_tribits.cmake | 392 ++ lib/kokkos/cmake/pgi.cmake | 8 + lib/kokkos/cmake/tpls/FindTPLCUSPARSE.cmake | 2 +- lib/kokkos/cmake/tpls/FindTPLHWLOC.cmake | 2 +- lib/kokkos/cmake/tpls/FindTPLPthread.cmake | 2 +- lib/kokkos/cmake/tpls/FindTPLQTHREADS.cmake | 69 - lib/kokkos/cmake/tribits.cmake | 531 -- lib/kokkos/containers/CMakeLists.txt | 23 +- .../performance_tests/CMakeLists.txt | 91 +- .../containers/performance_tests/TestCuda.cpp | 48 +- .../performance_tests/TestDynRankView.hpp | 159 +- .../performance_tests/TestGlobal2LocalIds.hpp | 138 +- .../containers/performance_tests/TestHPX.cpp | 68 +- .../containers/performance_tests/TestMain.cpp | 14 +- .../performance_tests/TestOpenMP.cpp | 79 +- .../containers/performance_tests/TestROCm.cpp | 38 +- .../performance_tests/TestScatterView.hpp | 112 +- .../performance_tests/TestThreads.cpp | 55 +- .../TestUnorderedMapPerformance.hpp | 100 +- lib/kokkos/containers/src/CMakeLists.txt | 81 +- lib/kokkos/containers/src/Kokkos_Bitset.hpp | 348 +- lib/kokkos/containers/src/Kokkos_DualView.hpp | 830 +-- .../containers/src/Kokkos_DynRankView.hpp | 3176 +++++----- .../containers/src/Kokkos_DynamicView.hpp | 719 +-- .../containers/src/Kokkos_ErrorReporter.hpp | 111 +- .../containers/src/Kokkos_Functional.hpp | 85 +- .../containers/src/Kokkos_OffsetView.hpp | 3802 +++++------ .../containers/src/Kokkos_ScatterView.hpp | 1535 +++-- .../containers/src/Kokkos_StaticCrsGraph.hpp | 430 +- .../containers/src/Kokkos_UnorderedMap.hpp | 621 +- lib/kokkos/containers/src/Kokkos_Vector.hpp | 294 +- .../src/impl/Kokkos_Bitset_impl.hpp | 60 +- .../src/impl/Kokkos_Functional_impl.hpp | 113 +- .../impl/Kokkos_StaticCrsGraph_factory.hpp | 253 +- .../src/impl/Kokkos_UnorderedMap_impl.cpp | 105 +- .../src/impl/Kokkos_UnorderedMap_impl.hpp | 169 +- .../containers/unit_tests/CMakeLists.txt | 171 +- .../containers/unit_tests/TestBitset.hpp | 183 +- .../containers/unit_tests/TestDualView.hpp | 271 +- .../containers/unit_tests/TestDynViewAPI.hpp | 2425 +++---- .../unit_tests/TestDynViewAPI_generic.hpp | 20 +- .../unit_tests/TestDynViewAPI_rank12345.hpp | 20 +- .../unit_tests/TestDynViewAPI_rank67.hpp | 20 +- .../containers/unit_tests/TestDynamicView.hpp | 259 +- .../unit_tests/TestErrorReporter.hpp | 146 +- .../containers/unit_tests/TestOffsetView.hpp | 933 ++- .../containers/unit_tests/TestScatterView.hpp | 672 +- .../unit_tests/TestStaticCrsGraph.hpp | 306 +- .../unit_tests/TestUnorderedMap.hpp | 276 +- .../containers/unit_tests/TestVector.hpp | 235 +- .../TestViewCtorPropEmbeddedDim.hpp | 173 +- .../containers/unit_tests/UnitTestMain.cpp | 17 +- .../unit_tests/cuda/TestCuda_BitSet.cpp | 16 +- .../unit_tests/cuda/TestCuda_Category.hpp | 26 +- .../unit_tests/cuda/TestCuda_DualView.cpp | 16 +- .../cuda/TestCuda_DynRankViewAPI_generic.cpp | 16 +- .../TestCuda_DynRankViewAPI_rank12345.cpp | 16 +- .../cuda/TestCuda_DynRankViewAPI_rank67.cpp | 16 +- .../unit_tests/cuda/TestCuda_DynamicView.cpp | 16 +- .../cuda/TestCuda_ErrorReporter.cpp | 16 +- .../unit_tests/cuda/TestCuda_OffsetView.cpp | 16 +- .../unit_tests/cuda/TestCuda_ScatterView.cpp | 16 +- .../cuda/TestCuda_StaticCrsGraph.cpp | 16 +- .../unit_tests/cuda/TestCuda_UnorderedMap.cpp | 16 +- .../unit_tests/cuda/TestCuda_Vector.cpp | 16 +- .../cuda/TestCuda_ViewCtorPropEmbeddedDim.cpp | 16 +- .../unit_tests/hpx/TestHPX_BitSet.cpp | 16 +- .../unit_tests/hpx/TestHPX_Category.hpp | 26 +- .../unit_tests/hpx/TestHPX_DualView.cpp | 16 +- .../hpx/TestHPX_DynRankViewAPI_generic.cpp | 16 +- .../hpx/TestHPX_DynRankViewAPI_rank12345.cpp | 16 +- .../hpx/TestHPX_DynRankViewAPI_rank67.cpp | 16 +- .../unit_tests/hpx/TestHPX_DynamicView.cpp | 16 +- .../unit_tests/hpx/TestHPX_ErrorReporter.cpp | 16 +- .../unit_tests/hpx/TestHPX_OffsetView.cpp | 16 +- .../unit_tests/hpx/TestHPX_ScatterView.cpp | 16 +- .../unit_tests/hpx/TestHPX_StaticCrsGraph.cpp | 16 +- .../unit_tests/hpx/TestHPX_UnorderedMap.cpp | 16 +- .../unit_tests/hpx/TestHPX_Vector.cpp | 16 +- .../hpx/TestHPX_ViewCtorPropEmbeddedDim.cpp | 16 +- .../unit_tests/openmp/TestOpenMP_BitSet.cpp | 16 +- .../unit_tests/openmp/TestOpenMP_Category.hpp | 26 +- .../unit_tests/openmp/TestOpenMP_DualView.cpp | 16 +- .../TestOpenMP_DynRankViewAPI_generic.cpp | 16 +- .../TestOpenMP_DynRankViewAPI_rank12345.cpp | 16 +- .../TestOpenMP_DynRankViewAPI_rank67.cpp | 16 +- .../openmp/TestOpenMP_DynamicView.cpp | 16 +- .../openmp/TestOpenMP_ErrorReporter.cpp | 16 +- .../openmp/TestOpenMP_OffsetView.cpp | 16 +- .../openmp/TestOpenMP_ScatterView.cpp | 16 +- .../openmp/TestOpenMP_StaticCrsGraph.cpp | 16 +- .../openmp/TestOpenMP_UnorderedMap.cpp | 16 +- .../unit_tests/openmp/TestOpenMP_Vector.cpp | 16 +- .../TestOpenMP_ViewCtorPropEmbeddedDim.cpp | 16 +- .../unit_tests/rocm/TestROCm_BitSet.cpp | 16 +- .../unit_tests/rocm/TestROCm_Category.hpp | 26 +- .../unit_tests/rocm/TestROCm_DualView.cpp | 16 +- .../rocm/TestROCm_DynRankViewAPI_generic.cpp | 16 +- .../TestROCm_DynRankViewAPI_rank12345.cpp | 16 +- .../rocm/TestROCm_DynRankViewAPI_rank67.cpp | 16 +- .../unit_tests/rocm/TestROCm_DynamicView.cpp | 16 +- .../rocm/TestROCm_ErrorReporter.cpp | 16 +- .../unit_tests/rocm/TestROCm_ScatterView.cpp | 16 +- .../rocm/TestROCm_StaticCrsGraph.cpp | 16 +- .../unit_tests/rocm/TestROCm_UnorderedMap.cpp | 16 +- .../unit_tests/rocm/TestROCm_Vector.cpp | 16 +- .../rocm/TestROCm_ViewCtorPropEmbeddedDim.cpp | 16 +- .../unit_tests/serial/TestSerial_BitSet.cpp | 16 +- .../unit_tests/serial/TestSerial_Category.hpp | 26 +- .../unit_tests/serial/TestSerial_DualView.cpp | 16 +- .../TestSerial_DynRankViewAPI_generic.cpp | 16 +- .../TestSerial_DynRankViewAPI_rank12345.cpp | 16 +- .../TestSerial_DynRankViewAPI_rank67.cpp | 16 +- .../serial/TestSerial_DynamicView.cpp | 16 +- .../serial/TestSerial_ErrorReporter.cpp | 16 +- .../serial/TestSerial_OffsetView.cpp | 16 +- .../serial/TestSerial_ScatterView.cpp | 16 +- .../serial/TestSerial_StaticCrsGraph.cpp | 16 +- .../serial/TestSerial_UnorderedMap.cpp | 16 +- .../unit_tests/serial/TestSerial_Vector.cpp | 16 +- .../TestSerial_ViewCtorPropEmbeddedDim.cpp | 16 +- .../unit_tests/threads/TestThreads_BitSet.cpp | 16 +- .../threads/TestThreads_Category.hpp | 26 +- .../threads/TestThreads_DualView.cpp | 16 +- .../TestThreads_DynRankViewAPI_generic.cpp | 16 +- .../TestThreads_DynRankViewAPI_rank12345.cpp | 16 +- .../TestThreads_DynRankViewAPI_rank67.cpp | 16 +- .../threads/TestThreads_DynamicView.cpp | 16 +- .../threads/TestThreads_ErrorReporter.cpp | 16 +- .../threads/TestThreads_OffsetView.cpp | 16 +- .../threads/TestThreads_ScatterView.cpp | 16 +- .../threads/TestThreads_StaticCrsGraph.cpp | 16 +- .../threads/TestThreads_UnorderedMap.cpp | 16 +- .../unit_tests/threads/TestThreads_Vector.cpp | 16 +- .../TestThreads_ViewCtorPropEmbeddedDim.cpp | 16 +- lib/kokkos/core/CMakeLists.txt | 25 +- lib/kokkos/core/cmake/KokkosCore_config.h.in | 3 +- lib/kokkos/core/perf_test/CMakeLists.txt | 80 +- .../core/perf_test/PerfTestBlasKernels.hpp | 254 +- lib/kokkos/core/perf_test/PerfTestDriver.hpp | 545 +- .../core/perf_test/PerfTestGramSchmidt.cpp | 282 +- lib/kokkos/core/perf_test/PerfTestHexGrad.cpp | 437 +- lib/kokkos/core/perf_test/PerfTestMDRange.hpp | 762 +-- lib/kokkos/core/perf_test/PerfTestMain.cpp | 31 +- .../core/perf_test/PerfTest_Category.hpp | 22 +- .../perf_test/PerfTest_CustomReduction.cpp | 128 +- .../PerfTest_ExecSpacePartitioning.cpp | 1046 ++-- .../core/perf_test/PerfTest_ViewAllocate.cpp | 125 +- .../core/perf_test/PerfTest_ViewCopy.hpp | 268 +- .../core/perf_test/PerfTest_ViewCopy_a123.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_a45.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_a6.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_a7.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_a8.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_b123.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_b45.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_b6.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_b7.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_b8.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_c123.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_c45.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_c6.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_c7.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_c8.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_d123.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_d45.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_d6.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_d7.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_d8.cpp | 19 +- .../core/perf_test/PerfTest_ViewFill.hpp | 232 +- .../core/perf_test/PerfTest_ViewFill_123.cpp | 19 +- .../core/perf_test/PerfTest_ViewFill_45.cpp | 19 +- .../core/perf_test/PerfTest_ViewFill_6.cpp | 19 +- .../core/perf_test/PerfTest_ViewFill_7.cpp | 19 +- .../core/perf_test/PerfTest_ViewFill_8.cpp | 19 +- .../core/perf_test/PerfTest_ViewResize.hpp | 381 +- .../perf_test/PerfTest_ViewResize_123.cpp | 19 +- .../core/perf_test/PerfTest_ViewResize_45.cpp | 19 +- .../core/perf_test/PerfTest_ViewResize_6.cpp | 19 +- .../core/perf_test/PerfTest_ViewResize_7.cpp | 19 +- .../core/perf_test/PerfTest_ViewResize_8.cpp | 19 +- lib/kokkos/core/perf_test/test_atomic.cpp | 460 +- lib/kokkos/core/perf_test/test_mempool.cpp | 360 +- lib/kokkos/core/perf_test/test_taskdag.cpp | 264 +- lib/kokkos/core/src/CMakeLists.txt | 205 +- .../src/Cuda/KokkosExp_Cuda_IterateTile.hpp | 1757 +++--- .../KokkosExp_Cuda_IterateTile_Refactor.hpp | 3352 +++++----- lib/kokkos/core/src/Cuda/Kokkos_CudaSpace.cpp | 1054 ++-- .../core/src/Cuda/Kokkos_Cuda_Alloc.hpp | 119 +- .../Cuda/Kokkos_Cuda_Atomic_Intrinsics.hpp | 1289 ++-- ...uda_Atomic_Intrinsics_Restore_Builtins.hpp | 10 +- .../Cuda/Kokkos_Cuda_BlockSize_Deduction.hpp | 704 ++- .../core/src/Cuda/Kokkos_Cuda_Error.hpp | 91 +- .../core/src/Cuda/Kokkos_Cuda_Instance.cpp | 848 +-- .../core/src/Cuda/Kokkos_Cuda_Instance.hpp | 213 +- .../src/Cuda/Kokkos_Cuda_KernelLaunch.hpp | 599 +- .../core/src/Cuda/Kokkos_Cuda_Locks.cpp | 45 +- .../core/src/Cuda/Kokkos_Cuda_Locks.hpp | 92 +- .../core/src/Cuda/Kokkos_Cuda_Parallel.hpp | 3816 ++++++----- .../core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp | 1183 ++-- lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.cpp | 28 +- lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.hpp | 1115 ++-- lib/kokkos/core/src/Cuda/Kokkos_Cuda_Team.hpp | 1119 ++-- .../core/src/Cuda/Kokkos_Cuda_UniqueToken.hpp | 123 +- .../src/Cuda/Kokkos_Cuda_Vectorization.hpp | 484 +- .../Kokkos_Cuda_Version_9_8_Compatibility.hpp | 123 +- lib/kokkos/core/src/Cuda/Kokkos_Cuda_View.hpp | 330 +- .../src/Cuda/Kokkos_Cuda_ViewCopyETIAvail.hpp | 18 +- .../src/Cuda/Kokkos_Cuda_ViewCopyETIDecl.hpp | 18 +- .../src/Cuda/Kokkos_Cuda_WorkGraphPolicy.hpp | 109 +- .../core/src/Cuda/Kokkos_Cuda_abort.hpp | 40 +- lib/kokkos/core/src/HPX/Kokkos_HPX.cpp | 31 +- .../Kokkos_HPX_ChunkedRoundRobinExecutor.hpp | 208 + lib/kokkos/core/src/HPX/Kokkos_HPX_Task.cpp | 17 +- lib/kokkos/core/src/HPX/Kokkos_HPX_Task.hpp | 81 +- .../src/HPX/Kokkos_HPX_ViewCopyETIAvail.hpp | 18 +- .../src/HPX/Kokkos_HPX_ViewCopyETIDecl.hpp | 18 +- .../src/HPX/Kokkos_HPX_WorkGraphPolicy.hpp | 36 +- .../core/src/KokkosExp_MDRangePolicy.hpp | 727 +-- lib/kokkos/core/src/Kokkos_AnonymousSpace.hpp | 74 +- lib/kokkos/core/src/Kokkos_Array.hpp | 426 +- lib/kokkos/core/src/Kokkos_Atomic.hpp | 118 +- lib/kokkos/core/src/Kokkos_Complex.hpp | 1000 ++- lib/kokkos/core/src/Kokkos_Concepts.hpp | 422 +- lib/kokkos/core/src/Kokkos_CopyViews.hpp | 4466 +++++++------ lib/kokkos/core/src/Kokkos_Core.hpp | 149 +- lib/kokkos/core/src/Kokkos_Core_fwd.hpp | 330 +- lib/kokkos/core/src/Kokkos_Crs.hpp | 331 +- lib/kokkos/core/src/Kokkos_Cuda.hpp | 175 +- lib/kokkos/core/src/Kokkos_CudaSpace.hpp | 936 ++- lib/kokkos/core/src/Kokkos_ExecPolicy.hpp | 1080 ++-- lib/kokkos/core/src/Kokkos_Extents.hpp | 110 +- lib/kokkos/core/src/Kokkos_Future.hpp | 495 +- lib/kokkos/core/src/Kokkos_HBWSpace.hpp | 272 +- lib/kokkos/core/src/Kokkos_HPX.hpp | 1016 +-- lib/kokkos/core/src/Kokkos_HostSpace.hpp | 245 +- lib/kokkos/core/src/Kokkos_Layout.hpp | 325 +- lib/kokkos/core/src/Kokkos_Macros.hpp | 722 +-- lib/kokkos/core/src/Kokkos_MasterLock.hpp | 20 +- lib/kokkos/core/src/Kokkos_MemoryPool.hpp | 1138 ++-- lib/kokkos/core/src/Kokkos_MemoryTraits.hpp | 99 +- lib/kokkos/core/src/Kokkos_NumericTraits.hpp | 424 +- lib/kokkos/core/src/Kokkos_OpenMP.hpp | 139 +- lib/kokkos/core/src/Kokkos_OpenMPTarget.hpp | 83 +- .../core/src/Kokkos_OpenMPTargetSpace.hpp | 215 +- lib/kokkos/core/src/Kokkos_Pair.hpp | 319 +- lib/kokkos/core/src/Kokkos_Parallel.hpp | 404 +- .../core/src/Kokkos_Parallel_Reduce.hpp | 1143 ++-- .../core/src/Kokkos_PointerOwnership.hpp | 16 +- .../src/Kokkos_Profiling_ProfileSection.hpp | 175 +- lib/kokkos/core/src/Kokkos_Qthreads.hpp | 77 +- lib/kokkos/core/src/Kokkos_ROCm.hpp | 169 +- lib/kokkos/core/src/Kokkos_ROCmSpace.hpp | 617 +- lib/kokkos/core/src/Kokkos_ScratchSpace.hpp | 186 +- lib/kokkos/core/src/Kokkos_Serial.hpp | 1495 +++-- lib/kokkos/core/src/Kokkos_TaskPolicy.hpp | 20 +- lib/kokkos/core/src/Kokkos_TaskScheduler.hpp | 749 +-- .../core/src/Kokkos_TaskScheduler_fwd.hpp | 159 +- lib/kokkos/core/src/Kokkos_Threads.hpp | 117 +- lib/kokkos/core/src/Kokkos_Timer.hpp | 41 +- lib/kokkos/core/src/Kokkos_UniqueToken.hpp | 44 +- lib/kokkos/core/src/Kokkos_Vectorization.hpp | 14 +- lib/kokkos/core/src/Kokkos_View.hpp | 3779 ++++++----- .../core/src/Kokkos_WorkGraphPolicy.hpp | 200 +- lib/kokkos/core/src/Kokkos_hwloc.hpp | 34 +- lib/kokkos/core/src/Makefile | 117 - .../core/src/Makefile.generate_build_files | 125 - .../core/src/Makefile.generate_header_lists | 32 - .../core/src/OpenMP/Kokkos_OpenMP_Exec.cpp | 406 +- .../core/src/OpenMP/Kokkos_OpenMP_Exec.hpp | 326 +- .../src/OpenMP/Kokkos_OpenMP_Parallel.hpp | 1706 +++-- .../core/src/OpenMP/Kokkos_OpenMP_Task.cpp | 80 +- .../core/src/OpenMP/Kokkos_OpenMP_Task.hpp | 306 +- .../core/src/OpenMP/Kokkos_OpenMP_Team.hpp | 404 +- .../OpenMP/Kokkos_OpenMP_ViewCopyETIAvail.hpp | 18 +- .../OpenMP/Kokkos_OpenMP_ViewCopyETIDecl.hpp | 18 +- .../OpenMP/Kokkos_OpenMP_WorkGraphPolicy.hpp | 80 +- .../OpenMPTarget/Kokkos_OpenMPTargetSpace.cpp | 296 +- .../OpenMPTarget/Kokkos_OpenMPTarget_Exec.cpp | 249 +- .../OpenMPTarget/Kokkos_OpenMPTarget_Exec.hpp | 872 +-- .../Kokkos_OpenMPTarget_Parallel.hpp | 1150 ++-- .../OpenMPTarget/Kokkos_OpenMPTarget_Task.cpp | 235 +- .../OpenMPTarget/Kokkos_OpenMPTarget_Task.hpp | 340 +- .../core/src/Qthreads/Kokkos_QthreadsExec.cpp | 454 +- .../core/src/Qthreads/Kokkos_QthreadsExec.hpp | 614 +- .../src/Qthreads/Kokkos_Qthreads_Parallel.hpp | 945 +-- .../src/Qthreads/Kokkos_Qthreads_Task.cpp | 224 +- .../src/Qthreads/Kokkos_Qthreads_Task.hpp | 122 +- .../Kokkos_Qthreads_TaskPolicy.hpp.old | 2 +- .../Qthreads/Kokkos_Qthreads_TaskQueue.hpp | 290 +- .../Kokkos_Qthreads_TaskQueue_impl.hpp | 311 +- .../KokkosExp_ROCm_IterateTile_Refactor.hpp | 3256 +++++----- .../core/src/ROCm/Kokkos_ROCm_Atomic.hpp | 826 +-- .../core/src/ROCm/Kokkos_ROCm_Config.hpp | 11 +- lib/kokkos/core/src/ROCm/Kokkos_ROCm_Exec.cpp | 76 +- lib/kokkos/core/src/ROCm/Kokkos_ROCm_Exec.hpp | 212 +- lib/kokkos/core/src/ROCm/Kokkos_ROCm_Impl.cpp | 748 ++- .../core/src/ROCm/Kokkos_ROCm_Invoke.hpp | 122 +- lib/kokkos/core/src/ROCm/Kokkos_ROCm_Join.hpp | 32 +- .../core/src/ROCm/Kokkos_ROCm_Parallel.hpp | 2543 ++++---- .../core/src/ROCm/Kokkos_ROCm_Reduce.hpp | 162 +- .../core/src/ROCm/Kokkos_ROCm_ReduceScan.hpp | 501 +- lib/kokkos/core/src/ROCm/Kokkos_ROCm_Scan.hpp | 329 +- .../core/src/ROCm/Kokkos_ROCm_Space.cpp | 745 ++- lib/kokkos/core/src/ROCm/Kokkos_ROCm_Task.cpp | 118 +- lib/kokkos/core/src/ROCm/Kokkos_ROCm_Task.hpp | 489 +- lib/kokkos/core/src/ROCm/Kokkos_ROCm_Tile.hpp | 628 +- .../src/ROCm/Kokkos_ROCm_Vectorization.hpp | 512 +- .../src/ROCm/Kokkos_ROCm_ViewCopyETIAvail.hpp | 18 +- .../src/ROCm/Kokkos_ROCm_ViewCopyETIDecl.hpp | 18 +- lib/kokkos/core/src/ROCm/hc_math_std.hpp | 426 +- .../Serial/Kokkos_Serial_ViewCopyETIAvail.hpp | 18 +- .../Serial/Kokkos_Serial_ViewCopyETIDecl.hpp | 18 +- .../core/src/Threads/Kokkos_ThreadsExec.cpp | 828 ++- .../core/src/Threads/Kokkos_ThreadsExec.hpp | 791 +-- .../src/Threads/Kokkos_ThreadsExec_base.cpp | 158 +- .../core/src/Threads/Kokkos_ThreadsTeam.hpp | 1389 ++-- .../src/Threads/Kokkos_Threads_Parallel.hpp | 1412 ++--- .../Kokkos_Threads_ViewCopyETIAvail.hpp | 18 +- .../Kokkos_Threads_ViewCopyETIDecl.hpp | 18 +- .../Kokkos_Threads_WorkGraphPolicy.hpp | 103 +- lib/kokkos/core/src/dummy.cpp | 10 + ...TIInst_int64_t_double_LayoutLeft_Rank1.cpp | 33 +- ...TIInst_int64_t_double_LayoutLeft_Rank2.cpp | 33 +- ...TIInst_int64_t_double_LayoutLeft_Rank3.cpp | 34 +- ...TIInst_int64_t_double_LayoutLeft_Rank4.cpp | 35 +- ...TIInst_int64_t_double_LayoutLeft_Rank5.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank8.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank1.cpp | 33 +- ...IInst_int64_t_double_LayoutRight_Rank2.cpp | 34 +- ...IInst_int64_t_double_LayoutRight_Rank3.cpp | 35 +- ...IInst_int64_t_double_LayoutRight_Rank4.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank5.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank8.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank1.cpp | 34 +- ...Inst_int64_t_double_LayoutStride_Rank2.cpp | 35 +- ...Inst_int64_t_double_LayoutStride_Rank3.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank4.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank5.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank8.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank1.cpp | 33 +- ...ETIInst_int64_t_float_LayoutLeft_Rank2.cpp | 33 +- ...ETIInst_int64_t_float_LayoutLeft_Rank3.cpp | 33 +- ...ETIInst_int64_t_float_LayoutLeft_Rank4.cpp | 34 +- ...ETIInst_int64_t_float_LayoutLeft_Rank5.cpp | 35 +- ...ETIInst_int64_t_float_LayoutLeft_Rank8.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank1.cpp | 33 +- ...TIInst_int64_t_float_LayoutRight_Rank2.cpp | 33 +- ...TIInst_int64_t_float_LayoutRight_Rank3.cpp | 34 +- ...TIInst_int64_t_float_LayoutRight_Rank4.cpp | 35 +- ...TIInst_int64_t_float_LayoutRight_Rank5.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank8.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank1.cpp | 33 +- ...IInst_int64_t_float_LayoutStride_Rank2.cpp | 34 +- ...IInst_int64_t_float_LayoutStride_Rank3.cpp | 35 +- ...IInst_int64_t_float_LayoutStride_Rank4.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank5.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank8.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank1.cpp | 33 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank2.cpp | 34 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank3.cpp | 35 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank4.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank5.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank8.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank1.cpp | 34 +- ...Inst_int64_t_int64_t_LayoutRight_Rank2.cpp | 35 +- ...Inst_int64_t_int64_t_LayoutRight_Rank3.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank4.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank5.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank8.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank1.cpp | 35 +- ...nst_int64_t_int64_t_LayoutStride_Rank2.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank3.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank4.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank5.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank8.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank1.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank2.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank3.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank4.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank5.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank8.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank1.cpp | 33 +- ...yETIInst_int64_t_int_LayoutRight_Rank2.cpp | 33 +- ...yETIInst_int64_t_int_LayoutRight_Rank3.cpp | 33 +- ...yETIInst_int64_t_int_LayoutRight_Rank4.cpp | 33 +- ...yETIInst_int64_t_int_LayoutRight_Rank5.cpp | 34 +- ...yETIInst_int64_t_int_LayoutRight_Rank8.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank1.cpp | 33 +- ...ETIInst_int64_t_int_LayoutStride_Rank2.cpp | 33 +- ...ETIInst_int64_t_int_LayoutStride_Rank3.cpp | 33 +- ...ETIInst_int64_t_int_LayoutStride_Rank4.cpp | 34 +- ...ETIInst_int64_t_int_LayoutStride_Rank5.cpp | 35 +- ...ETIInst_int64_t_int_LayoutStride_Rank8.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank1.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank2.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank3.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank4.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank5.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank8.cpp | 35 +- ...pyETIInst_int_double_LayoutRight_Rank1.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank2.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank3.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank4.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank5.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank8.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank1.cpp | 33 +- ...yETIInst_int_double_LayoutStride_Rank2.cpp | 33 +- ...yETIInst_int_double_LayoutStride_Rank3.cpp | 33 +- ...yETIInst_int_double_LayoutStride_Rank4.cpp | 33 +- ...yETIInst_int_double_LayoutStride_Rank5.cpp | 34 +- ...yETIInst_int_double_LayoutStride_Rank8.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank1.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank2.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank3.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank4.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank5.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank8.cpp | 34 +- ...opyETIInst_int_float_LayoutRight_Rank1.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank2.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank3.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank4.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank5.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank8.cpp | 35 +- ...pyETIInst_int_float_LayoutStride_Rank1.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank2.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank3.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank4.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank5.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank8.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank1.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank2.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank3.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank4.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank5.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank8.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank1.cpp | 33 +- ...yETIInst_int_int64_t_LayoutRight_Rank2.cpp | 33 +- ...yETIInst_int_int64_t_LayoutRight_Rank3.cpp | 33 +- ...yETIInst_int_int64_t_LayoutRight_Rank4.cpp | 33 +- ...yETIInst_int_int64_t_LayoutRight_Rank5.cpp | 34 +- ...yETIInst_int_int64_t_LayoutRight_Rank8.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank1.cpp | 33 +- ...ETIInst_int_int64_t_LayoutStride_Rank2.cpp | 33 +- ...ETIInst_int_int64_t_LayoutStride_Rank3.cpp | 33 +- ...ETIInst_int_int64_t_LayoutStride_Rank4.cpp | 34 +- ...ETIInst_int_int64_t_LayoutStride_Rank5.cpp | 35 +- ...ETIInst_int_int64_t_LayoutStride_Rank8.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank1.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank2.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank3.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank4.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank5.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank8.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank1.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank2.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank3.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank4.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank5.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank8.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank1.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank2.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank3.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank4.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank5.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank8.cpp | 34 +- ...TIInst_int64_t_double_LayoutLeft_Rank1.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank2.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank3.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank4.cpp | 37 +- ...TIInst_int64_t_double_LayoutLeft_Rank5.cpp | 37 +- ...TIInst_int64_t_double_LayoutLeft_Rank8.cpp | 37 +- ...IInst_int64_t_double_LayoutRight_Rank1.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank2.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank3.cpp | 37 +- ...IInst_int64_t_double_LayoutRight_Rank4.cpp | 37 +- ...IInst_int64_t_double_LayoutRight_Rank5.cpp | 37 +- ...IInst_int64_t_double_LayoutRight_Rank8.cpp | 37 +- ...Inst_int64_t_double_LayoutStride_Rank1.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank2.cpp | 37 +- ...Inst_int64_t_double_LayoutStride_Rank3.cpp | 37 +- ...Inst_int64_t_double_LayoutStride_Rank4.cpp | 37 +- ...Inst_int64_t_double_LayoutStride_Rank5.cpp | 37 +- ...Inst_int64_t_double_LayoutStride_Rank8.cpp | 37 +- ...ETIInst_int64_t_float_LayoutLeft_Rank1.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank2.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank3.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank4.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank5.cpp | 37 +- ...ETIInst_int64_t_float_LayoutLeft_Rank8.cpp | 37 +- ...TIInst_int64_t_float_LayoutRight_Rank1.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank2.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank3.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank4.cpp | 37 +- ...TIInst_int64_t_float_LayoutRight_Rank5.cpp | 37 +- ...TIInst_int64_t_float_LayoutRight_Rank8.cpp | 37 +- ...IInst_int64_t_float_LayoutStride_Rank1.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank2.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank3.cpp | 37 +- ...IInst_int64_t_float_LayoutStride_Rank4.cpp | 37 +- ...IInst_int64_t_float_LayoutStride_Rank5.cpp | 37 +- ...IInst_int64_t_float_LayoutStride_Rank8.cpp | 37 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank1.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank2.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank3.cpp | 37 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank4.cpp | 37 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank5.cpp | 37 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank8.cpp | 37 +- ...Inst_int64_t_int64_t_LayoutRight_Rank1.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank2.cpp | 37 +- ...Inst_int64_t_int64_t_LayoutRight_Rank3.cpp | 37 +- ...Inst_int64_t_int64_t_LayoutRight_Rank4.cpp | 37 +- ...Inst_int64_t_int64_t_LayoutRight_Rank5.cpp | 37 +- ...Inst_int64_t_int64_t_LayoutRight_Rank8.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank1.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank2.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank3.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank4.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank5.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank8.cpp | 37 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank1.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank2.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank3.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank4.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank5.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank8.cpp | 37 +- ...yETIInst_int64_t_int_LayoutRight_Rank1.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank2.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank3.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank4.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank5.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank8.cpp | 37 +- ...ETIInst_int64_t_int_LayoutStride_Rank1.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank2.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank3.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank4.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank5.cpp | 37 +- ...ETIInst_int64_t_int_LayoutStride_Rank8.cpp | 37 +- ...opyETIInst_int_double_LayoutLeft_Rank1.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank2.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank3.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank4.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank5.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank8.cpp | 37 +- ...pyETIInst_int_double_LayoutRight_Rank1.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank2.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank3.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank4.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank5.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank8.cpp | 37 +- ...yETIInst_int_double_LayoutStride_Rank1.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank2.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank3.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank4.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank5.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank8.cpp | 37 +- ...CopyETIInst_int_float_LayoutLeft_Rank1.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank2.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank3.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank4.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank5.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank8.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank1.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank2.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank3.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank4.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank5.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank8.cpp | 37 +- ...pyETIInst_int_float_LayoutStride_Rank1.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank2.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank3.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank4.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank5.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank8.cpp | 37 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank1.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank2.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank3.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank4.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank5.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank8.cpp | 37 +- ...yETIInst_int_int64_t_LayoutRight_Rank1.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank2.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank3.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank4.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank5.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank8.cpp | 37 +- ...ETIInst_int_int64_t_LayoutStride_Rank1.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank2.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank3.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank4.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank5.cpp | 37 +- ...ETIInst_int_int64_t_LayoutStride_Rank8.cpp | 37 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank1.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank2.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank3.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank4.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank5.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank8.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank1.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank2.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank3.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank4.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank5.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank8.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank1.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank2.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank3.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank4.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank5.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank8.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank1.cpp | 34 +- ...TIInst_int64_t_double_LayoutLeft_Rank2.cpp | 35 +- ...TIInst_int64_t_double_LayoutLeft_Rank3.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank4.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank5.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank8.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank1.cpp | 35 +- ...IInst_int64_t_double_LayoutRight_Rank2.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank3.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank4.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank5.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank8.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank1.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank2.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank3.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank4.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank5.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank8.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank1.cpp | 33 +- ...ETIInst_int64_t_float_LayoutLeft_Rank2.cpp | 34 +- ...ETIInst_int64_t_float_LayoutLeft_Rank3.cpp | 35 +- ...ETIInst_int64_t_float_LayoutLeft_Rank4.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank5.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank8.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank1.cpp | 34 +- ...TIInst_int64_t_float_LayoutRight_Rank2.cpp | 35 +- ...TIInst_int64_t_float_LayoutRight_Rank3.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank4.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank5.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank8.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank1.cpp | 35 +- ...IInst_int64_t_float_LayoutStride_Rank2.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank3.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank4.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank5.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank8.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank1.cpp | 35 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank2.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank3.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank4.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank5.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank8.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank1.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank2.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank3.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank4.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank5.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank8.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank1.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank2.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank3.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank4.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank5.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank8.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank1.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank2.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank3.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank4.cpp | 34 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank5.cpp | 35 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank8.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank1.cpp | 33 +- ...yETIInst_int64_t_int_LayoutRight_Rank2.cpp | 33 +- ...yETIInst_int64_t_int_LayoutRight_Rank3.cpp | 34 +- ...yETIInst_int64_t_int_LayoutRight_Rank4.cpp | 35 +- ...yETIInst_int64_t_int_LayoutRight_Rank5.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank8.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank1.cpp | 33 +- ...ETIInst_int64_t_int_LayoutStride_Rank2.cpp | 34 +- ...ETIInst_int64_t_int_LayoutStride_Rank3.cpp | 35 +- ...ETIInst_int64_t_int_LayoutStride_Rank4.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank5.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank8.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank1.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank2.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank3.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank4.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank5.cpp | 34 +- ...opyETIInst_int_double_LayoutLeft_Rank8.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank1.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank2.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank3.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank4.cpp | 34 +- ...pyETIInst_int_double_LayoutRight_Rank5.cpp | 35 +- ...pyETIInst_int_double_LayoutRight_Rank8.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank1.cpp | 33 +- ...yETIInst_int_double_LayoutStride_Rank2.cpp | 33 +- ...yETIInst_int_double_LayoutStride_Rank3.cpp | 34 +- ...yETIInst_int_double_LayoutStride_Rank4.cpp | 35 +- ...yETIInst_int_double_LayoutStride_Rank5.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank8.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank1.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank2.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank3.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank4.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank5.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank8.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank1.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank2.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank3.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank4.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank5.cpp | 34 +- ...opyETIInst_int_float_LayoutRight_Rank8.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank1.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank2.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank3.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank4.cpp | 34 +- ...pyETIInst_int_float_LayoutStride_Rank5.cpp | 35 +- ...pyETIInst_int_float_LayoutStride_Rank8.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank1.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank2.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank3.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank4.cpp | 34 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank5.cpp | 35 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank8.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank1.cpp | 33 +- ...yETIInst_int_int64_t_LayoutRight_Rank2.cpp | 33 +- ...yETIInst_int_int64_t_LayoutRight_Rank3.cpp | 34 +- ...yETIInst_int_int64_t_LayoutRight_Rank4.cpp | 35 +- ...yETIInst_int_int64_t_LayoutRight_Rank5.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank8.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank1.cpp | 33 +- ...ETIInst_int_int64_t_LayoutStride_Rank2.cpp | 34 +- ...ETIInst_int_int64_t_LayoutStride_Rank3.cpp | 35 +- ...ETIInst_int_int64_t_LayoutStride_Rank4.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank5.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank8.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank1.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank2.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank3.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank4.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank5.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank8.cpp | 34 +- ...wCopyETIInst_int_int_LayoutRight_Rank1.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank2.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank3.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank4.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank5.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank8.cpp | 35 +- ...CopyETIInst_int_int_LayoutStride_Rank1.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank2.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank3.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank4.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank5.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank8.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank1.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank2.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank3.cpp | 37 +- ...TIInst_int64_t_double_LayoutLeft_Rank4.cpp | 37 +- ...TIInst_int64_t_double_LayoutLeft_Rank5.cpp | 37 +- ...TIInst_int64_t_double_LayoutLeft_Rank8.cpp | 37 +- ...IInst_int64_t_double_LayoutRight_Rank1.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank2.cpp | 37 +- ...IInst_int64_t_double_LayoutRight_Rank3.cpp | 37 +- ...IInst_int64_t_double_LayoutRight_Rank4.cpp | 37 +- ...IInst_int64_t_double_LayoutRight_Rank5.cpp | 37 +- ...IInst_int64_t_double_LayoutRight_Rank8.cpp | 37 +- ...Inst_int64_t_double_LayoutStride_Rank1.cpp | 37 +- ...Inst_int64_t_double_LayoutStride_Rank2.cpp | 37 +- ...Inst_int64_t_double_LayoutStride_Rank3.cpp | 37 +- ...Inst_int64_t_double_LayoutStride_Rank4.cpp | 37 +- ...Inst_int64_t_double_LayoutStride_Rank5.cpp | 37 +- ...Inst_int64_t_double_LayoutStride_Rank8.cpp | 37 +- ...ETIInst_int64_t_float_LayoutLeft_Rank1.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank2.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank3.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank4.cpp | 37 +- ...ETIInst_int64_t_float_LayoutLeft_Rank5.cpp | 37 +- ...ETIInst_int64_t_float_LayoutLeft_Rank8.cpp | 37 +- ...TIInst_int64_t_float_LayoutRight_Rank1.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank2.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank3.cpp | 37 +- ...TIInst_int64_t_float_LayoutRight_Rank4.cpp | 37 +- ...TIInst_int64_t_float_LayoutRight_Rank5.cpp | 37 +- ...TIInst_int64_t_float_LayoutRight_Rank8.cpp | 37 +- ...IInst_int64_t_float_LayoutStride_Rank1.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank2.cpp | 37 +- ...IInst_int64_t_float_LayoutStride_Rank3.cpp | 37 +- ...IInst_int64_t_float_LayoutStride_Rank4.cpp | 37 +- ...IInst_int64_t_float_LayoutStride_Rank5.cpp | 37 +- ...IInst_int64_t_float_LayoutStride_Rank8.cpp | 37 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank1.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank2.cpp | 37 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank3.cpp | 37 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank4.cpp | 37 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank5.cpp | 37 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank8.cpp | 37 +- ...Inst_int64_t_int64_t_LayoutRight_Rank1.cpp | 37 +- ...Inst_int64_t_int64_t_LayoutRight_Rank2.cpp | 37 +- ...Inst_int64_t_int64_t_LayoutRight_Rank3.cpp | 37 +- ...Inst_int64_t_int64_t_LayoutRight_Rank4.cpp | 37 +- ...Inst_int64_t_int64_t_LayoutRight_Rank5.cpp | 37 +- ...Inst_int64_t_int64_t_LayoutRight_Rank8.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank1.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank2.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank3.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank4.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank5.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank8.cpp | 37 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank1.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank2.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank3.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank4.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank5.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank8.cpp | 37 +- ...yETIInst_int64_t_int_LayoutRight_Rank1.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank2.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank3.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank4.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank5.cpp | 37 +- ...yETIInst_int64_t_int_LayoutRight_Rank8.cpp | 37 +- ...ETIInst_int64_t_int_LayoutStride_Rank1.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank2.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank3.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank4.cpp | 37 +- ...ETIInst_int64_t_int_LayoutStride_Rank5.cpp | 37 +- ...ETIInst_int64_t_int_LayoutStride_Rank8.cpp | 37 +- ...opyETIInst_int_double_LayoutLeft_Rank1.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank2.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank3.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank4.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank5.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank8.cpp | 37 +- ...pyETIInst_int_double_LayoutRight_Rank1.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank2.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank3.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank4.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank5.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank8.cpp | 37 +- ...yETIInst_int_double_LayoutStride_Rank1.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank2.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank3.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank4.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank5.cpp | 37 +- ...yETIInst_int_double_LayoutStride_Rank8.cpp | 37 +- ...CopyETIInst_int_float_LayoutLeft_Rank1.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank2.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank3.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank4.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank5.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank8.cpp | 37 +- ...opyETIInst_int_float_LayoutRight_Rank1.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank2.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank3.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank4.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank5.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank8.cpp | 37 +- ...pyETIInst_int_float_LayoutStride_Rank1.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank2.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank3.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank4.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank5.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank8.cpp | 37 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank1.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank2.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank3.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank4.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank5.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank8.cpp | 37 +- ...yETIInst_int_int64_t_LayoutRight_Rank1.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank2.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank3.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank4.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank5.cpp | 37 +- ...yETIInst_int_int64_t_LayoutRight_Rank8.cpp | 37 +- ...ETIInst_int_int64_t_LayoutStride_Rank1.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank2.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank3.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank4.cpp | 37 +- ...ETIInst_int_int64_t_LayoutStride_Rank5.cpp | 37 +- ...ETIInst_int_int64_t_LayoutStride_Rank8.cpp | 37 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank1.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank2.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank3.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank4.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank5.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank8.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank1.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank2.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank3.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank4.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank5.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank8.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank1.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank2.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank3.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank4.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank5.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank8.cpp | 37 +- ...TIInst_int64_t_double_LayoutLeft_Rank1.cpp | 34 +- ...TIInst_int64_t_double_LayoutLeft_Rank2.cpp | 35 +- ...TIInst_int64_t_double_LayoutLeft_Rank3.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank4.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank5.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank8.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank1.cpp | 35 +- ...IInst_int64_t_double_LayoutRight_Rank2.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank3.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank4.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank5.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank8.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank1.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank2.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank3.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank4.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank5.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank8.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank1.cpp | 33 +- ...ETIInst_int64_t_float_LayoutLeft_Rank2.cpp | 34 +- ...ETIInst_int64_t_float_LayoutLeft_Rank3.cpp | 35 +- ...ETIInst_int64_t_float_LayoutLeft_Rank4.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank5.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank8.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank1.cpp | 34 +- ...TIInst_int64_t_float_LayoutRight_Rank2.cpp | 35 +- ...TIInst_int64_t_float_LayoutRight_Rank3.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank4.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank5.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank8.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank1.cpp | 35 +- ...IInst_int64_t_float_LayoutStride_Rank2.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank3.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank4.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank5.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank8.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank1.cpp | 35 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank2.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank3.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank4.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank5.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank8.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank1.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank2.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank3.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank4.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank5.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank8.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank1.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank2.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank3.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank4.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank5.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank8.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank1.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank2.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank3.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank4.cpp | 34 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank5.cpp | 35 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank8.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank1.cpp | 33 +- ...yETIInst_int64_t_int_LayoutRight_Rank2.cpp | 33 +- ...yETIInst_int64_t_int_LayoutRight_Rank3.cpp | 34 +- ...yETIInst_int64_t_int_LayoutRight_Rank4.cpp | 35 +- ...yETIInst_int64_t_int_LayoutRight_Rank5.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank8.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank1.cpp | 33 +- ...ETIInst_int64_t_int_LayoutStride_Rank2.cpp | 34 +- ...ETIInst_int64_t_int_LayoutStride_Rank3.cpp | 35 +- ...ETIInst_int64_t_int_LayoutStride_Rank4.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank5.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank8.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank1.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank2.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank3.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank4.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank5.cpp | 34 +- ...opyETIInst_int_double_LayoutLeft_Rank8.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank1.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank2.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank3.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank4.cpp | 34 +- ...pyETIInst_int_double_LayoutRight_Rank5.cpp | 35 +- ...pyETIInst_int_double_LayoutRight_Rank8.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank1.cpp | 33 +- ...yETIInst_int_double_LayoutStride_Rank2.cpp | 33 +- ...yETIInst_int_double_LayoutStride_Rank3.cpp | 34 +- ...yETIInst_int_double_LayoutStride_Rank4.cpp | 35 +- ...yETIInst_int_double_LayoutStride_Rank5.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank8.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank1.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank2.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank3.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank4.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank5.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank8.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank1.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank2.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank3.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank4.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank5.cpp | 34 +- ...opyETIInst_int_float_LayoutRight_Rank8.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank1.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank2.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank3.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank4.cpp | 34 +- ...pyETIInst_int_float_LayoutStride_Rank5.cpp | 35 +- ...pyETIInst_int_float_LayoutStride_Rank8.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank1.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank2.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank3.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank4.cpp | 34 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank5.cpp | 35 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank8.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank1.cpp | 33 +- ...yETIInst_int_int64_t_LayoutRight_Rank2.cpp | 33 +- ...yETIInst_int_int64_t_LayoutRight_Rank3.cpp | 34 +- ...yETIInst_int_int64_t_LayoutRight_Rank4.cpp | 35 +- ...yETIInst_int_int64_t_LayoutRight_Rank5.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank8.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank1.cpp | 33 +- ...ETIInst_int_int64_t_LayoutStride_Rank2.cpp | 34 +- ...ETIInst_int_int64_t_LayoutStride_Rank3.cpp | 35 +- ...ETIInst_int_int64_t_LayoutStride_Rank4.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank5.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank8.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank1.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank2.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank3.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank4.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank5.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank8.cpp | 34 +- ...wCopyETIInst_int_int_LayoutRight_Rank1.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank2.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank3.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank4.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank5.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank8.cpp | 35 +- ...CopyETIInst_int_int_LayoutStride_Rank1.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank2.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank3.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank4.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank5.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank8.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank1.cpp | 35 +- ...TIInst_int64_t_double_LayoutLeft_Rank2.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank3.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank4.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank5.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank8.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank1.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank2.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank3.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank4.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank5.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank8.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank1.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank2.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank3.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank4.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank5.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank8.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank1.cpp | 34 +- ...ETIInst_int64_t_float_LayoutLeft_Rank2.cpp | 35 +- ...ETIInst_int64_t_float_LayoutLeft_Rank3.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank4.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank5.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank8.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank1.cpp | 35 +- ...TIInst_int64_t_float_LayoutRight_Rank2.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank3.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank4.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank5.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank8.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank1.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank2.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank3.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank4.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank5.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank8.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank1.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank2.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank3.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank4.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank5.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank8.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank1.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank2.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank3.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank4.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank5.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank8.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank1.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank2.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank3.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank4.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank5.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank8.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank1.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank2.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank3.cpp | 34 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank4.cpp | 35 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank5.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank8.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank1.cpp | 33 +- ...yETIInst_int64_t_int_LayoutRight_Rank2.cpp | 34 +- ...yETIInst_int64_t_int_LayoutRight_Rank3.cpp | 35 +- ...yETIInst_int64_t_int_LayoutRight_Rank4.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank5.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank8.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank1.cpp | 34 +- ...ETIInst_int64_t_int_LayoutStride_Rank2.cpp | 35 +- ...ETIInst_int64_t_int_LayoutStride_Rank3.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank4.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank5.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank8.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank1.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank2.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank3.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank4.cpp | 34 +- ...opyETIInst_int_double_LayoutLeft_Rank5.cpp | 35 +- ...opyETIInst_int_double_LayoutLeft_Rank8.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank1.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank2.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank3.cpp | 34 +- ...pyETIInst_int_double_LayoutRight_Rank4.cpp | 35 +- ...pyETIInst_int_double_LayoutRight_Rank5.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank8.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank1.cpp | 33 +- ...yETIInst_int_double_LayoutStride_Rank2.cpp | 34 +- ...yETIInst_int_double_LayoutStride_Rank3.cpp | 35 +- ...yETIInst_int_double_LayoutStride_Rank4.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank5.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank8.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank1.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank2.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank3.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank4.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank5.cpp | 34 +- ...CopyETIInst_int_float_LayoutLeft_Rank8.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank1.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank2.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank3.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank4.cpp | 34 +- ...opyETIInst_int_float_LayoutRight_Rank5.cpp | 35 +- ...opyETIInst_int_float_LayoutRight_Rank8.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank1.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank2.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank3.cpp | 34 +- ...pyETIInst_int_float_LayoutStride_Rank4.cpp | 35 +- ...pyETIInst_int_float_LayoutStride_Rank5.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank8.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank1.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank2.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank3.cpp | 34 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank4.cpp | 35 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank5.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank8.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank1.cpp | 33 +- ...yETIInst_int_int64_t_LayoutRight_Rank2.cpp | 34 +- ...yETIInst_int_int64_t_LayoutRight_Rank3.cpp | 35 +- ...yETIInst_int_int64_t_LayoutRight_Rank4.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank5.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank8.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank1.cpp | 34 +- ...ETIInst_int_int64_t_LayoutStride_Rank2.cpp | 35 +- ...ETIInst_int_int64_t_LayoutStride_Rank3.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank4.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank5.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank8.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank1.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank2.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank3.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank4.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank5.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank8.cpp | 35 +- ...wCopyETIInst_int_int_LayoutRight_Rank1.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank2.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank3.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank4.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank5.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank8.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank1.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank2.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank3.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank4.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank5.cpp | 34 +- ...CopyETIInst_int_int_LayoutStride_Rank8.cpp | 36 +- .../Kokkos_ViewFillCopyETIAvail_Macros.hpp | 2016 ++++-- .../Kokkos_ViewFillCopyETIDecl_Macros.hpp | 1728 +++-- lib/kokkos/core/src/impl/CMakeLists.txt | 36 +- .../src/impl/KokkosExp_Host_IterateTile.hpp | 3833 ++++++------ .../core/src/impl/KokkosExp_ViewMapping.hpp | 19 +- .../core/src/impl/Kokkos_AnalyzePolicy.hpp | 309 +- .../core/src/impl/Kokkos_Atomic_Assembly.hpp | 113 +- .../Kokkos_Atomic_Compare_Exchange_Strong.hpp | 496 +- .../Kokkos_Atomic_Compare_Exchange_Weak.hpp | 343 +- .../core/src/impl/Kokkos_Atomic_Decrement.hpp | 122 +- .../core/src/impl/Kokkos_Atomic_Exchange.hpp | 436 +- .../core/src/impl/Kokkos_Atomic_Fetch_Add.hpp | 389 +- .../core/src/impl/Kokkos_Atomic_Fetch_And.hpp | 117 +- .../core/src/impl/Kokkos_Atomic_Fetch_Or.hpp | 117 +- .../core/src/impl/Kokkos_Atomic_Fetch_Sub.hpp | 316 +- .../core/src/impl/Kokkos_Atomic_Generic.hpp | 428 +- .../core/src/impl/Kokkos_Atomic_Increment.hpp | 128 +- .../core/src/impl/Kokkos_Atomic_Load.hpp | 185 +- .../src/impl/Kokkos_Atomic_Memory_Order.hpp | 55 +- .../core/src/impl/Kokkos_Atomic_Store.hpp | 189 +- .../core/src/impl/Kokkos_Atomic_View.hpp | 340 +- .../core/src/impl/Kokkos_Atomic_Windows.hpp | 340 +- lib/kokkos/core/src/impl/Kokkos_BitOps.hpp | 139 +- .../core/src/impl/Kokkos_CPUDiscovery.cpp | 55 +- .../core/src/impl/Kokkos_CPUDiscovery.hpp | 15 +- lib/kokkos/core/src/impl/Kokkos_ChaseLev.hpp | 205 +- lib/kokkos/core/src/impl/Kokkos_ClockTic.hpp | 46 +- .../core/src/impl/Kokkos_ConcurrentBitset.hpp | 338 +- lib/kokkos/core/src/impl/Kokkos_Core.cpp | 940 +-- lib/kokkos/core/src/impl/Kokkos_EBO.hpp | 223 +- lib/kokkos/core/src/impl/Kokkos_Error.cpp | 173 +- lib/kokkos/core/src/impl/Kokkos_Error.hpp | 199 +- .../core/src/impl/Kokkos_ExecPolicy.cpp | 28 +- .../src/impl/Kokkos_FixedBufferMemoryPool.hpp | 142 +- .../core/src/impl/Kokkos_FunctorAdapter.hpp | 3126 ++++----- .../core/src/impl/Kokkos_FunctorAnalysis.hpp | 1203 ++-- lib/kokkos/core/src/impl/Kokkos_HBWSpace.cpp | 328 +- .../core/src/impl/Kokkos_HostBarrier.cpp | 94 +- .../core/src/impl/Kokkos_HostBarrier.hpp | 237 +- lib/kokkos/core/src/impl/Kokkos_HostSpace.cpp | 543 +- .../src/impl/Kokkos_HostSpace_deepcopy.cpp | 101 +- .../src/impl/Kokkos_HostSpace_deepcopy.hpp | 20 +- .../core/src/impl/Kokkos_HostThreadTeam.cpp | 289 +- .../core/src/impl/Kokkos_HostThreadTeam.hpp | 1322 ++-- lib/kokkos/core/src/impl/Kokkos_LIFO.hpp | 171 +- .../core/src/impl/Kokkos_LinkedListNode.hpp | 109 +- .../core/src/impl/Kokkos_MemoryPool.cpp | 95 +- .../src/impl/Kokkos_MemoryPoolAllocator.hpp | 53 +- .../core/src/impl/Kokkos_MemorySpace.hpp | 110 + .../core/src/impl/Kokkos_Memory_Fence.hpp | 69 +- .../src/impl/Kokkos_MultipleTaskQueue.hpp | 515 +- lib/kokkos/core/src/impl/Kokkos_OldMacros.hpp | 70 +- .../core/src/impl/Kokkos_OptionalRef.hpp | 87 +- .../core/src/impl/Kokkos_PhysicalLayout.hpp | 43 +- .../src/impl/Kokkos_Profiling_DeviceInfo.hpp | 85 +- .../src/impl/Kokkos_Profiling_Interface.cpp | 380 +- .../src/impl/Kokkos_Profiling_Interface.hpp | 170 +- lib/kokkos/core/src/impl/Kokkos_Serial.cpp | 167 +- .../core/src/impl/Kokkos_Serial_Task.cpp | 20 +- .../core/src/impl/Kokkos_Serial_Task.hpp | 195 +- .../impl/Kokkos_Serial_WorkGraphPolicy.hpp | 83 +- .../core/src/impl/Kokkos_SharedAlloc.cpp | 388 +- .../core/src/impl/Kokkos_SharedAlloc.hpp | 437 +- .../src/impl/Kokkos_SimpleTaskScheduler.hpp | 574 +- .../core/src/impl/Kokkos_SingleTaskQueue.hpp | 123 +- lib/kokkos/core/src/impl/Kokkos_Spinwait.cpp | 155 +- lib/kokkos/core/src/impl/Kokkos_Spinwait.hpp | 78 +- .../core/src/impl/Kokkos_Stacktrace.cpp | 247 + .../core/src/impl/Kokkos_Stacktrace.hpp | 45 + lib/kokkos/core/src/impl/Kokkos_Tags.hpp | 44 +- lib/kokkos/core/src/impl/Kokkos_TaskBase.hpp | 235 +- lib/kokkos/core/src/impl/Kokkos_TaskNode.hpp | 550 +- .../core/src/impl/Kokkos_TaskPolicyData.hpp | 103 +- lib/kokkos/core/src/impl/Kokkos_TaskQueue.hpp | 151 +- .../core/src/impl/Kokkos_TaskQueueCommon.hpp | 366 +- .../impl/Kokkos_TaskQueueMemoryManager.hpp | 173 +- .../src/impl/Kokkos_TaskQueueMultiple.hpp | 165 +- .../impl/Kokkos_TaskQueueMultiple_impl.hpp | 20 +- .../core/src/impl/Kokkos_TaskQueue_impl.hpp | 443 +- .../core/src/impl/Kokkos_TaskResult.hpp | 101 +- .../core/src/impl/Kokkos_TaskTeamMember.hpp | 43 +- lib/kokkos/core/src/impl/Kokkos_Timer.hpp | 28 +- lib/kokkos/core/src/impl/Kokkos_Traits.hpp | 539 +- lib/kokkos/core/src/impl/Kokkos_Utilities.hpp | 460 +- .../core/src/impl/Kokkos_VLAEmulation.hpp | 164 +- lib/kokkos/core/src/impl/Kokkos_ViewArray.hpp | 882 +-- lib/kokkos/core/src/impl/Kokkos_ViewCtor.hpp | 260 +- .../src/impl/Kokkos_ViewFillCopyETIAvail.hpp | 96 +- .../src/impl/Kokkos_ViewFillCopyETIDecl.hpp | 115 +- .../core/src/impl/Kokkos_ViewLayoutTiled.hpp | 1806 ++++-- .../core/src/impl/Kokkos_ViewMapping.hpp | 5558 +++++++++-------- lib/kokkos/core/src/impl/Kokkos_ViewTile.hpp | 262 +- .../core/src/impl/Kokkos_ViewUniformType.hpp | 116 +- .../core/src/impl/Kokkos_Volatile_Load.hpp | 163 +- lib/kokkos/core/src/impl/Kokkos_hwloc.cpp | 731 +-- lib/kokkos/core/src/kokkos.pc.in | 18 +- lib/kokkos/core/unit_test/CMakeLists.txt | 915 +-- lib/kokkos/core/unit_test/Makefile | 57 +- lib/kokkos/core/unit_test/TestAggregate.hpp | 132 +- lib/kokkos/core/unit_test/TestAtomic.hpp | 431 +- .../core/unit_test/TestAtomicOperations.hpp | 728 +-- .../TestAtomicOperations_complexdouble.hpp | 33 +- .../TestAtomicOperations_complexfloat.hpp | 33 +- .../unit_test/TestAtomicOperations_double.hpp | 37 +- .../unit_test/TestAtomicOperations_float.hpp | 37 +- .../unit_test/TestAtomicOperations_int.hpp | 58 +- .../TestAtomicOperations_longint.hpp | 58 +- .../TestAtomicOperations_longlongint.hpp | 58 +- .../TestAtomicOperations_unsignedint.hpp | 58 +- .../TestAtomicOperations_unsignedlongint.hpp | 58 +- lib/kokkos/core/unit_test/TestAtomicViews.hpp | 1529 ++--- lib/kokkos/core/unit_test/TestCXX11.hpp | 399 +- .../core/unit_test/TestCXX11Deduction.hpp | 65 +- .../core/unit_test/TestCompilerMacros.hpp | 74 +- lib/kokkos/core/unit_test/TestComplex.hpp | 364 +- .../core/unit_test/TestConcurrentBitset.hpp | 156 +- lib/kokkos/core/unit_test/TestCrs.hpp | 163 +- lib/kokkos/core/unit_test/TestDeepCopy.hpp | 223 +- .../unit_test/TestDefaultDeviceTypeInit.hpp | 380 +- .../core/unit_test/TestFunctorAnalysis.hpp | 171 +- lib/kokkos/core/unit_test/TestHWLOC.cpp | 25 +- lib/kokkos/core/unit_test/TestHostBarrier.cpp | 13 +- lib/kokkos/core/unit_test/TestInit.hpp | 35 +- .../core/unit_test/TestLocalDeepCopy.hpp | 1541 ++--- lib/kokkos/core/unit_test/TestMDRange.hpp | 3629 ++++++----- lib/kokkos/core/unit_test/TestMDRange_a.hpp | 24 +- lib/kokkos/core/unit_test/TestMDRange_b.hpp | 24 +- lib/kokkos/core/unit_test/TestMDRange_c.hpp | 30 +- lib/kokkos/core/unit_test/TestMDRange_d.hpp | 40 +- lib/kokkos/core/unit_test/TestMDRange_e.hpp | 24 +- lib/kokkos/core/unit_test/TestMemoryPool.hpp | 679 +- .../core/unit_test/TestPolicyConstruction.hpp | 1299 ++-- lib/kokkos/core/unit_test/TestRange.hpp | 412 +- lib/kokkos/core/unit_test/TestReduce.hpp | 465 +- .../unit_test/TestReduceCombinatorical.hpp | 599 +- .../core/unit_test/TestReduceDeviceView.hpp | 194 +- lib/kokkos/core/unit_test/TestReducers.hpp | 925 +-- lib/kokkos/core/unit_test/TestReducers_a.hpp | 18 +- lib/kokkos/core/unit_test/TestReducers_b.hpp | 18 +- lib/kokkos/core/unit_test/TestReducers_c.hpp | 18 +- lib/kokkos/core/unit_test/TestReducers_d.hpp | 19 +- lib/kokkos/core/unit_test/TestResize.hpp | 397 +- lib/kokkos/core/unit_test/TestScan.hpp | 114 +- lib/kokkos/core/unit_test/TestSharedAlloc.hpp | 154 +- .../unit_test/TestStackTrace.cpp} | 42 +- lib/kokkos/core/unit_test/TestStackTrace.hpp | 169 + .../unit_test/TestStackTrace_f0.cpp} | 45 +- .../unit_test/TestStackTrace_f1.cpp} | 45 +- .../unit_test/TestStackTrace_f2.cpp} | 49 +- .../core/unit_test/TestStackTrace_f3.cpp | 62 + .../core/unit_test/TestStackTrace_f4.cpp | 53 + .../core/unit_test/TestTaskScheduler.hpp | 910 ++- .../unit_test/TestTaskScheduler_single.hpp | 62 +- lib/kokkos/core/unit_test/TestTeam.hpp | 1237 ++-- .../core/unit_test/TestTeamTeamSize.hpp | 243 +- lib/kokkos/core/unit_test/TestTeamVector.hpp | 1037 +-- .../core/unit_test/TestTeamVectorRange.hpp | 421 +- .../unit_test/TestTemplateMetaFunctions.hpp | 169 +- lib/kokkos/core/unit_test/TestTile.hpp | 149 +- lib/kokkos/core/unit_test/TestUniqueToken.hpp | 120 +- lib/kokkos/core/unit_test/TestUtilities.hpp | 455 +- lib/kokkos/core/unit_test/TestViewAPI.hpp | 1899 +++--- lib/kokkos/core/unit_test/TestViewAPI_a.hpp | 20 +- lib/kokkos/core/unit_test/TestViewAPI_b.hpp | 24 +- lib/kokkos/core/unit_test/TestViewAPI_c.hpp | 22 +- lib/kokkos/core/unit_test/TestViewAPI_d.hpp | 30 +- lib/kokkos/core/unit_test/TestViewAPI_e.hpp | 212 +- lib/kokkos/core/unit_test/TestViewCopy.hpp | 202 +- .../unit_test/TestViewCtorPropEmbeddedDim.hpp | 121 +- .../TestViewLayoutStrideAssignment.hpp | 1092 ++-- .../core/unit_test/TestViewLayoutTiled.hpp | 2157 ++++--- .../core/unit_test/TestViewMapping_a.hpp | 1711 ++--- .../core/unit_test/TestViewMapping_b.hpp | 241 +- .../unit_test/TestViewMapping_subview.hpp | 259 +- lib/kokkos/core/unit_test/TestViewOfClass.hpp | 91 +- lib/kokkos/core/unit_test/TestViewResize.hpp | 58 + .../core/unit_test/TestViewSpaceAssign.hpp | 42 +- lib/kokkos/core/unit_test/TestViewSubview.hpp | 2511 +++++--- lib/kokkos/core/unit_test/TestView_64bit.hpp | 119 +- lib/kokkos/core/unit_test/TestWorkGraph.hpp | 99 +- lib/kokkos/core/unit_test/UnitTestMain.cpp | 15 +- .../core/unit_test/UnitTestMainInit.cpp | 19 +- .../unit_test/UnitTest_PushFinalizeHook.cpp | 67 +- .../UnitTest_PushFinalizeHook_terminate.cpp | 33 +- .../unit_test/config/cmaketest/CMakeLists.txt | 1 - .../configuration/test-code/CMakeLists.txt | 44 + .../configuration/test-code/Makefile | 46 + .../configuration/test-code/main.cpp | 6 + .../configuration/test-code/test_config.bash | 7 + .../test-code/test_config_arch_list.bash | 45 + .../test-code/test_config_device_list.bash | 45 + .../test-code/test_config_options_list.bash | 49 + .../test-code/test_config_run.bash | 111 + .../cuda/TestCudaHostPinned_Category.hpp | 28 +- .../cuda/TestCudaHostPinned_SharedAlloc.cpp | 19 +- .../cuda/TestCudaHostPinned_ViewAPI_a.cpp | 11 +- .../cuda/TestCudaHostPinned_ViewAPI_b.cpp | 11 +- .../cuda/TestCudaHostPinned_ViewAPI_c.cpp | 11 +- .../cuda/TestCudaHostPinned_ViewAPI_d.cpp | 11 +- .../cuda/TestCudaHostPinned_ViewAPI_e.cpp | 11 +- .../cuda/TestCudaHostPinned_ViewCopy.cpp | 11 +- .../cuda/TestCudaHostPinned_ViewMapping_a.cpp | 12 +- .../cuda/TestCudaHostPinned_ViewMapping_b.cpp | 12 +- ...TestCudaHostPinned_ViewMapping_subview.cpp | 12 +- .../unit_test/cuda/TestCudaUVM_Category.hpp | 25 +- .../cuda/TestCudaUVM_SharedAlloc.cpp | 19 +- .../unit_test/cuda/TestCudaUVM_ViewAPI_a.cpp | 11 +- .../unit_test/cuda/TestCudaUVM_ViewAPI_b.cpp | 11 +- .../unit_test/cuda/TestCudaUVM_ViewAPI_c.cpp | 11 +- .../unit_test/cuda/TestCudaUVM_ViewAPI_d.cpp | 11 +- .../unit_test/cuda/TestCudaUVM_ViewAPI_e.cpp | 11 +- .../unit_test/cuda/TestCudaUVM_ViewCopy.cpp | 11 +- .../cuda/TestCudaUVM_ViewMapping_a.cpp | 12 +- .../cuda/TestCudaUVM_ViewMapping_b.cpp | 12 +- .../cuda/TestCudaUVM_ViewMapping_subview.cpp | 12 +- ...estCuda_AtomicOperations_complexdouble.cpp | 16 +- ...TestCuda_AtomicOperations_complexfloat.cpp | 16 +- .../cuda/TestCuda_AtomicOperations_double.cpp | 16 +- .../cuda/TestCuda_AtomicOperations_float.cpp | 16 +- .../cuda/TestCuda_AtomicOperations_int.cpp | 16 +- .../TestCuda_AtomicOperations_longint.cpp | 16 +- .../TestCuda_AtomicOperations_longlongint.cpp | 16 +- .../TestCuda_AtomicOperations_unsignedint.cpp | 16 +- ...tCuda_AtomicOperations_unsignedlongint.cpp | 16 +- .../unit_test/cuda/TestCuda_AtomicViews.cpp | 16 +- .../core/unit_test/cuda/TestCuda_Atomics.cpp | 12 +- .../core/unit_test/cuda/TestCuda_Category.hpp | 25 +- .../core/unit_test/cuda/TestCuda_Complex.cpp | 16 +- .../core/unit_test/cuda/TestCuda_Crs.cpp | 11 +- .../cuda/TestCuda_DebugPinUVMSpace.cpp | 131 + .../cuda/TestCuda_DebugSerialExecution.cpp | 197 + .../cuda/TestCuda_DeepCopyAlignment.cpp | 14 +- .../cuda/TestCuda_FunctorAnalysis.cpp | 47 + .../core/unit_test/cuda/TestCuda_Init.cpp | 21 +- .../unit_test/cuda/TestCuda_InterOp_Init.cpp | 50 +- .../cuda/TestCuda_InterOp_Streams.cpp | 256 +- .../unit_test/cuda/TestCuda_LocalDeepCopy.cpp | 12 +- .../unit_test/cuda/TestCuda_MDRange_a.cpp | 16 +- .../unit_test/cuda/TestCuda_MDRange_b.cpp | 16 +- .../unit_test/cuda/TestCuda_MDRange_c.cpp | 16 +- .../unit_test/cuda/TestCuda_MDRange_d.cpp | 16 +- .../unit_test/cuda/TestCuda_MDRange_e.cpp | 16 +- .../core/unit_test/cuda/TestCuda_Other.cpp | 27 +- .../unit_test/cuda/TestCuda_RangePolicy.cpp | 16 +- .../unit_test/cuda/TestCuda_Reducers_a.cpp | 11 +- .../unit_test/cuda/TestCuda_Reducers_b.cpp | 11 +- .../unit_test/cuda/TestCuda_Reducers_c.cpp | 11 +- .../unit_test/cuda/TestCuda_Reducers_d.cpp | 11 +- .../unit_test/cuda/TestCuda_Reductions.cpp | 11 +- .../cuda/TestCuda_Reductions_DeviceView.cpp | 11 +- .../core/unit_test/cuda/TestCuda_Scan.cpp | 16 +- .../unit_test/cuda/TestCuda_SharedAlloc.cpp | 19 +- .../core/unit_test/cuda/TestCuda_Spaces.cpp | 365 +- .../unit_test/cuda/TestCuda_SubView_a.cpp | 77 +- .../unit_test/cuda/TestCuda_SubView_b.cpp | 35 +- .../unit_test/cuda/TestCuda_SubView_c01.cpp | 18 +- .../unit_test/cuda/TestCuda_SubView_c02.cpp | 19 +- .../unit_test/cuda/TestCuda_SubView_c03.cpp | 19 +- .../unit_test/cuda/TestCuda_SubView_c04.cpp | 18 +- .../unit_test/cuda/TestCuda_SubView_c05.cpp | 19 +- .../unit_test/cuda/TestCuda_SubView_c06.cpp | 19 +- .../unit_test/cuda/TestCuda_SubView_c07.cpp | 18 +- .../unit_test/cuda/TestCuda_SubView_c08.cpp | 19 +- .../unit_test/cuda/TestCuda_SubView_c09.cpp | 19 +- .../unit_test/cuda/TestCuda_SubView_c10.cpp | 18 +- .../unit_test/cuda/TestCuda_SubView_c11.cpp | 19 +- .../unit_test/cuda/TestCuda_SubView_c12.cpp | 19 +- .../unit_test/cuda/TestCuda_SubView_c13.cpp | 18 +- .../core/unit_test/cuda/TestCuda_Task.cpp | 16 +- .../core/unit_test/cuda/TestCuda_Team.cpp | 85 +- .../cuda/TestCuda_TeamReductionScan.cpp | 63 +- .../unit_test/cuda/TestCuda_TeamScratch.cpp | 59 +- .../unit_test/cuda/TestCuda_TeamTeamSize.cpp | 11 +- .../cuda/TestCuda_TeamVectorRange.cpp | 17 +- .../unit_test/cuda/TestCuda_UniqueToken.cpp | 16 +- .../unit_test/cuda/TestCuda_ViewAPI_a.cpp | 11 +- .../unit_test/cuda/TestCuda_ViewAPI_b.cpp | 11 +- .../unit_test/cuda/TestCuda_ViewAPI_c.cpp | 11 +- .../unit_test/cuda/TestCuda_ViewAPI_d.cpp | 11 +- .../unit_test/cuda/TestCuda_ViewAPI_e.cpp | 11 +- .../TestCuda_ViewLayoutStrideAssignment.cpp | 12 +- .../unit_test/cuda/TestCuda_ViewMapping_a.cpp | 12 +- .../unit_test/cuda/TestCuda_ViewMapping_b.cpp | 12 +- .../cuda/TestCuda_ViewMapping_subview.cpp | 12 +- .../unit_test/cuda/TestCuda_ViewOfClass.cpp | 12 +- .../unit_test/cuda/TestCuda_ViewResize.cpp | 46 + .../unit_test/cuda/TestCuda_View_64bit.cpp | 11 +- .../unit_test/cuda/TestCuda_WorkGraph.cpp | 15 +- .../default/TestDefaultDeviceType.cpp | 39 +- .../default/TestDefaultDeviceTypeInit_1.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_10.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_11.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_12.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_13.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_14.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_15.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_16.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_2.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_3.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_4.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_5.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_6.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_7.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_8.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_9.cpp | 2 +- .../default/TestDefaultDeviceTypeResize.cpp | 18 +- .../TestDefaultDeviceType_Category.hpp | 27 +- .../default/TestDefaultDeviceType_a1.cpp | 19 +- .../default/TestDefaultDeviceType_a2.cpp | 19 +- .../default/TestDefaultDeviceType_a3.cpp | 19 +- .../default/TestDefaultDeviceType_b1.cpp | 18 +- .../default/TestDefaultDeviceType_b2.cpp | 18 +- .../default/TestDefaultDeviceType_b3.cpp | 18 +- .../default/TestDefaultDeviceType_c1.cpp | 20 +- .../default/TestDefaultDeviceType_c2.cpp | 20 +- .../default/TestDefaultDeviceType_c3.cpp | 20 +- .../default/TestDefaultDeviceType_d.cpp | 35 +- ...TestHPX_AtomicOperations_complexdouble.cpp | 46 + .../TestHPX_AtomicOperations_complexfloat.cpp | 46 + .../hpx/TestHPX_AtomicOperations_double.cpp | 16 +- .../hpx/TestHPX_AtomicOperations_float.cpp | 16 +- .../hpx/TestHPX_AtomicOperations_int.cpp | 16 +- .../hpx/TestHPX_AtomicOperations_longint.cpp | 16 +- .../TestHPX_AtomicOperations_longlongint.cpp | 16 +- .../TestHPX_AtomicOperations_unsignedint.cpp | 16 +- ...stHPX_AtomicOperations_unsignedlongint.cpp | 16 +- .../unit_test/hpx/TestHPX_AtomicViews.cpp | 16 +- .../core/unit_test/hpx/TestHPX_Atomics.cpp | 12 +- .../core/unit_test/hpx/TestHPX_Category.hpp | 25 +- .../core/unit_test/hpx/TestHPX_Complex.cpp | 16 +- lib/kokkos/core/unit_test/hpx/TestHPX_Crs.cpp | 11 +- .../hpx/TestHPX_DeepCopyAlignment.cpp | 46 + .../unit_test/hpx/TestHPX_FunctorAnalysis.cpp | 47 + .../core/unit_test/hpx/TestHPX_Init.cpp | 21 +- .../core/unit_test/hpx/TestHPX_InterOp.cpp | 21 +- .../unit_test/hpx/TestHPX_LocalDeepCopy.cpp | 46 + .../core/unit_test/hpx/TestHPX_MDRange_a.cpp | 16 +- .../core/unit_test/hpx/TestHPX_MDRange_b.cpp | 16 +- .../core/unit_test/hpx/TestHPX_MDRange_c.cpp | 16 +- .../core/unit_test/hpx/TestHPX_MDRange_d.cpp | 16 +- .../core/unit_test/hpx/TestHPX_MDRange_e.cpp | 16 +- .../core/unit_test/hpx/TestHPX_Other.cpp | 11 +- .../unit_test/hpx/TestHPX_RangePolicy.cpp | 16 +- .../core/unit_test/hpx/TestHPX_Reducers_a.cpp | 11 +- .../core/unit_test/hpx/TestHPX_Reducers_b.cpp | 11 +- .../core/unit_test/hpx/TestHPX_Reducers_c.cpp | 11 +- .../core/unit_test/hpx/TestHPX_Reducers_d.cpp | 11 +- .../core/unit_test/hpx/TestHPX_Reductions.cpp | 11 +- .../hpx/TestHPX_Reductions_DeviceView.cpp | 46 + .../core/unit_test/hpx/TestHPX_Scan.cpp | 16 +- .../unit_test/hpx/TestHPX_SharedAlloc.cpp | 19 +- .../core/unit_test/hpx/TestHPX_SubView_a.cpp | 68 +- .../core/unit_test/hpx/TestHPX_SubView_b.cpp | 35 +- .../unit_test/hpx/TestHPX_SubView_c01.cpp | 18 +- .../unit_test/hpx/TestHPX_SubView_c02.cpp | 19 +- .../unit_test/hpx/TestHPX_SubView_c03.cpp | 19 +- .../unit_test/hpx/TestHPX_SubView_c04.cpp | 18 +- .../unit_test/hpx/TestHPX_SubView_c05.cpp | 19 +- .../unit_test/hpx/TestHPX_SubView_c06.cpp | 19 +- .../unit_test/hpx/TestHPX_SubView_c07.cpp | 18 +- .../unit_test/hpx/TestHPX_SubView_c08.cpp | 19 +- .../unit_test/hpx/TestHPX_SubView_c09.cpp | 19 +- .../unit_test/hpx/TestHPX_SubView_c10.cpp | 18 +- .../unit_test/hpx/TestHPX_SubView_c11.cpp | 19 +- .../unit_test/hpx/TestHPX_SubView_c12.cpp | 19 +- .../unit_test/hpx/TestHPX_SubView_c13.cpp | 18 +- .../core/unit_test/hpx/TestHPX_Task.cpp | 16 +- .../core/unit_test/hpx/TestHPX_Team.cpp | 58 +- .../hpx/TestHPX_TeamReductionScan.cpp | 64 +- .../unit_test/hpx/TestHPX_TeamScratch.cpp | 55 +- .../unit_test/hpx/TestHPX_TeamTeamSize.cpp | 46 + .../unit_test/hpx/TestHPX_TeamVectorRange.cpp | 17 +- .../unit_test/hpx/TestHPX_UniqueToken.cpp | 16 +- .../core/unit_test/hpx/TestHPX_ViewAPI_a.cpp | 11 +- .../core/unit_test/hpx/TestHPX_ViewAPI_b.cpp | 11 +- .../core/unit_test/hpx/TestHPX_ViewAPI_c.cpp | 11 +- .../core/unit_test/hpx/TestHPX_ViewAPI_d.cpp | 11 +- .../core/unit_test/hpx/TestHPX_ViewAPI_e.cpp | 11 +- .../TestHPX_ViewLayoutStrideAssignment.cpp | 46 + .../unit_test/hpx/TestHPX_ViewMapping_a.cpp | 12 +- .../unit_test/hpx/TestHPX_ViewMapping_b.cpp | 12 +- .../hpx/TestHPX_ViewMapping_subview.cpp | 12 +- .../unit_test/hpx/TestHPX_ViewOfClass.cpp | 12 +- .../core/unit_test/hpx/TestHPX_ViewResize.cpp | 46 + .../core/unit_test/hpx/TestHPX_View_64bit.cpp | 11 +- .../core/unit_test/hpx/TestHPX_WorkGraph.cpp | 15 +- .../core/unit_test/openmp/TestOpenMP.hpp | 33 +- ...tOpenMP_AtomicOperations_complexdouble.cpp | 16 +- ...stOpenMP_AtomicOperations_complexfloat.cpp | 16 +- .../TestOpenMP_AtomicOperations_double.cpp | 16 +- .../TestOpenMP_AtomicOperations_float.cpp | 16 +- .../TestOpenMP_AtomicOperations_int.cpp | 16 +- .../TestOpenMP_AtomicOperations_longint.cpp | 16 +- ...estOpenMP_AtomicOperations_longlongint.cpp | 16 +- ...estOpenMP_AtomicOperations_unsignedint.cpp | 16 +- ...penMP_AtomicOperations_unsignedlongint.cpp | 16 +- .../openmp/TestOpenMP_AtomicViews.cpp | 16 +- .../unit_test/openmp/TestOpenMP_Atomics.cpp | 12 +- .../unit_test/openmp/TestOpenMP_Category.hpp | 25 +- .../unit_test/openmp/TestOpenMP_Complex.cpp | 16 +- .../core/unit_test/openmp/TestOpenMP_Crs.cpp | 11 +- .../openmp/TestOpenMP_DeepCopyAlignment.cpp | 11 +- .../openmp/TestOpenMP_FunctorAnalysis.cpp | 47 + .../core/unit_test/openmp/TestOpenMP_Init.cpp | 21 +- .../unit_test/openmp/TestOpenMP_InterOp.cpp | 45 +- .../openmp/TestOpenMP_LocalDeepCopy.cpp | 12 +- .../unit_test/openmp/TestOpenMP_MDRange_a.cpp | 16 +- .../unit_test/openmp/TestOpenMP_MDRange_b.cpp | 16 +- .../unit_test/openmp/TestOpenMP_MDRange_c.cpp | 16 +- .../unit_test/openmp/TestOpenMP_MDRange_d.cpp | 16 +- .../unit_test/openmp/TestOpenMP_MDRange_e.cpp | 16 +- .../unit_test/openmp/TestOpenMP_Other.cpp | 119 +- .../openmp/TestOpenMP_RangePolicy.cpp | 16 +- .../openmp/TestOpenMP_Reducers_a.cpp | 11 +- .../openmp/TestOpenMP_Reducers_b.cpp | 11 +- .../openmp/TestOpenMP_Reducers_c.cpp | 11 +- .../openmp/TestOpenMP_Reducers_d.cpp | 11 +- .../openmp/TestOpenMP_Reductions.cpp | 11 +- .../TestOpenMP_Reductions_DeviceView.cpp | 11 +- .../core/unit_test/openmp/TestOpenMP_Scan.cpp | 16 +- .../openmp/TestOpenMP_SharedAlloc.cpp | 19 +- .../unit_test/openmp/TestOpenMP_SubView_a.cpp | 77 +- .../unit_test/openmp/TestOpenMP_SubView_b.cpp | 35 +- .../openmp/TestOpenMP_SubView_c01.cpp | 18 +- .../openmp/TestOpenMP_SubView_c02.cpp | 19 +- .../openmp/TestOpenMP_SubView_c03.cpp | 19 +- .../openmp/TestOpenMP_SubView_c04.cpp | 18 +- .../openmp/TestOpenMP_SubView_c05.cpp | 19 +- .../openmp/TestOpenMP_SubView_c06.cpp | 19 +- .../openmp/TestOpenMP_SubView_c07.cpp | 18 +- .../openmp/TestOpenMP_SubView_c08.cpp | 19 +- .../openmp/TestOpenMP_SubView_c09.cpp | 19 +- .../openmp/TestOpenMP_SubView_c10.cpp | 18 +- .../openmp/TestOpenMP_SubView_c11.cpp | 19 +- .../openmp/TestOpenMP_SubView_c12.cpp | 19 +- .../openmp/TestOpenMP_SubView_c13.cpp | 18 +- .../core/unit_test/openmp/TestOpenMP_Task.cpp | 16 +- .../core/unit_test/openmp/TestOpenMP_Team.cpp | 85 +- .../openmp/TestOpenMP_TeamReductionScan.cpp | 64 +- .../openmp/TestOpenMP_TeamScratch.cpp | 59 +- .../openmp/TestOpenMP_TeamTeamSize.cpp | 12 +- .../openmp/TestOpenMP_TeamVectorRange.cpp | 17 +- .../openmp/TestOpenMP_UniqueToken.cpp | 16 +- .../unit_test/openmp/TestOpenMP_ViewAPI_a.cpp | 11 +- .../unit_test/openmp/TestOpenMP_ViewAPI_b.cpp | 11 +- .../unit_test/openmp/TestOpenMP_ViewAPI_c.cpp | 11 +- .../unit_test/openmp/TestOpenMP_ViewAPI_d.cpp | 11 +- .../unit_test/openmp/TestOpenMP_ViewAPI_e.cpp | 11 +- .../TestOpenMP_ViewLayoutStrideAssignment.cpp | 12 +- .../openmp/TestOpenMP_ViewMapping_a.cpp | 12 +- .../openmp/TestOpenMP_ViewMapping_b.cpp | 12 +- .../openmp/TestOpenMP_ViewMapping_subview.cpp | 12 +- .../openmp/TestOpenMP_ViewOfClass.cpp | 12 +- .../openmp/TestOpenMP_ViewResize.cpp | 46 + .../openmp/TestOpenMP_View_64bit.cpp | 11 +- .../unit_test/openmp/TestOpenMP_WorkGraph.cpp | 15 +- .../openmptarget/TestOpenMPTarget.hpp | 41 +- ...PTarget_AtomicOperations_complexdouble.cpp | 16 +- ...MPTarget_AtomicOperations_complexfloat.cpp | 16 +- ...stOpenMPTarget_AtomicOperations_double.cpp | 16 +- ...estOpenMPTarget_AtomicOperations_float.cpp | 16 +- .../TestOpenMPTarget_AtomicOperations_int.cpp | 16 +- ...tOpenMPTarget_AtomicOperations_longint.cpp | 16 +- ...nMPTarget_AtomicOperations_longlongint.cpp | 16 +- ...nMPTarget_AtomicOperations_unsignedint.cpp | 16 +- ...arget_AtomicOperations_unsignedlongint.cpp | 16 +- .../TestOpenMPTarget_AtomicViews.cpp | 16 +- .../openmptarget/TestOpenMPTarget_Atomics.cpp | 12 +- .../TestOpenMPTarget_Category.hpp | 25 +- .../openmptarget/TestOpenMPTarget_Complex.cpp | 16 +- .../TestOpenMPTarget_DeepCopyAlignment.cpp | 11 +- .../openmptarget/TestOpenMPTarget_Init.cpp | 21 +- .../TestOpenMPTarget_MDRange_a.cpp | 16 +- .../TestOpenMPTarget_MDRange_b.cpp | 16 +- .../TestOpenMPTarget_MDRange_c.cpp | 16 +- .../TestOpenMPTarget_MDRange_d.cpp | 16 +- .../TestOpenMPTarget_MDRange_e.cpp | 16 +- .../openmptarget/TestOpenMPTarget_Other.cpp | 23 +- .../TestOpenMPTarget_RangePolicy.cpp | 16 +- .../TestOpenMPTarget_Reducers_a.cpp | 11 +- .../TestOpenMPTarget_Reducers_b.cpp | 11 +- .../TestOpenMPTarget_Reducers_c.cpp | 11 +- .../TestOpenMPTarget_Reducers_d.cpp | 11 +- .../TestOpenMPTarget_Reductions.cpp | 11 +- .../openmptarget/TestOpenMPTarget_Scan.cpp | 16 +- .../TestOpenMPTarget_SharedAlloc.cpp | 20 +- .../TestOpenMPTarget_SubView_a.cpp | 77 +- .../TestOpenMPTarget_SubView_b.cpp | 35 +- .../TestOpenMPTarget_SubView_c01.cpp | 18 +- .../TestOpenMPTarget_SubView_c02.cpp | 19 +- .../TestOpenMPTarget_SubView_c03.cpp | 19 +- .../TestOpenMPTarget_SubView_c04.cpp | 18 +- .../TestOpenMPTarget_SubView_c05.cpp | 19 +- .../TestOpenMPTarget_SubView_c06.cpp | 19 +- .../TestOpenMPTarget_SubView_c07.cpp | 18 +- .../TestOpenMPTarget_SubView_c08.cpp | 19 +- .../TestOpenMPTarget_SubView_c09.cpp | 19 +- .../TestOpenMPTarget_SubView_c10.cpp | 18 +- .../TestOpenMPTarget_SubView_c11.cpp | 19 +- .../TestOpenMPTarget_SubView_c12.cpp | 19 +- .../openmptarget/TestOpenMPTarget_Team.cpp | 58 +- .../TestOpenMPTarget_TeamReductionScan.cpp | 64 +- .../TestOpenMPTarget_TeamScratch.cpp | 55 +- .../TestOpenMPTarget_ViewAPI_a.cpp | 11 +- .../TestOpenMPTarget_ViewAPI_b.cpp | 11 +- .../TestOpenMPTarget_ViewAPI_c.cpp | 11 +- .../TestOpenMPTarget_ViewAPI_d.cpp | 11 +- .../TestOpenMPTarget_ViewAPI_e.cpp | 11 +- .../TestOpenMPTarget_ViewMapping_a.cpp | 12 +- .../TestOpenMPTarget_ViewMapping_b.cpp | 12 +- .../TestOpenMPTarget_ViewMapping_subview.cpp | 12 +- .../TestOpenMPTarget_ViewOfClass.cpp | 12 +- ...threads_AtomicOperations_complexdouble.cpp | 16 +- ...qthreads_AtomicOperations_complexfloat.cpp | 16 +- .../TestQqthreads_AtomicOperations_double.cpp | 16 +- .../TestQqthreads_AtomicOperations_float.cpp | 16 +- .../TestQqthreads_AtomicOperations_int.cpp | 16 +- ...TestQqthreads_AtomicOperations_longint.cpp | 16 +- ...Qqthreads_AtomicOperations_longlongint.cpp | 16 +- ...Qqthreads_AtomicOperations_unsignedint.cpp | 16 +- ...reads_AtomicOperations_unsignedlongint.cpp | 16 +- .../qthreads/TestQqthreads_MDRange_a.cpp | 16 +- .../qthreads/TestQqthreads_MDRange_b.cpp | 16 +- .../qthreads/TestQqthreads_MDRange_c.cpp | 16 +- .../qthreads/TestQqthreads_MDRange_d.cpp | 16 +- .../qthreads/TestQqthreads_MDRange_e.cpp | 16 +- .../qthreads/TestQqthreads_ViewAPI_a.cpp | 11 +- .../qthreads/TestQqthreads_ViewAPI_b.cpp | 11 +- .../qthreads/TestQqthreads_ViewAPI_c.cpp | 11 +- .../qthreads/TestQqthreads_ViewAPI_d.cpp | 11 +- .../qthreads/TestQqthreads_ViewAPI_e.cpp | 11 +- .../core/unit_test/qthreads/TestQthreads.hpp | 42 +- .../qthreads/TestQthreads_Atomics.cpp | 28 +- .../qthreads/TestQthreads_Category.hpp | 25 +- .../qthreads/TestQthreads_Complex.cpp | 5 +- .../TestQthreads_DeepCopyAlignment.cpp | 11 +- .../unit_test/qthreads/TestQthreads_Other.cpp | 57 +- .../qthreads/TestQthreads_Reductions.cpp | 49 +- .../qthreads/TestQthreads_SubView_a.cpp | 46 +- .../qthreads/TestQthreads_SubView_b.cpp | 19 +- .../qthreads/TestQthreads_SubView_c01.cpp | 16 +- .../qthreads/TestQthreads_SubView_c02.cpp | 16 +- .../qthreads/TestQthreads_SubView_c03.cpp | 16 +- .../qthreads/TestQthreads_SubView_c04.cpp | 16 +- .../qthreads/TestQthreads_SubView_c05.cpp | 16 +- .../qthreads/TestQthreads_SubView_c06.cpp | 16 +- .../qthreads/TestQthreads_SubView_c07.cpp | 16 +- .../qthreads/TestQthreads_SubView_c08.cpp | 16 +- .../qthreads/TestQthreads_SubView_c09.cpp | 16 +- .../qthreads/TestQthreads_SubView_c10.cpp | 16 +- .../qthreads/TestQthreads_SubView_c11.cpp | 16 +- .../qthreads/TestQthreads_SubView_c12.cpp | 16 +- .../qthreads/TestQthreads_SubView_c13.cpp | 16 +- .../unit_test/qthreads/TestQthreads_Team.cpp | 41 +- .../qthreads/TestQthreads_ViewAPI_a.cpp | 16 +- .../qthreads/TestQthreads_ViewAPI_b.cpp | 34 +- .../rocm/TestROCmHostPinned_Category.hpp | 25 +- .../rocm/TestROCmHostPinned_SharedAlloc.cpp | 19 +- .../rocm/TestROCmHostPinned_ViewAPI_a.cpp | 11 +- .../rocm/TestROCmHostPinned_ViewAPI_b.cpp | 11 +- .../rocm/TestROCmHostPinned_ViewAPI_c.cpp | 11 +- .../rocm/TestROCmHostPinned_ViewAPI_d.cpp | 11 +- .../rocm/TestROCmHostPinned_ViewAPI_e.cpp | 11 +- .../rocm/TestROCmHostPinned_ViewCopy.cpp | 11 +- .../rocm/TestROCmHostPinned_ViewMapping_a.cpp | 12 +- .../rocm/TestROCmHostPinned_ViewMapping_b.cpp | 12 +- ...TestROCmHostPinned_ViewMapping_subview.cpp | 12 +- .../rocm/TestROCmHostPinned_View_64bit.cpp | 11 +- .../rocm/TestROCm_AtomicOperations_double.cpp | 16 +- .../rocm/TestROCm_AtomicOperations_float.cpp | 16 +- .../rocm/TestROCm_AtomicOperations_int.cpp | 16 +- .../TestROCm_AtomicOperations_longint.cpp | 16 +- .../TestROCm_AtomicOperations_longlongint.cpp | 16 +- .../TestROCm_AtomicOperations_unsignedint.cpp | 16 +- ...tROCm_AtomicOperations_unsignedlongint.cpp | 16 +- .../unit_test/rocm/TestROCm_AtomicViews.cpp | 16 +- .../core/unit_test/rocm/TestROCm_Atomics.cpp | 12 +- .../core/unit_test/rocm/TestROCm_Category.hpp | 25 +- .../core/unit_test/rocm/TestROCm_Complex.cpp | 16 +- .../core/unit_test/rocm/TestROCm_Crs.cpp | 16 +- .../rocm/TestROCm_DeepCopyAlignment.cpp | 11 +- .../core/unit_test/rocm/TestROCm_Init.cpp | 21 +- .../rocm/TestROCm_MDRangeReduce_a.cpp | 22 +- .../rocm/TestROCm_MDRangeReduce_b.cpp | 22 +- .../rocm/TestROCm_MDRangeReduce_c.cpp | 22 +- .../rocm/TestROCm_MDRangeReduce_d.cpp | 22 +- .../rocm/TestROCm_MDRangeReduce_e.cpp | 22 +- .../unit_test/rocm/TestROCm_MDRange_a.cpp | 16 +- .../unit_test/rocm/TestROCm_MDRange_b.cpp | 16 +- .../unit_test/rocm/TestROCm_MDRange_c.cpp | 16 +- .../unit_test/rocm/TestROCm_MDRange_d.cpp | 16 +- .../unit_test/rocm/TestROCm_MDRange_e.cpp | 16 +- .../core/unit_test/rocm/TestROCm_Other.cpp | 25 +- .../unit_test/rocm/TestROCm_RangePolicy.cpp | 16 +- .../unit_test/rocm/TestROCm_Reducers_a.cpp | 11 +- .../unit_test/rocm/TestROCm_Reducers_b.cpp | 11 +- .../unit_test/rocm/TestROCm_Reducers_c.cpp | 11 +- .../unit_test/rocm/TestROCm_Reducers_d.cpp | 11 +- .../unit_test/rocm/TestROCm_Reductions.cpp | 11 +- .../core/unit_test/rocm/TestROCm_Scan.cpp | 16 +- .../unit_test/rocm/TestROCm_SharedAlloc.cpp | 20 +- .../core/unit_test/rocm/TestROCm_Spaces.cpp | 205 +- .../unit_test/rocm/TestROCm_SubView_a.cpp | 77 +- .../unit_test/rocm/TestROCm_SubView_b.cpp | 35 +- .../unit_test/rocm/TestROCm_SubView_c01.cpp | 18 +- .../unit_test/rocm/TestROCm_SubView_c02.cpp | 19 +- .../unit_test/rocm/TestROCm_SubView_c03.cpp | 19 +- .../unit_test/rocm/TestROCm_SubView_c04.cpp | 18 +- .../unit_test/rocm/TestROCm_SubView_c05.cpp | 19 +- .../unit_test/rocm/TestROCm_SubView_c06.cpp | 19 +- .../unit_test/rocm/TestROCm_SubView_c07.cpp | 18 +- .../unit_test/rocm/TestROCm_SubView_c08.cpp | 19 +- .../unit_test/rocm/TestROCm_SubView_c09.cpp | 19 +- .../unit_test/rocm/TestROCm_SubView_c10.cpp | 18 +- .../unit_test/rocm/TestROCm_SubView_c11.cpp | 19 +- .../unit_test/rocm/TestROCm_SubView_c12.cpp | 19 +- .../unit_test/rocm/TestROCm_SubView_c13.cpp | 18 +- .../core/unit_test/rocm/TestROCm_Team.cpp | 58 +- .../rocm/TestROCm_TeamReductionScan.cpp | 63 +- .../unit_test/rocm/TestROCm_TeamScratch.cpp | 59 +- .../unit_test/rocm/TestROCm_TeamTeamSize.cpp | 11 +- .../unit_test/rocm/TestROCm_ViewAPI_a.cpp | 11 +- .../unit_test/rocm/TestROCm_ViewAPI_b.cpp | 11 +- .../unit_test/rocm/TestROCm_ViewAPI_c.cpp | 11 +- .../unit_test/rocm/TestROCm_ViewAPI_d.cpp | 11 +- .../unit_test/rocm/TestROCm_ViewAPI_e.cpp | 11 +- .../unit_test/rocm/TestROCm_ViewMapping_a.cpp | 12 +- .../unit_test/rocm/TestROCm_ViewMapping_b.cpp | 12 +- .../rocm/TestROCm_ViewMapping_subview.cpp | 12 +- .../unit_test/rocm/TestROCm_ViewOfClass.cpp | 12 +- ...tSerial_AtomicOperations_complexdouble.cpp | 16 +- ...stSerial_AtomicOperations_complexfloat.cpp | 16 +- .../TestSerial_AtomicOperations_double.cpp | 16 +- .../TestSerial_AtomicOperations_float.cpp | 16 +- .../TestSerial_AtomicOperations_int.cpp | 16 +- .../TestSerial_AtomicOperations_longint.cpp | 16 +- ...estSerial_AtomicOperations_longlongint.cpp | 16 +- ...estSerial_AtomicOperations_unsignedint.cpp | 16 +- ...erial_AtomicOperations_unsignedlongint.cpp | 16 +- .../serial/TestSerial_AtomicViews.cpp | 16 +- .../unit_test/serial/TestSerial_Atomics.cpp | 12 +- .../unit_test/serial/TestSerial_Category.hpp | 25 +- .../unit_test/serial/TestSerial_Complex.cpp | 16 +- .../core/unit_test/serial/TestSerial_Crs.cpp | 11 +- .../serial/TestSerial_DeepCopyAlignment.cpp | 11 +- .../serial/TestSerial_FunctorAnalysis.cpp | 47 + .../core/unit_test/serial/TestSerial_Init.cpp | 21 +- .../serial/TestSerial_LocalDeepCopy.cpp | 12 +- .../unit_test/serial/TestSerial_MDRange_a.cpp | 16 +- .../unit_test/serial/TestSerial_MDRange_b.cpp | 16 +- .../unit_test/serial/TestSerial_MDRange_c.cpp | 16 +- .../unit_test/serial/TestSerial_MDRange_d.cpp | 16 +- .../unit_test/serial/TestSerial_MDRange_e.cpp | 16 +- .../unit_test/serial/TestSerial_Other.cpp | 27 +- .../serial/TestSerial_RangePolicy.cpp | 16 +- .../serial/TestSerial_Reducers_a.cpp | 11 +- .../serial/TestSerial_Reducers_b.cpp | 11 +- .../serial/TestSerial_Reducers_c.cpp | 11 +- .../serial/TestSerial_Reducers_d.cpp | 11 +- .../serial/TestSerial_Reductions.cpp | 11 +- .../TestSerial_Reductions_DeviceView.cpp | 11 +- .../core/unit_test/serial/TestSerial_Scan.cpp | 16 +- .../serial/TestSerial_SharedAlloc.cpp | 19 +- .../unit_test/serial/TestSerial_SubView_a.cpp | 77 +- .../unit_test/serial/TestSerial_SubView_b.cpp | 35 +- .../serial/TestSerial_SubView_c01.cpp | 18 +- .../serial/TestSerial_SubView_c02.cpp | 19 +- .../serial/TestSerial_SubView_c03.cpp | 19 +- .../serial/TestSerial_SubView_c04.cpp | 18 +- .../serial/TestSerial_SubView_c05.cpp | 19 +- .../serial/TestSerial_SubView_c06.cpp | 19 +- .../serial/TestSerial_SubView_c07.cpp | 18 +- .../serial/TestSerial_SubView_c08.cpp | 19 +- .../serial/TestSerial_SubView_c09.cpp | 19 +- .../serial/TestSerial_SubView_c10.cpp | 18 +- .../serial/TestSerial_SubView_c11.cpp | 19 +- .../serial/TestSerial_SubView_c12.cpp | 19 +- .../serial/TestSerial_SubView_c13.cpp | 18 +- .../core/unit_test/serial/TestSerial_Task.cpp | 16 +- .../core/unit_test/serial/TestSerial_Team.cpp | 85 +- .../serial/TestSerial_TeamReductionScan.cpp | 64 +- .../serial/TestSerial_TeamScratch.cpp | 59 +- .../serial/TestSerial_TeamTeamSize.cpp | 11 +- .../serial/TestSerial_TeamVectorRange.cpp | 17 +- .../serial/TestSerial_UniqueToken.cpp | 46 + .../unit_test/serial/TestSerial_ViewAPI_a.cpp | 11 +- .../unit_test/serial/TestSerial_ViewAPI_b.cpp | 11 +- .../unit_test/serial/TestSerial_ViewAPI_c.cpp | 11 +- .../unit_test/serial/TestSerial_ViewAPI_d.cpp | 11 +- .../unit_test/serial/TestSerial_ViewAPI_e.cpp | 12 +- .../TestSerial_ViewLayoutStrideAssignment.cpp | 12 +- .../serial/TestSerial_ViewMapping_a.cpp | 12 +- .../serial/TestSerial_ViewMapping_b.cpp | 12 +- .../serial/TestSerial_ViewMapping_subview.cpp | 12 +- .../serial/TestSerial_ViewOfClass.cpp | 12 +- .../serial/TestSerial_ViewResize.cpp | 46 + .../serial/TestSerial_View_64bit.cpp | 11 +- .../unit_test/serial/TestSerial_WorkGraph.cpp | 15 +- lib/kokkos/core/unit_test/standalone/Makefile | 7 +- .../unit_test/standalone/UnitTestMainInit.cpp | 23 +- ...Threads_AtomicOperations_complexdouble.cpp | 16 +- ...tThreads_AtomicOperations_complexfloat.cpp | 16 +- .../TestThreads_AtomicOperations_double.cpp | 16 +- .../TestThreads_AtomicOperations_float.cpp | 16 +- .../TestThreads_AtomicOperations_int.cpp | 16 +- .../TestThreads_AtomicOperations_longint.cpp | 16 +- ...stThreads_AtomicOperations_longlongint.cpp | 16 +- ...stThreads_AtomicOperations_unsignedint.cpp | 16 +- ...reads_AtomicOperations_unsignedlongint.cpp | 16 +- .../threads/TestThreads_AtomicViews.cpp | 16 +- .../unit_test/threads/TestThreads_Atomics.cpp | 12 +- .../threads/TestThreads_Category.hpp | 25 +- .../unit_test/threads/TestThreads_Complex.cpp | 16 +- .../unit_test/threads/TestThreads_Crs.cpp | 15 +- .../threads/TestThreads_DeepCopyAlignment.cpp | 11 +- .../threads/TestThreads_FunctorAnalysis.cpp | 47 + .../unit_test/threads/TestThreads_Init.cpp | 21 +- .../threads/TestThreads_LocalDeepCopy.cpp | 12 +- .../threads/TestThreads_MDRange_a.cpp | 16 +- .../threads/TestThreads_MDRange_b.cpp | 16 +- .../threads/TestThreads_MDRange_c.cpp | 16 +- .../threads/TestThreads_MDRange_d.cpp | 16 +- .../threads/TestThreads_MDRange_e.cpp | 16 +- .../unit_test/threads/TestThreads_Other.cpp | 27 +- .../threads/TestThreads_RangePolicy.cpp | 16 +- .../threads/TestThreads_Reducers_a.cpp | 11 +- .../threads/TestThreads_Reducers_b.cpp | 11 +- .../threads/TestThreads_Reducers_c.cpp | 11 +- .../threads/TestThreads_Reducers_d.cpp | 11 +- .../threads/TestThreads_Reductions.cpp | 11 +- .../TestThreads_Reductions_DeviceView.cpp | 11 +- .../unit_test/threads/TestThreads_Scan.cpp | 16 +- .../threads/TestThreads_SharedAlloc.cpp | 19 +- .../threads/TestThreads_SubView_a.cpp | 77 +- .../threads/TestThreads_SubView_b.cpp | 35 +- .../threads/TestThreads_SubView_c01.cpp | 18 +- .../threads/TestThreads_SubView_c02.cpp | 19 +- .../threads/TestThreads_SubView_c03.cpp | 19 +- .../threads/TestThreads_SubView_c04.cpp | 18 +- .../threads/TestThreads_SubView_c05.cpp | 19 +- .../threads/TestThreads_SubView_c06.cpp | 19 +- .../threads/TestThreads_SubView_c07.cpp | 18 +- .../threads/TestThreads_SubView_c08.cpp | 19 +- .../threads/TestThreads_SubView_c09.cpp | 19 +- .../threads/TestThreads_SubView_c10.cpp | 18 +- .../threads/TestThreads_SubView_c11.cpp | 19 +- .../threads/TestThreads_SubView_c12.cpp | 19 +- .../threads/TestThreads_SubView_c13.cpp | 18 +- .../unit_test/threads/TestThreads_Team.cpp | 85 +- .../threads/TestThreads_TeamReductionScan.cpp | 64 +- .../threads/TestThreads_TeamScratch.cpp | 59 +- .../threads/TestThreads_TeamTeamSize.cpp | 13 +- .../threads/TestThreads_TeamVectorRange.cpp | 17 +- .../threads/TestThreads_UniqueToken.cpp | 46 + .../threads/TestThreads_ViewAPI_a.cpp | 11 +- .../threads/TestThreads_ViewAPI_b.cpp | 11 +- .../threads/TestThreads_ViewAPI_c.cpp | 11 +- .../threads/TestThreads_ViewAPI_d.cpp | 11 +- .../threads/TestThreads_ViewAPI_e.cpp | 11 +- ...TestThreads_ViewLayoutStrideAssignment.cpp | 12 +- .../threads/TestThreads_ViewMapping_a.cpp | 12 +- .../threads/TestThreads_ViewMapping_b.cpp | 12 +- .../TestThreads_ViewMapping_subview.cpp | 12 +- .../threads/TestThreads_ViewOfClass.cpp | 12 +- .../threads/TestThreads_ViewResize.cpp | 46 + .../threads/TestThreads_View_64bit.cpp | 11 +- .../threads/TestThreads_WorkGraph.cpp | 15 +- lib/kokkos/example/CMakeLists.txt | 28 +- .../CMakeLists.txt | 0 .../cmake_example.cpp | 17 +- .../foo.f | 0 .../build_cmake_installed/CMakeLists.txt | 42 + .../cmake_example.cpp} | 68 +- .../example/build_cmake_installed/foo.f | 4 + lib/kokkos/example/common/VectorImport.hpp | 294 - lib/kokkos/example/common/WrapMPI.hpp | 103 - lib/kokkos/example/feint/CMakeLists.txt | 18 - lib/kokkos/example/feint/ElemFunctor.hpp | 485 -- lib/kokkos/example/feint/Makefile | 71 - lib/kokkos/example/feint/feint.hpp | 165 - lib/kokkos/example/feint/feint_cuda.cpp | 67 - lib/kokkos/example/feint/feint_hpx.cpp | 67 - lib/kokkos/example/feint/feint_rocm.cpp | 67 - lib/kokkos/example/feint/feint_threads.cpp | 67 - lib/kokkos/example/fenl/CGSolve.hpp | 300 - lib/kokkos/example/fenl/CMakeLists.txt | 17 - lib/kokkos/example/fenl/Makefile | 50 - lib/kokkos/example/fenl/fenl.cpp | 181 - lib/kokkos/example/fenl/fenl.hpp | 89 - lib/kokkos/example/fenl/fenl_functors.hpp | 1173 ---- lib/kokkos/example/fenl/fenl_impl.hpp | 598 -- lib/kokkos/example/fenl/main.cpp | 367 -- lib/kokkos/example/fixture/BoxElemFixture.hpp | 355 -- lib/kokkos/example/fixture/BoxElemPart.cpp | 413 -- lib/kokkos/example/fixture/BoxElemPart.hpp | 320 - lib/kokkos/example/fixture/CMakeLists.txt | 13 - lib/kokkos/example/fixture/HexElement.hpp | 270 - lib/kokkos/example/fixture/Main.cpp | 307 - lib/kokkos/example/fixture/Makefile | 46 - lib/kokkos/example/fixture/TestFixture.hpp | 156 - .../example/global_2_local_ids/CMakeLists.txt | 17 - lib/kokkos/example/global_2_local_ids/G2L.hpp | 266 - .../example/global_2_local_ids/G2L_Main.cpp | 158 - .../example/global_2_local_ids/Makefile | 46 - lib/kokkos/example/grow_array/CMakeLists.txt | 14 - lib/kokkos/example/grow_array/Makefile | 46 - lib/kokkos/example/grow_array/grow_array.hpp | 257 - lib/kokkos/example/grow_array/main.cpp | 110 - lib/kokkos/example/make_buildlink/main.cpp | 13 +- lib/kokkos/example/md_skeleton/CMakeLists.txt | 16 - lib/kokkos/example/md_skeleton/Makefile | 46 - lib/kokkos/example/md_skeleton/README | 3 - lib/kokkos/example/md_skeleton/force.cpp | 184 - lib/kokkos/example/md_skeleton/main.cpp | 205 - lib/kokkos/example/md_skeleton/neighbor.cpp | 430 -- lib/kokkos/example/md_skeleton/setup.cpp | 271 - lib/kokkos/example/md_skeleton/system.h | 92 - lib/kokkos/example/md_skeleton/types.h | 118 - .../example/multi_fem/BoxMeshFixture.hpp | 610 -- .../example/multi_fem/BoxMeshPartition.cpp | 381 -- .../example/multi_fem/BoxMeshPartition.hpp | 210 - lib/kokkos/example/multi_fem/CMakeLists.txt | 16 - lib/kokkos/example/multi_fem/Explicit.hpp | 452 -- .../example/multi_fem/ExplicitFunctors.hpp | 1471 ----- lib/kokkos/example/multi_fem/FEMesh.hpp | 86 - lib/kokkos/example/multi_fem/HexElement.hpp | 268 - .../multi_fem/HexExplicitFunctions.hpp | 443 -- lib/kokkos/example/multi_fem/Implicit.hpp | 341 - .../example/multi_fem/ImplicitFunctors.hpp | 585 -- lib/kokkos/example/multi_fem/LinAlgBLAS.hpp | 567 -- lib/kokkos/example/multi_fem/Makefile | 49 - lib/kokkos/example/multi_fem/Nonlinear.hpp | 573 -- .../multi_fem/NonlinearElement_Cuda.hpp | 390 -- .../example/multi_fem/NonlinearFunctors.hpp | 482 -- lib/kokkos/example/multi_fem/ParallelComm.hpp | 167 - .../example/multi_fem/ParallelDataMap.hpp | 517 -- .../example/multi_fem/ParallelMachine.cpp | 178 - .../example/multi_fem/ParallelMachine.hpp | 118 - .../example/multi_fem/SparseLinearSystem.hpp | 404 -- .../multi_fem/SparseLinearSystemFill.hpp | 276 - .../multi_fem/SparseLinearSystem_Cuda.hpp | 164 - .../example/multi_fem/TestBoxMeshFixture.hpp | 242 - .../multi_fem/TestBoxMeshPartition.cpp | 172 - lib/kokkos/example/multi_fem/TestCuda.cpp | 188 - lib/kokkos/example/multi_fem/TestHost.cpp | 142 - .../example/multi_fem/TestHybridFEM.cpp | 348 -- .../example/query_device/CMakeLists.txt | 10 +- .../example/query_device/query_device.cpp | 58 +- lib/kokkos/example/sort_array/CMakeLists.txt | 14 - lib/kokkos/example/sort_array/Makefile | 46 - lib/kokkos/example/sort_array/main.cpp | 95 - lib/kokkos/example/sort_array/sort_array.hpp | 190 - .../tutorial/01_hello_world/CMakeLists.txt | 9 +- .../tutorial/01_hello_world/hello_world.cpp | 36 +- .../01_hello_world_lambda/CMakeLists.txt | 17 +- .../hello_world_lambda.cpp | 31 +- .../tutorial/02_simple_reduce/CMakeLists.txt | 9 +- .../02_simple_reduce/simple_reduce.cpp | 46 +- .../02_simple_reduce_lambda/CMakeLists.txt | 17 +- .../simple_reduce_lambda.cpp | 49 +- .../tutorial/03_simple_view/CMakeLists.txt | 9 +- .../example/tutorial/03_simple_view/Makefile | 2 +- .../tutorial/03_simple_view/simple_view.cpp | 56 +- .../03_simple_view_lambda/CMakeLists.txt | 6 +- .../simple_view_lambda.cpp | 78 +- .../04_simple_memoryspaces/CMakeLists.txt | 5 +- .../simple_memoryspaces.cpp | 44 +- .../tutorial/05_simple_atomics/CMakeLists.txt | 6 +- .../05_simple_atomics/simple_atomics.cpp | 76 +- .../06_simple_mdrangepolicy/CMakeLists.txt | 6 +- .../simple_mdrangepolicy.cpp | 130 +- .../01_data_layouts/CMakeLists.txt | 5 +- .../01_data_layouts/data_layouts.cpp | 72 +- .../02_memory_traits/CMakeLists.txt | 5 +- .../02_memory_traits/memory_traits.cpp | 86 +- .../Advanced_Views/03_subviews/CMakeLists.txt | 5 +- .../Advanced_Views/03_subviews/subviews.cpp | 108 +- .../04_dualviews/CMakeLists.txt | 5 +- .../Advanced_Views/04_dualviews/dual_view.cpp | 209 +- .../05_NVIDIA_UVM/CMakeLists.txt | 14 +- .../05_NVIDIA_UVM/uvm_example.cpp | 91 +- .../overlapping_deepcopy.cpp | 129 +- .../tutorial/Advanced_Views/CMakeLists.txt | 12 +- .../01_random_numbers/random_numbers.cpp | 182 +- lib/kokkos/example/tutorial/CMakeLists.txt | 22 +- .../01_thread_teams/CMakeLists.txt | 5 +- .../01_thread_teams/thread_teams.cpp | 67 +- .../01_thread_teams_lambda/CMakeLists.txt | 13 +- .../thread_teams_lambda.cpp | 53 +- .../02_nested_parallel_for/CMakeLists.txt | 5 +- .../nested_parallel_for.cpp | 81 +- .../03_vectorization/CMakeLists.txt | 10 +- .../03_vectorization/vectorization.cpp | 156 +- .../04_team_scan/CMakeLists.txt | 6 +- .../04_team_scan/team_scan.cpp | 151 +- .../Hierarchical_Parallelism/CMakeLists.txt | 10 +- .../tutorial/launch_bounds/CMakeLists.txt | 5 +- .../launch_bounds/launch_bounds_reduce.cpp | 199 +- .../example/virtual_functions/classes.cpp | 22 +- .../example/virtual_functions/classes.hpp | 48 +- lib/kokkos/example/virtual_functions/main.cpp | 52 +- lib/kokkos/generate_makefile.bash | 100 +- lib/kokkos/master_history.txt | 1 + 2169 files changed, 121961 insertions(+), 127047 deletions(-) create mode 100644 lib/kokkos/BUILD.md create mode 100644 lib/kokkos/CONTRIBUTING.md delete mode 100644 lib/kokkos/README create mode 100644 lib/kokkos/README.md create mode 100755 lib/kokkos/cm_generate_makefile.bash create mode 100644 lib/kokkos/cmake/KokkosConfigCommon.cmake.in create mode 100644 lib/kokkos/cmake/KokkosCore_config.h.in delete mode 100644 lib/kokkos/cmake/Makefile.generate_cmake_settings delete mode 100644 lib/kokkos/cmake/Modules/FindHWLOC.cmake delete mode 100644 lib/kokkos/cmake/Modules/FindMemkind.cmake delete mode 100644 lib/kokkos/cmake/Modules/FindQthreads.cmake create mode 100644 lib/kokkos/cmake/Modules/FindTPLCUDA.cmake create mode 100644 lib/kokkos/cmake/Modules/FindTPLHPX.cmake create mode 100644 lib/kokkos/cmake/Modules/FindTPLHWLOC.cmake create mode 100644 lib/kokkos/cmake/Modules/FindTPLLIBDL.cmake create mode 100644 lib/kokkos/cmake/Modules/FindTPLLIBNUMA.cmake create mode 100644 lib/kokkos/cmake/Modules/FindTPLLIBRT.cmake create mode 100644 lib/kokkos/cmake/Modules/FindTPLMEMKIND.cmake create mode 100644 lib/kokkos/cmake/Modules/FindTPLPTHREAD.cmake create mode 100644 lib/kokkos/cmake/README.md create mode 100644 lib/kokkos/cmake/compile_tests/clang_omp.cpp create mode 100644 lib/kokkos/cmake/compile_tests/pthread.cpp create mode 100644 lib/kokkos/cmake/cray.cmake delete mode 100644 lib/kokkos/cmake/deps/QTHREADS.cmake create mode 100644 lib/kokkos/cmake/fake_tribits.cmake create mode 100644 lib/kokkos/cmake/gnu.cmake create mode 100644 lib/kokkos/cmake/intel.cmake create mode 100644 lib/kokkos/cmake/kokkos_arch.cmake delete mode 100644 lib/kokkos/cmake/kokkos_build.cmake create mode 100644 lib/kokkos/cmake/kokkos_compiler_id.cmake create mode 100644 lib/kokkos/cmake/kokkos_corner_cases.cmake create mode 100644 lib/kokkos/cmake/kokkos_enable_devices.cmake create mode 100644 lib/kokkos/cmake/kokkos_enable_options.cmake create mode 100644 lib/kokkos/cmake/kokkos_install.cmake delete mode 100644 lib/kokkos/cmake/kokkos_options.cmake create mode 100644 lib/kokkos/cmake/kokkos_pick_cxx_std.cmake delete mode 100644 lib/kokkos/cmake/kokkos_settings.cmake create mode 100644 lib/kokkos/cmake/kokkos_test_cxx_std.cmake create mode 100644 lib/kokkos/cmake/kokkos_tpls.cmake create mode 100644 lib/kokkos/cmake/kokkos_tribits.cmake create mode 100644 lib/kokkos/cmake/pgi.cmake delete mode 100644 lib/kokkos/cmake/tpls/FindTPLQTHREADS.cmake delete mode 100644 lib/kokkos/cmake/tribits.cmake create mode 100644 lib/kokkos/core/src/HPX/Kokkos_HPX_ChunkedRoundRobinExecutor.hpp delete mode 100644 lib/kokkos/core/src/Makefile delete mode 100644 lib/kokkos/core/src/Makefile.generate_build_files delete mode 100644 lib/kokkos/core/src/Makefile.generate_header_lists create mode 100644 lib/kokkos/core/src/dummy.cpp create mode 100644 lib/kokkos/core/src/impl/Kokkos_MemorySpace.hpp create mode 100644 lib/kokkos/core/src/impl/Kokkos_Stacktrace.cpp create mode 100644 lib/kokkos/core/src/impl/Kokkos_Stacktrace.hpp rename lib/kokkos/{example/feint/feint_fwd.hpp => core/unit_test/TestStackTrace.cpp} (69%) create mode 100644 lib/kokkos/core/unit_test/TestStackTrace.hpp rename lib/kokkos/{example/feint/feint_openmp.cpp => core/unit_test/TestStackTrace_f0.cpp} (67%) rename lib/kokkos/{example/fixture/TestFixture.cpp => core/unit_test/TestStackTrace_f1.cpp} (69%) rename lib/kokkos/{example/feint/feint_serial.cpp => core/unit_test/TestStackTrace_f2.cpp} (67%) create mode 100644 lib/kokkos/core/unit_test/TestStackTrace_f3.cpp create mode 100644 lib/kokkos/core/unit_test/TestStackTrace_f4.cpp create mode 100644 lib/kokkos/core/unit_test/TestViewResize.hpp create mode 100644 lib/kokkos/core/unit_test/configuration/test-code/CMakeLists.txt create mode 100644 lib/kokkos/core/unit_test/configuration/test-code/Makefile create mode 100644 lib/kokkos/core/unit_test/configuration/test-code/main.cpp create mode 100755 lib/kokkos/core/unit_test/configuration/test-code/test_config.bash create mode 100755 lib/kokkos/core/unit_test/configuration/test-code/test_config_arch_list.bash create mode 100755 lib/kokkos/core/unit_test/configuration/test-code/test_config_device_list.bash create mode 100755 lib/kokkos/core/unit_test/configuration/test-code/test_config_options_list.bash create mode 100755 lib/kokkos/core/unit_test/configuration/test-code/test_config_run.bash create mode 100644 lib/kokkos/core/unit_test/cuda/TestCuda_DebugPinUVMSpace.cpp create mode 100644 lib/kokkos/core/unit_test/cuda/TestCuda_DebugSerialExecution.cpp create mode 100644 lib/kokkos/core/unit_test/cuda/TestCuda_FunctorAnalysis.cpp create mode 100644 lib/kokkos/core/unit_test/cuda/TestCuda_ViewResize.cpp create mode 100644 lib/kokkos/core/unit_test/hpx/TestHPX_AtomicOperations_complexdouble.cpp create mode 100644 lib/kokkos/core/unit_test/hpx/TestHPX_AtomicOperations_complexfloat.cpp create mode 100644 lib/kokkos/core/unit_test/hpx/TestHPX_DeepCopyAlignment.cpp create mode 100644 lib/kokkos/core/unit_test/hpx/TestHPX_FunctorAnalysis.cpp create mode 100644 lib/kokkos/core/unit_test/hpx/TestHPX_LocalDeepCopy.cpp create mode 100644 lib/kokkos/core/unit_test/hpx/TestHPX_Reductions_DeviceView.cpp create mode 100644 lib/kokkos/core/unit_test/hpx/TestHPX_TeamTeamSize.cpp create mode 100644 lib/kokkos/core/unit_test/hpx/TestHPX_ViewLayoutStrideAssignment.cpp create mode 100644 lib/kokkos/core/unit_test/hpx/TestHPX_ViewResize.cpp create mode 100644 lib/kokkos/core/unit_test/openmp/TestOpenMP_FunctorAnalysis.cpp create mode 100644 lib/kokkos/core/unit_test/openmp/TestOpenMP_ViewResize.cpp create mode 100644 lib/kokkos/core/unit_test/serial/TestSerial_FunctorAnalysis.cpp create mode 100644 lib/kokkos/core/unit_test/serial/TestSerial_UniqueToken.cpp create mode 100644 lib/kokkos/core/unit_test/serial/TestSerial_ViewResize.cpp create mode 100644 lib/kokkos/core/unit_test/threads/TestThreads_FunctorAnalysis.cpp create mode 100644 lib/kokkos/core/unit_test/threads/TestThreads_UniqueToken.cpp create mode 100644 lib/kokkos/core/unit_test/threads/TestThreads_ViewResize.cpp rename lib/kokkos/example/{cmake_build => build_cmake_in_tree}/CMakeLists.txt (100%) rename lib/kokkos/example/{cmake_build => build_cmake_in_tree}/cmake_example.cpp (85%) rename lib/kokkos/example/{cmake_build => build_cmake_in_tree}/foo.f (100%) create mode 100644 lib/kokkos/example/build_cmake_installed/CMakeLists.txt rename lib/kokkos/example/{feint/main.cpp => build_cmake_installed/cmake_example.cpp} (55%) create mode 100644 lib/kokkos/example/build_cmake_installed/foo.f delete mode 100644 lib/kokkos/example/common/VectorImport.hpp delete mode 100644 lib/kokkos/example/common/WrapMPI.hpp delete mode 100644 lib/kokkos/example/feint/CMakeLists.txt delete mode 100644 lib/kokkos/example/feint/ElemFunctor.hpp delete mode 100644 lib/kokkos/example/feint/Makefile delete mode 100644 lib/kokkos/example/feint/feint.hpp delete mode 100644 lib/kokkos/example/feint/feint_cuda.cpp delete mode 100644 lib/kokkos/example/feint/feint_hpx.cpp delete mode 100644 lib/kokkos/example/feint/feint_rocm.cpp delete mode 100644 lib/kokkos/example/feint/feint_threads.cpp delete mode 100644 lib/kokkos/example/fenl/CGSolve.hpp delete mode 100644 lib/kokkos/example/fenl/CMakeLists.txt delete mode 100644 lib/kokkos/example/fenl/Makefile delete mode 100644 lib/kokkos/example/fenl/fenl.cpp delete mode 100644 lib/kokkos/example/fenl/fenl.hpp delete mode 100644 lib/kokkos/example/fenl/fenl_functors.hpp delete mode 100644 lib/kokkos/example/fenl/fenl_impl.hpp delete mode 100644 lib/kokkos/example/fenl/main.cpp delete mode 100644 lib/kokkos/example/fixture/BoxElemFixture.hpp delete mode 100644 lib/kokkos/example/fixture/BoxElemPart.cpp delete mode 100644 lib/kokkos/example/fixture/BoxElemPart.hpp delete mode 100644 lib/kokkos/example/fixture/CMakeLists.txt delete mode 100644 lib/kokkos/example/fixture/HexElement.hpp delete mode 100644 lib/kokkos/example/fixture/Main.cpp delete mode 100644 lib/kokkos/example/fixture/Makefile delete mode 100644 lib/kokkos/example/fixture/TestFixture.hpp delete mode 100644 lib/kokkos/example/global_2_local_ids/CMakeLists.txt delete mode 100644 lib/kokkos/example/global_2_local_ids/G2L.hpp delete mode 100644 lib/kokkos/example/global_2_local_ids/G2L_Main.cpp delete mode 100644 lib/kokkos/example/global_2_local_ids/Makefile delete mode 100644 lib/kokkos/example/grow_array/CMakeLists.txt delete mode 100644 lib/kokkos/example/grow_array/Makefile delete mode 100644 lib/kokkos/example/grow_array/grow_array.hpp delete mode 100644 lib/kokkos/example/grow_array/main.cpp delete mode 100644 lib/kokkos/example/md_skeleton/CMakeLists.txt delete mode 100644 lib/kokkos/example/md_skeleton/Makefile delete mode 100644 lib/kokkos/example/md_skeleton/README delete mode 100644 lib/kokkos/example/md_skeleton/force.cpp delete mode 100644 lib/kokkos/example/md_skeleton/main.cpp delete mode 100644 lib/kokkos/example/md_skeleton/neighbor.cpp delete mode 100644 lib/kokkos/example/md_skeleton/setup.cpp delete mode 100644 lib/kokkos/example/md_skeleton/system.h delete mode 100644 lib/kokkos/example/md_skeleton/types.h delete mode 100644 lib/kokkos/example/multi_fem/BoxMeshFixture.hpp delete mode 100644 lib/kokkos/example/multi_fem/BoxMeshPartition.cpp delete mode 100644 lib/kokkos/example/multi_fem/BoxMeshPartition.hpp delete mode 100644 lib/kokkos/example/multi_fem/CMakeLists.txt delete mode 100644 lib/kokkos/example/multi_fem/Explicit.hpp delete mode 100644 lib/kokkos/example/multi_fem/ExplicitFunctors.hpp delete mode 100644 lib/kokkos/example/multi_fem/FEMesh.hpp delete mode 100644 lib/kokkos/example/multi_fem/HexElement.hpp delete mode 100644 lib/kokkos/example/multi_fem/HexExplicitFunctions.hpp delete mode 100644 lib/kokkos/example/multi_fem/Implicit.hpp delete mode 100644 lib/kokkos/example/multi_fem/ImplicitFunctors.hpp delete mode 100644 lib/kokkos/example/multi_fem/LinAlgBLAS.hpp delete mode 100644 lib/kokkos/example/multi_fem/Makefile delete mode 100644 lib/kokkos/example/multi_fem/Nonlinear.hpp delete mode 100644 lib/kokkos/example/multi_fem/NonlinearElement_Cuda.hpp delete mode 100644 lib/kokkos/example/multi_fem/NonlinearFunctors.hpp delete mode 100644 lib/kokkos/example/multi_fem/ParallelComm.hpp delete mode 100644 lib/kokkos/example/multi_fem/ParallelDataMap.hpp delete mode 100644 lib/kokkos/example/multi_fem/ParallelMachine.cpp delete mode 100644 lib/kokkos/example/multi_fem/ParallelMachine.hpp delete mode 100644 lib/kokkos/example/multi_fem/SparseLinearSystem.hpp delete mode 100644 lib/kokkos/example/multi_fem/SparseLinearSystemFill.hpp delete mode 100644 lib/kokkos/example/multi_fem/SparseLinearSystem_Cuda.hpp delete mode 100644 lib/kokkos/example/multi_fem/TestBoxMeshFixture.hpp delete mode 100644 lib/kokkos/example/multi_fem/TestBoxMeshPartition.cpp delete mode 100644 lib/kokkos/example/multi_fem/TestCuda.cpp delete mode 100644 lib/kokkos/example/multi_fem/TestHost.cpp delete mode 100644 lib/kokkos/example/multi_fem/TestHybridFEM.cpp delete mode 100644 lib/kokkos/example/sort_array/CMakeLists.txt delete mode 100644 lib/kokkos/example/sort_array/Makefile delete mode 100644 lib/kokkos/example/sort_array/main.cpp delete mode 100644 lib/kokkos/example/sort_array/sort_array.hpp diff --git a/lib/kokkos/BUILD.md b/lib/kokkos/BUILD.md new file mode 100644 index 0000000000..c4d6c98365 --- /dev/null +++ b/lib/kokkos/BUILD.md @@ -0,0 +1,323 @@ +![Kokkos](https://avatars2.githubusercontent.com/u/10199860?s=200&v=4) + +# Installing and Using Kokkos + +## Kokkos Philosophy +Kokkos provides a modern CMake style build system. +As C++ continues to develop for C++20 and beyond, CMake is likely to provide the most robust support +for C++. Applications heavily leveraging Kokkos are strongly encouraged to use a CMake build system. + +You can either use Kokkos as an installed package (encouraged) or use Kokkos in-tree in your project. +Modern CMake is exceedingly simple at a high-level (with the devil in the details). +Once Kokkos is installed In your `CMakeLists.txt` simply use: +```` +find_package(Kokkos REQUIRED) +```` +Then for every executable or library in your project: +```` +target_link_libraries(myTarget Kokkos::kokkos) +```` +That's it! There is no checking Kokkos preprocessor, compiler, or linker flags. +Kokkos propagates all the necesssary flags to your project. +This means not only is linking to Kokkos easy, but Kokkos itself can actually configure compiler and linker flags for *your* +project. If building in-tree, there is no `find_package` and you link with `target_link_libraries(kokkos)`. + + +## Configuring CMake +A very basic installation is done with: +```` +cmake ${srcdir} \ + -DCMAKE_CXX_COMPILER=g++ \ + -DCMAKE_INSTALL_PREFIX=${my_install_folder} +```` +which builds and installed a default Kokkos when you run `make install`. +There are numerous device backends, options, and architecture-specific optimizations that can be configured, e.g. +```` +cmake ${srcdir} \ + -DCMAKE_CXX_COMPILER=g++ \ + -DCMAKE_INSTALL_PREFIX=${my_install_folder} \ + -DKokkos_ENABLE_OPENMP=On +```` +which activates the OpenMP backend. All of the options controlling device backends, options, architectures, and third-party libraries (TPLs) are given below. + +## Spack +An alternative to manually building with the CMake is to use the Spack package manager. +To do so, download the `kokkos-spack` git repo and add to the package list: +```` +spack repo add $path-to-kokkos-spack +```` +A basic installation would be done as: +```` +spack install kokkos +```` +Spack allows options and and compilers to be tuned in the install command. +```` +spack install kokkos@3.0 %gcc@7.3.0 +openmp +```` +This example illustrates the three most common parameters to Spack: +* Variants: specified with, e.g. `+openmp`, this activates (or deactivates with, e.g. `~openmp`) certain options. +* Version: immediately following `kokkos` the `@version` can specify a particular Kokkos to build +* Compiler: a default compiler will be chosen if not specified, but an exact compiler version can be given with the `%`option. + +For a complete list of Kokkos options, run: +```` +spack info kokkos +```` + +#### Spack Development +Spack currently installs packages to a location determined by a unique hash. This hash name is not really "human readable". +Generally, Spack usage should never really require you to reference the computer-generated unique install folder. +If you must know, you can locate Spack Kokkos installations with: +```` +spack find -p kokkos ... +```` +where `...` is the unique spec identifying the particular Kokkos configuration and version. + +A better way to use Spack for doing Kokkos development is the DIY feature of Spack. +If you wish to develop Kokkos itself, go to the Kokkos source folder: +```` +spack diy -u cmake kokkos@diy ... +```` +where `...` is a Spack spec identifying the exact Kokkos configuration. +This then creates a `spack-build` directory where you can run `make`. + +If doing development on a downstream project, you can do almost exactly the same thing. +```` +spack diy -u cmake ${myproject}@${myversion} ... ^kokkos... +```` +where the `...` are the specs for your project and the desired Kokkos configuration. +Again, a `spack-build` directory will be created where you can run `make`. + +Spack has a few idiosyncracies that make building outside of Spack annoying related to Spack forcing use of a compiler wrapper. This can be worked around by having a `-DSpack_WORKAROUND=On` given your CMake. Then add the block of code to your CMakeLists.txt: + +```` +if (Spack_WORKAROUND) + set(SPACK_CXX $ENV{SPACK_CXX}) + if(SPACK_CXX) + set(CMAKE_CXX_COMPILER ${SPACK_CXX} CACHE STRING "the C++ compiler" FORCE) + set(ENV{CXX} ${SPACK_CXX}) + endif() +endif() +```` + +# Kokkos Keyword Listing + +## Device Backends +Device backends can be enabled by specifiying `-DKokkos_ENABLE_X`. + +* Kokkos_ENABLE_CUDA + * Whether to build CUDA backend + * BOOL Default: OFF +* Kokkos_ENABLE_HPX + * Whether to build HPX backend (experimental) + * BOOL Default: OFF +* Kokkos_ENABLE_OPENMP + * Whether to build OpenMP backend + * BOOL Default: OFF +* Kokkos_ENABLE_PTHREAD + * Whether to build Pthread backend + * BOOL Default: OFF +* Kokkos_ENABLE_SERIAL + * Whether to build serial backend + * BOOL Default: ON + +## Enable Options +Options can be enabled by specifiying `-DKokkos_ENABLE_X`. + +* Kokkos_ENABLE_AGGRESSIVE_VECTORIZATION + * Whether to aggressively vectorize loops + * BOOL Default: OFF +* Kokkos_ENABLE_COMPILER_WARNINGS + * Whether to print all compiler warnings + * BOOL Default: OFF +* Kokkos_ENABLE_CUDA_CONSTEXPR + * Whether to activate experimental relaxed constexpr functions + * BOOL Default: OFF +* Kokkos_ENABLE_CUDA_LAMBDA + * Whether to activate experimental lambda features + * BOOL Default: OFF +* Kokkos_ENABLE_CUDA_LDG_INTRINSIC + * Whether to use CUDA LDG intrinsics + * BOOL Default: OFF +* Kokkos_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE + * Whether to enable relocatable device code (RDC) for CUDA + * BOOL Default: OFF +* Kokkos_ENABLE_CUDA_UVM + * Whether to use unified memory (UM) by default for CUDA + * BOOL Default: OFF +* Kokkos_ENABLE_DEBUG + * Whether to activate extra debug features - may increase compile times + * BOOL Default: OFF +* Kokkos_ENABLE_DEBUG_BOUNDS_CHECK + * Whether to use bounds checking - will increase runtime + * BOOL Default: OFF +* Kokkos_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK + * Debug check on dual views + * BOOL Default: OFF +* Kokkos_ENABLE_DEPRECATED_CODE + * Whether to enable deprecated code + * BOOL Default: OFF +* Kokkos_ENABLE_HPX_ASYNC_DISPATCH + * Whether HPX supports asynchronous dispatch + * BOOL Default: OFF +* Kokkos_ENABLE_LARGE_MEM_TESTS + * Whether to perform extra large memory tests + * BOOL_Default: OFF +* Kokkos_ENABLE_PROFILING + * Whether to create bindings for profiling tools + * BOOL Default: ON +* Kokkos_ENABLE_PROFILING_LOAD_PRINT + * Whether to print information about which profiling tools gotloaded + * BOOL Default: OFF +* Kokkos_ENABLE_TESTS + * Whether to build serial backend + * BOOL Default: OFF + +## Other Options +* Kokkos_CXX_STANDARD + * The C++ standard for Kokkos to use: c++11, c++14, c++17, or c++20. This should be given in CMake style as 11, 14, 17, or 20. + * STRING Default: 11 + +## Third-party Libraries (TPLs) +The following options control enabling TPLs: +* Kokkos_ENABLE_HPX + * Whether to enable the HPX library + * BOOL Default: OFF +* Kokkos_ENABLE_HWLOC + * Whether to enable the HWLOC library + * BOOL Default: Off +* Kokkos_ENABLE_LIBNUMA + * Whether to enable the LIBNUMA library + * BOOL Default: Off +* Kokkos_ENABLE_MEMKIND + * Whether to enable the MEMKIND library + * BOOL Default: Off +* Kokkos_ENABLE_LIBDL + * Whether to enable the LIBDL library + * BOOL Default: On +* Kokkos_ENABLE_LIBRT + * Whether to enable the LIBRT library + * BOOL Default: Off + +The following options control finding and configuring non-CMake TPLs: +* Kokkos_CUDA_DIR or CUDA_ROOT + * Location of CUDA install prefix for libraries + * PATH Default: +* Kokkos_HWLOC_DIR or HWLOC_ROOT + * Location of HWLOC install prefix + * PATH Default: +* Kokkos_LIBNUMA_DIR or LIBNUMA_ROOT + * Location of LIBNUMA install prefix + * PATH Default: +* Kokkos_MEMKIND_DIR or MEMKIND_ROOT + * Location of MEMKIND install prefix + * PATH Default: +* Kokkos_LIBDL_DIR or LIBDL_ROOT + * Location of LIBDL install prefix + * PATH Default: +* Kokkos_LIBRT_DIR or LIBRT_ROOT + * Location of LIBRT install prefix + * PATH Default: + +The following options control `find_package` paths for CMake-based TPLs: +* HPX_DIR or HPX_ROOT + * Location of HPX prefix (ROOT) or CMake config file (DIR) + * PATH Default: + +## Architecture Keywords +Architecture-specific optimizations can be enabled by specifiying `-DKokkos_ARCH_X`. + +* Kokkos_ARCH_AMDAVX + * Whether to optimize for the AMDAVX architecture + * BOOL Default: OFF +* Kokkos_ARCH_ARMV80 + * Whether to optimize for the ARMV80 architecture + * BOOL Default: OFF +* Kokkos_ARCH_ARMV81 + * Whether to optimize for the ARMV81 architecture + * BOOL Default: OFF +* Kokkos_ARCH_ARMV8_THUNDERX + * Whether to optimize for the ARMV8_THUNDERX architecture + * BOOL Default: OFF +* Kokkos_ARCH_ARMV8_TX2 + * Whether to optimize for the ARMV8_TX2 architecture + * BOOL Default: OFF +* Kokkos_ARCH_BDW + * Whether to optimize for the BDW architecture + * BOOL Default: OFF +* Kokkos_ARCH_BGQ + * Whether to optimize for the BGQ architecture + * BOOL Default: OFF +* Kokkos_ARCH_EPYC + * Whether to optimize for the EPYC architecture + * BOOL Default: OFF +* Kokkos_ARCH_HSW + * Whether to optimize for the HSW architecture + * BOOL Default: OFF +* Kokkos_ARCH_KEPLER30 + * Whether to optimize for the KEPLER30 architecture + * BOOL Default: OFF +* Kokkos_ARCH_KEPLER32 + * Whether to optimize for the KEPLER32 architecture + * BOOL Default: OFF +* Kokkos_ARCH_KEPLER35 + * Whether to optimize for the KEPLER35 architecture + * BOOL Default: OFF +* Kokkos_ARCH_KEPLER37 + * Whether to optimize for the KEPLER37 architecture + * BOOL Default: OFF +* Kokkos_ARCH_KNC + * Whether to optimize for the KNC architecture + * BOOL Default: OFF +* Kokkos_ARCH_KNL + * Whether to optimize for the KNL architecture + * BOOL Default: OFF +* Kokkos_ARCH_MAXWELL50 + * Whether to optimize for the MAXWELL50 architecture + * BOOL Default: OFF +* Kokkos_ARCH_MAXWELL52 + * Whether to optimize for the MAXWELL52 architecture + * BOOL Default: OFF +* Kokkos_ARCH_MAXWELL53 + * Whether to optimize for the MAXWELL53 architecture + * BOOL Default: OFF +* Kokkos_ARCH_PASCAL60 + * Whether to optimize for the PASCAL60 architecture + * BOOL Default: OFF +* Kokkos_ARCH_PASCAL61 + * Whether to optimize for the PASCAL61 architecture + * BOOL Default: OFF +* Kokkos_ARCH_POWER7 + * Whether to optimize for the POWER7 architecture + * BOOL Default: OFF +* Kokkos_ARCH_POWER8 + * Whether to optimize for the POWER8 architecture + * BOOL Default: OFF +* Kokkos_ARCH_POWER9 + * Whether to optimize for the POWER9 architecture + * BOOL Default: OFF +* Kokkos_ARCH_SKX + * Whether to optimize for the SKX architecture + * BOOL Default: OFF +* Kokkos_ARCH_SNB + * Whether to optimize for the SNB architecture + * BOOL Default: OFF +* Kokkos_ARCH_TURING75 + * Whether to optimize for the TURING75 architecture + * BOOL Default: OFF +* Kokkos_ARCH_VOLTA70 + * Whether to optimize for the VOLTA70 architecture + * BOOL Default: OFF +* Kokkos_ARCH_VOLTA72 + * Whether to optimize for the VOLTA72 architecture + * BOOL Default: OFF +* Kokkos_ARCH_WSM + * Whether to optimize for the WSM architecture + * BOOL Default: OFF + +##### [LICENSE](https://github.com/kokkos/kokkos/blob/devel/LICENSE) + +[![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) + +Under the terms of Contract DE-NA0003525 with NTESS, +the U.S. Government retains certain rights in this software. diff --git a/lib/kokkos/CHANGELOG.md b/lib/kokkos/CHANGELOG.md index 8d196e2c35..459aeb3d2e 100644 --- a/lib/kokkos/CHANGELOG.md +++ b/lib/kokkos/CHANGELOG.md @@ -1,5 +1,45 @@ # Change Log +## [3.0.00](https://github.com/kokkos/kokkos/tree/3.0.00) (2020-01-27) +[Full Changelog](https://github.com/kokkos/kokkos/compare/2.9.00...3.0.00) + +**Implemented enhancements:** + +- BuildSystem: Standalone Modern CMake Support [\#2104](https://github.com/kokkos/kokkos/issues/2104) +- StyleFormat: ClangFormat Style [\#2157](https://github.com/kokkos/kokkos/issues/2157) +- Documentation: Document build system and CMake philosophy [\#2263](https://github.com/kokkos/kokkos/issues/2263) +- BuildSystem: Add Alias with Namespace Kokkos:: to Interal Libraries [\#2530](https://github.com/kokkos/kokkos/issues/2530) +- BuildSystem: Universal Kokkos find\_package [\#2099](https://github.com/kokkos/kokkos/issues/2099) +- BuildSystem: Dropping support for Kokkos\_{DEVICES,OPTIONS,ARCH} in CMake [\#2329](https://github.com/kokkos/kokkos/issues/2329) +- BuildSystem: Set Kokkos\_DEVICES and Kokkos\_ARCH variables in exported CMake configuration [\#2193](https://github.com/kokkos/kokkos/issues/2193) +- BuildSystem: Drop support for CUDA 7 and CUDA 8 [\#2489](https://github.com/kokkos/kokkos/issues/2489) +- BuildSystem: Drop CMake option SEPARATE\_TESTS [\#2266](https://github.com/kokkos/kokkos/issues/2266) +- BuildSystem: Support expt-relaxed-constexpr same as expt-extended-lambda [\#2411](https://github.com/kokkos/kokkos/issues/2411) +- BuildSystem: Add Xnvlink to command line options allowed in nvcc\_wrapper [\#2197](https://github.com/kokkos/kokkos/issues/2197) +- BuildSystem: Install Kokkos config files and target files to lib/cmake/Kokkos [\#2162](https://github.com/kokkos/kokkos/issues/2162) +- BuildSystem: nvcc\_wrappers and c++ 14 [\#2035](https://github.com/kokkos/kokkos/issues/2035) +- BuildSystem: Kokkos version major/version minor \(Feature request\) [\#1930](https://github.com/kokkos/kokkos/issues/1930) +- BuildSystem: CMake namespaces \(and other modern cmake cleanup\) [\#1924](https://github.com/kokkos/kokkos/issues/1924) +- BuildSystem: Remove capability to install Kokkos via GNU Makefiles [\#2332](https://github.com/kokkos/kokkos/issues/2332) +- Documentation: Remove PDF ProgrammingGuide in Kokkos replace with link [\#2244](https://github.com/kokkos/kokkos/issues/2244) +- View: Add Method to Resize View without Initialization [\#2048](https://github.com/kokkos/kokkos/issues/2048) +- Vector: implement “insert†method for Kokkos\_Vector \(as a serial function on host\) [\#2437](https://github.com/kokkos/kokkos/issues/2437) + +**Fixed bugs:** + +- ParallelScan: Kokkos::parallel\scan fix race condition seen in inter-block fence [\#2681](https://github.com/kokkos/kokkos/issues/2681) +- OffsetView: Kokkos::OffsetView missing constructor which takes pointer [\#2247](https://github.com/kokkos/kokkos/issues/2247) +- OffsetView: Kokkos::OffsetView: allow offset=0 [\#2246](https://github.com/kokkos/kokkos/issues/2246) +- DeepCopy: Missing DeepCopy instrumentation in Kokkos [\#2522](https://github.com/kokkos/kokkos/issues/2522) +- nvcc\_wrapper: --host-only fails with mutiple -W\* flags [\#2484](https://github.com/kokkos/kokkos/issues/2484) +- nvcc\_wrapper: taking first -std option is counterintuitive [\#2553](https://github.com/kokkos/kokkos/issues/2553) +- Subview: Error taking subviews of views with static_extents of min rank [\#2448](https://github.com/kokkos/kokkos/issues/2448) +- TeamPolicy: reducers with valuetypes without += broken on CUDA [\#2410](https://github.com/kokkos/kokkos/issues/2410) +- Libs: Fix inconsistency of Kokkos library names in Kokkos and Trilinos [\#1902](https://github.com/kokkos/kokkos/issues/1902) +- Complex: operator\>\> for complex\ uses std::ostream, not std::istream [\#2313](https://github.com/kokkos/kokkos/issues/2313) +- Macros: Restrict not honored for non-intel compilers [\#1922](https://github.com/kokkos/kokkos/issues/1922) + + ## [2.9.00](https://github.com/kokkos/kokkos/tree/2.9.00) (2019-06-24) [Full Changelog](https://github.com/kokkos/kokkos/compare/2.8.00...2.9.00) diff --git a/lib/kokkos/CMakeLists.txt b/lib/kokkos/CMakeLists.txt index 236f523aec..6a4451b2e7 100644 --- a/lib/kokkos/CMakeLists.txt +++ b/lib/kokkos/CMakeLists.txt @@ -1,128 +1,218 @@ -# Is this a build as part of Trilinos? +# We want to determine if options are given with the wrong case +# In order to detect which arguments are given to compare against +# the list of valid arguments, at the beginning here we need to +# form a list of all the given variables. If it begins with any +# case of KoKkOS, we add it to the list. + + +GET_CMAKE_PROPERTY(_variableNames VARIABLES) +SET(KOKKOS_GIVEN_VARIABLES) +FOREACH (var ${_variableNames}) + STRING(TOUPPER ${var} UC_VAR) + STRING(FIND ${UC_VAR} KOKKOS IDX) + IF (${IDX} EQUAL 0) + LIST(APPEND KOKKOS_GIVEN_VARIABLES ${var}) + ENDIF() +ENDFOREACH() + +# Basic initialization (Used in KOKKOS_SETTINGS) +SET(Kokkos_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +SET(KOKKOS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +SET(KOKKOS_SRC_PATH ${Kokkos_SOURCE_DIR}) +SET(KOKKOS_PATH ${Kokkos_SOURCE_DIR}) +SET(KOKKOS_TOP_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}) + +# Needed to simplify syntax of if statements +CMAKE_POLICY(SET CMP0054 NEW) + +# Is this a build as part of Trilinos? IF(COMMAND TRIBITS_PACKAGE_DECL) - SET(KOKKOS_HAS_TRILINOS ON CACHE BOOL "") + SET(KOKKOS_HAS_TRILINOS ON) ELSE() - SET(KOKKOS_HAS_TRILINOS OFF CACHE BOOL "") + SET(KOKKOS_HAS_TRILINOS OFF) ENDIF() -IF(NOT KOKKOS_HAS_TRILINOS) - cmake_minimum_required(VERSION 3.3 FATAL_ERROR) +INCLUDE(${KOKKOS_SRC_PATH}/cmake/kokkos_functions.cmake) +INCLUDE(${KOKKOS_SRC_PATH}/cmake/kokkos_pick_cxx_std.cmake) + +SET(KOKKOS_ENABLED_OPTIONS) #exported in config file +SET(KOKKOS_ENABLED_DEVICES) #exported in config file +SET(KOKKOS_ENABLED_TPLS) #exported in config file +SET(KOKKOS_ENABLED_ARCH_LIST) #exported in config file + +#These are helper flags used for sanity checks during config +#Certain features should depend on other features being configured first +SET(KOKKOS_CFG_DAG_NONE On) #sentinel to indicate no dependencies +SET(KOKKOS_CFG_DAG_DEVICES_DONE Off) +SET(KOKKOS_CFG_DAG_OPTIONS_DONE Off) +SET(KOKKOS_CFG_DAG_ARCH_DONE Off) +SET(KOKKOS_CFG_DAG_CXX_STD_DONE Off) +SET(KOKKOS_CFG_DAG_COMPILER_ID_DONE Off) +FUNCTION(KOKKOS_CFG_DEPENDS SUCCESSOR PRECURSOR) + SET(PRE_FLAG KOKKOS_CFG_DAG_${PRECURSOR}) + SET(POST_FLAG KOKKOS_CFG_DAG_${SUCCESSOR}) + IF (NOT ${PRE_FLAG}) + MESSAGE(FATAL_ERROR "Bad CMake refactor: feature ${SUCCESSOR} cannot be configured until ${PRECURSOR} is configured") + ENDIF() + GLOBAL_SET(${POST_FLAG} On) +ENDFUNCTION() - # Define Project Name if this is a standalone build + +LIST(APPEND CMAKE_MODULE_PATH cmake/Modules) + +IF(NOT KOKKOS_HAS_TRILINOS) + cmake_minimum_required(VERSION 3.10 FATAL_ERROR) + set(CMAKE_DISABLE_SOURCE_CHANGES ON) + set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) + IF (Spack_WORKAROUND) + #if we are explicitly using Spack for development, + #nuke the Spack compiler + SET(SPACK_CXX $ENV{SPACK_CXX}) + IF(SPACK_CXX) + SET(CMAKE_CXX_COMPILER ${SPACK_CXX} CACHE STRING "the C++ compiler" FORCE) + SET(ENV{CXX} ${SPACK_CXX}) + ENDIF() + ENDif() IF(NOT DEFINED ${PROJECT_NAME}) - project(Kokkos CXX) + PROJECT(Kokkos CXX) ENDIF() +ENDIF() - # Basic initialization (Used in KOKKOS_SETTINGS) - set(KOKKOS_SRC_PATH ${Kokkos_SOURCE_DIR}) - set(KOKKOS_PATH ${KOKKOS_SRC_PATH}) - - #------------ COMPILER AND FEATURE CHECKS ------------------------------------ - include(${KOKKOS_SRC_PATH}/cmake/kokkos_functions.cmake) - set_kokkos_cxx_compiler() - set_kokkos_cxx_standard() - - #------------ GET OPTIONS AND KOKKOS_SETTINGS -------------------------------- - # Add Kokkos' modules to CMake's module path. - set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${Kokkos_SOURCE_DIR}/cmake/Modules/") - - set(KOKKOS_CMAKE_VERBOSE True) - include(${KOKKOS_SRC_PATH}/cmake/kokkos_options.cmake) - - include(${KOKKOS_SRC_PATH}/cmake/kokkos_settings.cmake) - - #------------ GENERATE HEADER AND SOURCE FILES ------------------------------- - execute_process( - COMMAND ${KOKKOS_SETTINGS} make -f ${KOKKOS_SRC_PATH}/cmake/Makefile.generate_cmake_settings CXX=${CMAKE_CXX_COMPILER} PREFIX=${CMAKE_INSTALL_PREFIX} generate_build_settings - WORKING_DIRECTORY "${Kokkos_BINARY_DIR}" - OUTPUT_FILE ${Kokkos_BINARY_DIR}/core_src_make.out - RESULT_VARIABLE GEN_SETTINGS_RESULT - ) - if (GEN_SETTINGS_RESULT) - message(FATAL_ERROR "Kokkos settings generation failed:\n" - "${KOKKOS_SETTINGS} make -f ${KOKKOS_SRC_PATH}/cmake/Makefile.generate_cmake_settings CXX=${CMAKE_CXX_COMPILER} generate_build_settings") - endif() - include(${Kokkos_BINARY_DIR}/kokkos_generated_settings.cmake) - install(FILES ${Kokkos_BINARY_DIR}/kokkos_generated_settings.cmake DESTINATION lib/cmake/Kokkos) - install(FILES ${Kokkos_BINARY_DIR}/kokkos_generated_settings.cmake DESTINATION ${CMAKE_INSTALL_PREFIX}) - string(REPLACE " " ";" KOKKOS_TPL_INCLUDE_DIRS "${KOKKOS_GMAKE_TPL_INCLUDE_DIRS}") - string(REPLACE " " ";" KOKKOS_TPL_LIBRARY_DIRS "${KOKKOS_GMAKE_TPL_LIBRARY_DIRS}") - string(REPLACE " " ";" KOKKOS_TPL_LIBRARY_NAMES "${KOKKOS_GMAKE_TPL_LIBRARY_NAMES}") - list(REMOVE_ITEM KOKKOS_TPL_INCLUDE_DIRS "") - list(REMOVE_ITEM KOKKOS_TPL_LIBRARY_DIRS "") - list(REMOVE_ITEM KOKKOS_TPL_LIBRARY_NAMES "") - set_kokkos_srcs(KOKKOS_SRC ${KOKKOS_SRC}) - - #------------ NOW BUILD ------------------------------------------------------ - include(${KOKKOS_SRC_PATH}/cmake/kokkos_build.cmake) - - #------------ Add in Fake Tribits Handling to allow unit test builds- -------- - - include(${KOKKOS_SRC_PATH}/cmake/tribits.cmake) - - TRIBITS_PACKAGE_DECL(Kokkos) - - ADD_SUBDIRECTORY(core) - ADD_SUBDIRECTORY(containers) - ADD_SUBDIRECTORY(algorithms) +IF (NOT CMAKE_SIZEOF_VOID_P) + STRING(FIND ${CMAKE_CXX_COMPILER} nvcc_wrapper FIND_IDX) + IF (NOT FIND_IDX STREQUAL -1) + MESSAGE(FATAL_ERROR "Kokkos did not configure correctly and failed to validate compiler. The most likely cause is CUDA linkage using nvcc_wrapper. Please ensure your CUDA environment is correctly configured.") + ELSE() + MESSAGE(FATAL_ERROR "Kokkos did not configure correctly and failed to validate compiler. The most likely cause is linkage errors during CMake compiler validation. Please consult the CMake error log shown below for the exact error during compiler validation") + ENDIF() +ELSEIF (NOT CMAKE_SIZEOF_VOID_P EQUAL 8) + MESSAGE(FATAL_ERROR "Kokkos assumes a 64-bit build; i.e., 8-byte pointers, but found ${CMAKE_SIZEOF_VOID_P}-byte pointers instead") +ENDIF() -ELSE() -#------------------------------------------------------------------------------ -# -# A) Forward declare the package so that certain options are also defined for -# subpackages -# -TRIBITS_PACKAGE_DECL(Kokkos) # ENABLE_SHADOWING_WARNINGS) +set(Kokkos_VERSION_MAJOR 3) +set(Kokkos_VERSION_MINOR 0) +set(Kokkos_VERSION_PATCH 0) +set(Kokkos_VERSION "${Kokkos_VERSION_MAJOR}.${Kokkos_VERSION_MINOR}.${Kokkos_VERSION_PATCH}") +IF(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.12.0") + MESSAGE(STATUS "Setting policy CMP0074 to use _ROOT variables") + CMAKE_POLICY(SET CMP0074 NEW) +ENDIF() + +# Load either the real TriBITS or a TriBITS wrapper +# for certain utility functions that are universal (like GLOBAL_SET) +INCLUDE(${KOKKOS_SRC_PATH}/cmake/fake_tribits.cmake) + +IF (Kokkos_ENABLE_CUDA AND ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14.0") + #If we are building CUDA, we have tricked CMake because we declare a CXX project + #If the default C++ standard for a given compiler matches the requested + #standard, then CMake just omits the -std flag in later versions of CMake + #This breaks CUDA compilation (CUDA compiler can have a different default + #-std then the underlying host compiler by itself). Setting this variable + #forces CMake to always add the -std flag even if it thinks it doesn't need it + GLOBAL_SET(CMAKE_CXX_STANDARD_DEFAULT 98) +ENDIF() + +# These are the variables we will append to as we go +# I really wish these were regular variables +# but scoping issues can make it difficult +GLOBAL_RESET(KOKKOS_COMPILE_OPTIONS) +GLOBAL_RESET(KOKKOS_LINK_OPTIONS) +GLOBAL_RESET(KOKKOS_CUDA_OPTIONS) +GLOBAL_RESET(KOKKOS_CUDAFE_OPTIONS) +GLOBAL_RESET(KOKKOS_XCOMPILER_OPTIONS) +# We need to append text here for making sure TPLs +# we import are available for an installed Kokkos +GLOBAL_RESET(KOKKOS_TPL_EXPORTS) +# We need these for controlling the exact -std flag +GLOBAL_RESET(KOKKOS_DONT_ALLOW_EXTENSIONS) +GLOBAL_RESET(KOKKOS_USE_CXX_EXTENSIONS) +GLOBAL_RESET(KOKKOS_CXX_STANDARD_FEATURE) + +# Include a set of Kokkos-specific wrapper functions that +# will either call raw CMake or TriBITS +# These are functions like KOKKOS_INCLUDE_DIRECTORIES +INCLUDE(${KOKKOS_SRC_PATH}/cmake/kokkos_tribits.cmake) + + +# The build environment setup goes in the following steps +# 1) Check all the enable options. This includes checking Kokkos_DEVICES +# 2) Check the compiler ID (type and version) +# 3) Check the CXX standard and select important CXX flags +# 4) Check for any third-party libraries (TPLs) like hwloc +# 5) Check if optimizing for a particular architecture and add arch-specific flags +KOKKOS_SETUP_BUILD_ENVIRONMENT() + +# Finish off the build +# 6) Recurse into subdirectories and configure individual libraries +# 7) Export and install targets + +OPTION(BUILD_SHARED_LIBS "Build shared libraries" OFF) +# Workaround for building position independent code. +IF(BUILD_SHARED_LIBS) + SET(CMAKE_POSITION_INDEPENDENT_CODE ON) +ENDIF() + +SET(KOKKOS_EXT_LIBRARIES Kokkos::kokkos Kokkos::kokkoscore Kokkos::kokkoscontainers Kokkos::kokkosalgorithms) +SET(KOKKOS_INT_LIBRARIES kokkos kokkoscore kokkoscontainers kokkosalgorithms) +SET_PROPERTY(GLOBAL PROPERTY KOKKOS_INT_LIBRARIES ${KOKKOS_INT_LIBRARIES}) + +GET_DIRECTORY_PROPERTY(HAS_PARENT PARENT_DIRECTORY) +IF (KOKKOS_HAS_TRILINOS) + SET(TRILINOS_INCDIR ${CMAKE_INSTALL_PREFIX}/${${PROJECT_NAME}_INSTALL_INCLUDE_DIR}) + SET(KOKKOS_HEADER_DIR ${TRILINOS_INCDIR}) + SET(KOKKOS_IS_SUBDIRECTORY TRUE) +ELSEIF(HAS_PARENT) + SET(KOKKOS_HEADER_DIR "include/kokkos") + SET(KOKKOS_IS_SUBDIRECTORY TRUE) +ELSE() + SET(KOKKOS_HEADER_DIR "${CMAKE_INSTALL_INCLUDEDIR}") + SET(KOKKOS_IS_SUBDIRECTORY FALSE) +ENDIF() -#------------------------------------------------------------------------------ -# -# B) Install Kokkos' build files -# -# If using the Makefile-generated files, then need to set things up. -# Here, assume that TriBITS has been run from ProjectCompilerPostConfig.cmake -# and already generated KokkosCore_config.h and kokkos_generated_settings.cmake -# in the previously define Kokkos_GEN_DIR -# We need to copy them over to the correct place and source the cmake file - -if(NOT KOKKOS_LEGACY_TRIBITS) - set(Kokkos_GEN_DIR ${CMAKE_BINARY_DIR}) - file(COPY "${Kokkos_GEN_DIR}/KokkosCore_config.h" - DESTINATION "${CMAKE_CURRENT_BINARY_DIR}" USE_SOURCE_PERMISSIONS) - install(FILES "${Kokkos_GEN_DIR}/KokkosCore_config.h" - DESTINATION include) - file(COPY "${Kokkos_GEN_DIR}/kokkos_generated_settings.cmake" - DESTINATION "${CMAKE_CURRENT_BINARY_DIR}" USE_SOURCE_PERMISSIONS) - - include(${CMAKE_CURRENT_BINARY_DIR}/kokkos_generated_settings.cmake) - # Sources come from makefile-generated kokkos_generated_settings.cmake file - # Enable using the individual sources if needed - set_kokkos_srcs(KOKKOS_SRC ${KOKKOS_SRC}) -endif () #------------------------------------------------------------------------------ # -# C) Install Kokkos' executable scripts -# +# A) Forward declare the package so that certain options are also defined for +# subpackages -# nvcc_wrapper is Kokkos' wrapper for NVIDIA's NVCC CUDA compiler. -# Kokkos needs nvcc_wrapper in order to build. Other libraries and -# executables also need nvcc_wrapper. Thus, we need to install it. -# If the argument of DESTINATION is a relative path, CMake computes it -# as relative to ${CMAKE_INSTALL_PATH}. +## This restores the old behavior of ProjectCompilerPostConfig.cmake +# It sets the CMAKE_CXX_FLAGS globally to those used by Kokkos +# We must do this before KOKKOS_PACKAGE_DECL +IF (KOKKOS_HAS_TRILINOS) + # Overwrite the old flags at the top-level + # Because Tribits doesn't use lists, it uses spaces for the list of CXX flags + # we have to match the annoying behavior + STRING(REPLACE ";" " " KOKKOSCORE_COMPILE_OPTIONS "${KOKKOS_COMPILE_OPTIONS}") + STRING(REPLACE ";" " " KOKKOSCORE_CUDA_OPTIONS "${KOKKOS_CUDA_OPTIONS}") + FOREACH(CUDAFE_FLAG ${KOKKOS_CUDAFE_OPTIONS}) + SET(KOKKOSCORE_CUDAFE_OPTIONS "${KOKKOSCORE_CUDAFE_OPTIONS} -Xcudafe ${CUDAFE_FLAG}") + ENDFOREACH() + FOREACH(XCOMP_FLAG ${KOKKOS_XCOMPILER_OPTIONS}) + SET(KOKKOSCORE_XCOMPILER_OPTIONS "${KOKKOSCORE_XCOMPILER_OPTIONS} -Xcompiler ${XCOMP_FLAG}") + ENDFOREACH() + SET(KOKKOSCORE_CXX_FLAGS "${KOKKOSCORE_COMPILE_OPTIONS} ${CMAKE_CXX${KOKKOS_CXX_STANDARD}_STANDARD_COMPILE_OPTION} ${KOKKOSCORE_CUDA_OPTIONS} ${KOKKOSCORE_CUDAFE_OPTIONS} ${KOKKOSCORE_XCOMPILER_OPTIONS}") + # Both parent scope and this package + # In ProjectCompilerPostConfig.cmake, we capture the "global" flags Trilinos wants in + # TRILINOS_TOPLEVEL_CXX_FLAGS + SET(CMAKE_CXX_FLAGS "${TRILINOS_TOPLEVEL_CXX_FLAGS} ${KOKKOSCORE_CXX_FLAGS}" PARENT_SCOPE) + SET(CMAKE_CXX_FLAGS "${TRILINOS_TOPLEVEL_CXX_FLAGS} ${KOKKOSCORE_CXX_FLAGS}") + #CMAKE_CXX_FLAGS will get added to Kokkos and Kokkos dependencies automatically here + #These flags get set up in KOKKOS_PACKAGE_DECL, which means they + #must be configured before KOKKOS_PACKAGE_DECL +ENDIF() -INSTALL(PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/bin/nvcc_wrapper DESTINATION bin) +KOKKOS_PACKAGE_DECL() #------------------------------------------------------------------------------ # -# D) Process the subpackages for Kokkos +# D) Process the subpackages (subdirectories) for Kokkos # - -TRIBITS_PROCESS_SUBPACKAGES() +KOKKOS_PROCESS_SUBPACKAGES() #------------------------------------------------------------------------------ @@ -130,10 +220,39 @@ TRIBITS_PROCESS_SUBPACKAGES() # E) If Kokkos itself is enabled, process the Kokkos package # -TRIBITS_PACKAGE_DEF() +KOKKOS_PACKAGE_DEF() +KOKKOS_EXCLUDE_AUTOTOOLS_FILES() +KOKKOS_PACKAGE_POSTPROCESS() -TRIBITS_EXCLUDE_AUTOTOOLS_FILES() +#We are ready to configure the header +CONFIGURE_FILE(cmake/KokkosCore_config.h.in KokkosCore_config.h @ONLY) -TRIBITS_PACKAGE_POSTPROCESS() +IF (NOT KOKKOS_HAS_TRILINOS) + ADD_LIBRARY(kokkos INTERFACE) + #Make sure in-tree projects can reference this as Kokkos:: + #to match the installed target names + ADD_LIBRARY(Kokkos::kokkos ALIAS kokkos) + TARGET_LINK_LIBRARIES(kokkos INTERFACE kokkoscore kokkoscontainers kokkosalgorithms) + KOKKOS_INTERNAL_ADD_LIBRARY_INSTALL(kokkos) +ENDIF() +INCLUDE(${KOKKOS_SRC_PATH}/cmake/kokkos_install.cmake) +# nvcc_wrapper is Kokkos' wrapper for NVIDIA's NVCC CUDA compiler. +# Kokkos needs nvcc_wrapper in order to build. Other libraries and +# executables also need nvcc_wrapper. Thus, we need to install it. +# If the argument of DESTINATION is a relative path, CMake computes it +# as relative to ${CMAKE_INSTALL_PATH}. +INSTALL(PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/bin/nvcc_wrapper DESTINATION ${CMAKE_INSTALL_BINDIR}) +INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/KokkosCore_config.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + + +# Finally - if we are a subproject - make sure the enabled devices are visible +IF (HAS_PARENT) + FOREACH(DEV Kokkos_ENABLED_DEVICES) + #I would much rather not make these cache variables or global properties, but I can't + #make any guarantees on whether PARENT_SCOPE is good enough to make + #these variables visible where I need them + SET(Kokkos_ENABLE_${DEV} ON PARENT_SCOPE) + SET_PROPERTY(GLOBAL PROPERTY Kokkos_ENABLE_${DEV} ON) + ENDFOREACH() ENDIF() diff --git a/lib/kokkos/CONTRIBUTING.md b/lib/kokkos/CONTRIBUTING.md new file mode 100644 index 0000000000..b4f3057cef --- /dev/null +++ b/lib/kokkos/CONTRIBUTING.md @@ -0,0 +1,14 @@ +# Contributing to Kokkos + +## Pull Requests +We actively welcome pull requests. +1. Fork the repo and create your branch from `develop`. +2. If you've added code that should be tested, add tests. +3. If you've changed APIs, update the documentation. +4. Ensure the test suite passes. + +## Issues +We use GitHub issues to track public bugs. Please ensure your description is clear and has sufficient instructions to be able to reproduce the issue. + +## License +By contributing to Kokkos, you agree that your contributions will be licensed under the LICENSE file in the root directory of this source tree. diff --git a/lib/kokkos/Copyright.txt b/lib/kokkos/Copyright.txt index 50b76995af..06184796b2 100644 --- a/lib/kokkos/Copyright.txt +++ b/lib/kokkos/Copyright.txt @@ -1,10 +1,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -22,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/lib/kokkos/LICENSE b/lib/kokkos/LICENSE index c68a8a2a9f..c6f17087d5 100644 --- a/lib/kokkos/LICENSE +++ b/lib/kokkos/LICENSE @@ -1,10 +1,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Kokkos is licensed under 3-clause BSD terms of use: @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/lib/kokkos/Makefile.kokkos b/lib/kokkos/Makefile.kokkos index e9ad57f0ae..fd96e14bb5 100644 --- a/lib/kokkos/Makefile.kokkos +++ b/lib/kokkos/Makefile.kokkos @@ -23,14 +23,16 @@ KOKKOS_DEBUG ?= "no" KOKKOS_USE_TPLS ?= "" # Options: c++11,c++14,c++1y,c++17,c++1z,c++2a KOKKOS_CXX_STANDARD ?= "c++11" -# Options: aggressive_vectorization,disable_profiling,enable_deprecated_code,disable_deprecated_code,enable_large_mem_tests +# Options: aggressive_vectorization,disable_profiling,enable_deprecated_code,disable_deprecated_code,enable_large_mem_tests,disable_complex_align KOKKOS_OPTIONS ?= "" # Option for setting ETI path KOKKOS_ETI_PATH ?= ${KOKKOS_PATH}/core/src/eti KOKKOS_CMAKE ?= "no" +KOKKOS_TRIBITS ?= "no" +KOKKOS_STANDALONE_CMAKE ?= "no" # Default settings specific options. -# Options: force_uvm,use_ldg,rdc,enable_lambda +# Options: force_uvm,use_ldg,rdc,enable_lambda,enable_constexpr KOKKOS_CUDA_OPTIONS ?= "enable_lambda" # Default settings specific options. @@ -47,7 +49,8 @@ kokkos_has_string=$(if $(findstring $2,$1),1,0) # Will return a 1 if /path/to/file exists kokkos_path_exists=$(if $(wildcard $1),1,0) -# Check for general settings. +# Check for general settings + KOKKOS_INTERNAL_ENABLE_DEBUG := $(call kokkos_has_string,$(KOKKOS_DEBUG),yes) KOKKOS_INTERNAL_ENABLE_CXX11 := $(call kokkos_has_string,$(KOKKOS_CXX_STANDARD),c++11) KOKKOS_INTERNAL_ENABLE_CXX14 := $(call kokkos_has_string,$(KOKKOS_CXX_STANDARD),c++14) @@ -67,6 +70,7 @@ KOKKOS_INTERNAL_OPT_RANGE_AGGRESSIVE_VECTORIZATION := $(call kokkos_has_string,$ KOKKOS_INTERNAL_DISABLE_PROFILING := $(call kokkos_has_string,$(KOKKOS_OPTIONS),disable_profiling) KOKKOS_INTERNAL_DISABLE_DEPRECATED_CODE := $(call kokkos_has_string,$(KOKKOS_OPTIONS),disable_deprecated_code) KOKKOS_INTERNAL_ENABLE_DEPRECATED_CODE := $(call kokkos_has_string,$(KOKKOS_OPTIONS),enable_deprecated_code) +KOKKOS_INTERNAL_DISABLE_COMPLEX_ALIGN := $(call kokkos_has_string,$(KOKKOS_OPTIONS),disable_complex_align) KOKKOS_INTERNAL_DISABLE_DUALVIEW_MODIFY_CHECK := $(call kokkos_has_string,$(KOKKOS_OPTIONS),disable_dualview_modify_check) KOKKOS_INTERNAL_ENABLE_PROFILING_LOAD_PRINT := $(call kokkos_has_string,$(KOKKOS_OPTIONS),enable_profile_load_print) KOKKOS_INTERNAL_ENABLE_LARGE_MEM_TESTS := $(call kokkos_has_string,$(KOKKOS_OPTIONS),enable_large_mem_tests) @@ -74,6 +78,7 @@ KOKKOS_INTERNAL_CUDA_USE_LDG := $(call kokkos_has_string,$(KOKKOS_CUDA_OPTIONS), KOKKOS_INTERNAL_CUDA_USE_UVM := $(call kokkos_has_string,$(KOKKOS_CUDA_OPTIONS),force_uvm) KOKKOS_INTERNAL_CUDA_USE_RELOC := $(call kokkos_has_string,$(KOKKOS_CUDA_OPTIONS),rdc) KOKKOS_INTERNAL_CUDA_USE_LAMBDA := $(call kokkos_has_string,$(KOKKOS_CUDA_OPTIONS),enable_lambda) +KOKKOS_INTERNAL_CUDA_USE_CONSTEXPR := $(call kokkos_has_string,$(KOKKOS_CUDA_OPTIONS),enable_constexpr) KOKKOS_INTERNAL_HPX_ENABLE_ASYNC_DISPATCH := $(call kokkos_has_string,$(KOKKOS_HPX_OPTIONS),enable_async_dispatch) KOKKOS_INTERNAL_ENABLE_ETI := $(call kokkos_has_string,$(KOKKOS_OPTIONS),enable_eti) @@ -123,7 +128,7 @@ KOKKOS_INTERNAL_COMPILER_INTEL := $(call kokkos_has_string,$(KOKKOS_CXX_VE KOKKOS_INTERNAL_COMPILER_PGI := $(call kokkos_has_string,$(KOKKOS_CXX_VERSION),PGI) KOKKOS_INTERNAL_COMPILER_XL := $(strip $(shell $(CXX) -qversion 2>&1 | grep XL | wc -l)) KOKKOS_INTERNAL_COMPILER_CRAY := $(strip $(shell $(CXX) -craype-verbose 2>&1 | grep "CC-" | wc -l)) -KOKKOS_INTERNAL_COMPILER_NVCC := $(strip $(shell export OMPI_CXX=$(OMPI_CXX); export MPICH_CXX=$(MPICH_CXX); $(CXX) --version 2>&1 | grep nvcc | wc -l)) +KOKKOS_INTERNAL_COMPILER_NVCC := $(strip $(shell export OMPI_CXX=$(OMPI_CXX); export MPICH_CXX=$(MPICH_CXX); echo "$(shell $(CXX) --version 2>&1 | grep nvcc | wc -l)>0" | bc)) KOKKOS_INTERNAL_COMPILER_CLANG := $(call kokkos_has_string,$(KOKKOS_CXX_VERSION),clang) KOKKOS_INTERNAL_COMPILER_APPLE_CLANG := $(call kokkos_has_string,$(KOKKOS_CXX_VERSION),Apple LLVM) KOKKOS_INTERNAL_COMPILER_HCC := $(call kokkos_has_string,$(KOKKOS_CXX_VERSION),HCC) @@ -383,10 +388,10 @@ endif # Generating the list of Flags. -#CPPFLAGS is now unused KOKKOS_CPPFLAGS = +KOKKOS_LIBDIRS = ifneq ($(KOKKOS_CMAKE), yes) - KOKKOS_CXXFLAGS = -I./ -I$(KOKKOS_PATH)/core/src -I$(KOKKOS_PATH)/containers/src -I$(KOKKOS_PATH)/algorithms/src -I$(KOKKOS_ETI_PATH) + KOKKOS_CPPFLAGS = -I./ -I$(KOKKOS_PATH)/core/src -I$(KOKKOS_PATH)/containers/src -I$(KOKKOS_PATH)/algorithms/src -I$(KOKKOS_ETI_PATH) endif KOKKOS_TPL_INCLUDE_DIRS = KOKKOS_TPL_LIBRARY_DIRS = @@ -399,7 +404,7 @@ endif KOKKOS_LIBS = -ldl KOKKOS_TPL_LIBRARY_NAMES += dl ifneq ($(KOKKOS_CMAKE), yes) - KOKKOS_LDFLAGS = -L$(shell pwd) + KOKKOS_LIBDIRS = -L$(shell pwd) # CXXLDFLAGS is used together with CXXFLAGS in a combined compile/link command KOKKOS_CXXLDFLAGS = -L$(shell pwd) endif @@ -492,28 +497,38 @@ ifeq ($(KOKKOS_INTERNAL_USE_ISA_POWERPCBE), 1) tmp := $(call kokkos_append_header,"\#endif") endif +#only add the c++ standard flags if this is not CMake tmp := $(call kokkos_append_header,"/* General Settings */") ifeq ($(KOKKOS_INTERNAL_ENABLE_CXX11), 1) +ifneq ($(KOKKOS_STANDALONE_CMAKE), yes) KOKKOS_CXXFLAGS += $(KOKKOS_INTERNAL_CXX11_FLAG) +endif tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_CXX11") endif ifeq ($(KOKKOS_INTERNAL_ENABLE_CXX14), 1) +ifneq ($(KOKKOS_STANDALONE_CMAKE), yes) KOKKOS_CXXFLAGS += $(KOKKOS_INTERNAL_CXX14_FLAG) +endif tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_CXX14") endif ifeq ($(KOKKOS_INTERNAL_ENABLE_CXX1Y), 1) + #I cannot make CMake add this in a good way - so add it here KOKKOS_CXXFLAGS += $(KOKKOS_INTERNAL_CXX1Y_FLAG) tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_CXX14") endif ifeq ($(KOKKOS_INTERNAL_ENABLE_CXX17), 1) +ifneq ($(KOKKOS_STANDALONE_CMAKE), yes) KOKKOS_CXXFLAGS += $(KOKKOS_INTERNAL_CXX17_FLAG) +endif tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_CXX17") endif ifeq ($(KOKKOS_INTERNAL_ENABLE_CXX1Z), 1) + #I cannot make CMake add this in a good way - so add it here KOKKOS_CXXFLAGS += $(KOKKOS_INTERNAL_CXX1Z_FLAG) tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_CXX17") endif ifeq ($(KOKKOS_INTERNAL_ENABLE_CXX2A), 1) + #I cannot make CMake add this in a good way - so add it here KOKKOS_CXXFLAGS += $(KOKKOS_INTERNAL_CXX2A_FLAG) tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_CXX20") endif @@ -531,23 +546,26 @@ ifeq ($(KOKKOS_INTERNAL_ENABLE_DEBUG), 1) tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK") endif endif +ifeq ($(KOKKOS_INTERNAL_DISABLE_COMPLEX_ALIGN), 0) + tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_COMPLEX_ALIGN") +endif ifeq ($(KOKKOS_INTERNAL_ENABLE_PROFILING_LOAD_PRINT), 1) tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_PROFILING_LOAD_PRINT") endif ifeq ($(KOKKOS_INTERNAL_USE_HWLOC), 1) - ifneq ($(HWLOC_PATH),) - ifneq ($(KOKKOS_CMAKE), yes) - KOKKOS_CXXFLAGS += -I$(HWLOC_PATH)/include + ifneq ($(KOKKOS_CMAKE), yes) + ifneq ($(HWLOC_PATH),) + KOKKOS_CPPFLAGS += -I$(HWLOC_PATH)/include + KOKKOS_LIBDIRS += -L$(HWLOC_PATH)/lib + KOKKOS_CXXLDFLAGS += -L$(HWLOC_PATH)/lib + KOKKOS_TPL_INCLUDE_DIRS += $(HWLOC_PATH)/include + KOKKOS_TPL_LIBRARY_DIRS += $(HWLOC_PATH)/lib endif - KOKKOS_LDFLAGS += -L$(HWLOC_PATH)/lib - KOKKOS_CXXLDFLAGS += -L$(HWLOC_PATH)/lib - KOKKOS_TPL_INCLUDE_DIRS += $(HWLOC_PATH)/include - KOKKOS_TPL_LIBRARY_DIRS += $(HWLOC_PATH)/lib + KOKKOS_LIBS += -lhwloc + KOKKOS_TPL_LIBRARY_NAMES += hwloc endif - KOKKOS_LIBS += -lhwloc - KOKKOS_TPL_LIBRARY_NAMES += hwloc tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_HWLOC") endif @@ -558,17 +576,17 @@ ifeq ($(KOKKOS_INTERNAL_USE_LIBRT), 1) endif ifeq ($(KOKKOS_INTERNAL_USE_MEMKIND), 1) - ifneq ($(MEMKIND_PATH),) - ifneq ($(KOKKOS_CMAKE), yes) - KOKKOS_CXXFLAGS += -I$(MEMKIND_PATH)/include + ifneq ($(KOKKOS_CMAKE), yes) + ifneq ($(MEMKIND_PATH),) + KOKKOS_CPPFLAGS += -I$(MEMKIND_PATH)/include + KOKKOS_LIBDIRS += -L$(MEMKIND_PATH)/lib + KOKKOS_CXXLDFLAGS += -L$(MEMKIND_PATH)/lib + KOKKOS_TPL_INCLUDE_DIRS += $(MEMKIND_PATH)/include + KOKKOS_TPL_LIBRARY_DIRS += $(MEMKIND_PATH)/lib endif - KOKKOS_LDFLAGS += -L$(MEMKIND_PATH)/lib - KOKKOS_CXXLDFLAGS += -L$(MEMKIND_PATH)/lib - KOKKOS_TPL_INCLUDE_DIRS += $(MEMKIND_PATH)/include - KOKKOS_TPL_LIBRARY_DIRS += $(MEMKIND_PATH)/lib + KOKKOS_LIBS += -lmemkind -lnuma + KOKKOS_TPL_LIBRARY_NAMES += memkind numa endif - KOKKOS_LIBS += -lmemkind -lnuma - KOKKOS_TPL_LIBRARY_NAMES += memkind numa tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_HBWSPACE") endif @@ -580,9 +598,6 @@ ifeq ($(KOKKOS_INTERNAL_USE_HPX), 0) ifeq ($(KOKKOS_INTERNAL_ENABLE_DEPRECATED_CODE), 1) tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_DEPRECATED_CODE") endif - ifeq ($(KOKKOS_INTERNAL_DISABLE_DEPRECATED_CODE), 0) - tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_DEPRECATED_CODE") - endif endif ifeq ($(KOKKOS_INTERNAL_ENABLE_ETI), 1) @@ -648,6 +663,21 @@ ifeq ($(KOKKOS_INTERNAL_USE_CUDA), 1) endif endif + ifeq ($(KOKKOS_INTERNAL_CUDA_USE_CONSTEXPR), 1) + ifeq ($(KOKKOS_INTERNAL_COMPILER_NVCC), 1) + ifeq ($(shell test $(KOKKOS_INTERNAL_COMPILER_NVCC_VERSION) -ge 80; echo $$?),0) + tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_CUDA_CONSTEXPR") + KOKKOS_CXXFLAGS += -expt-relaxed-constexpr + else + $(warning Warning: Cuda relaxed constexpr support was requested but NVCC version is too low. This requires NVCC for Cuda version 8.0 or higher. Disabling relaxed constexpr support now.) + endif + endif + + ifeq ($(KOKKOS_INTERNAL_COMPILER_CLANG), 1) + tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_CUDA_CONSTEXPR") + endif + endif + ifeq ($(KOKKOS_INTERNAL_COMPILER_CLANG), 1) tmp := $(call kokkos_append_header,"\#define KOKKOS_IMPL_CUDA_CLANG_WORKAROUND") endif @@ -1089,15 +1119,13 @@ ifeq ($(KOKKOS_INTERNAL_ENABLE_ETI), 1) endif KOKKOS_HEADERS += $(wildcard $(KOKKOS_PATH)/core/src/Cuda/*.hpp) ifneq ($(CUDA_PATH),) - ifneq ($(KOKKOS_CMAKE), yes) - KOKKOS_CXXFLAGS += -I$(CUDA_PATH)/include - endif + KOKKOS_CPPLAGS += -I$(CUDA_PATH)/include ifeq ($(call kokkos_path_exists,$(CUDA_PATH)/lib64), 1) - KOKKOS_LDFLAGS += -L$(CUDA_PATH)/lib64 + KOKKOS_LIBDIRS += -L$(CUDA_PATH)/lib64 KOKKOS_CXXLDFLAGS += -L$(CUDA_PATH)/lib64 KOKKOS_TPL_LIBRARY_DIRS += $(CUDA_PATH)/lib64 else ifeq ($(call kokkos_path_exists,$(CUDA_PATH)/lib), 1) - KOKKOS_LDFLAGS += -L$(CUDA_PATH)/lib + KOKKOS_LIBDIRS += -L$(CUDA_PATH)/lib KOKKOS_CXXLDFLAGS += -L$(CUDA_PATH)/lib KOKKOS_TPL_LIBRARY_DIRS += $(CUDA_PATH)/lib else @@ -1153,17 +1181,17 @@ endif ifeq ($(KOKKOS_INTERNAL_USE_QTHREADS), 1) KOKKOS_SRC += $(wildcard $(KOKKOS_PATH)/core/src/Qthreads/*.cpp) KOKKOS_HEADERS += $(wildcard $(KOKKOS_PATH)/core/src/Qthreads/*.hpp) - ifneq ($(QTHREADS_PATH),) - ifneq ($(KOKKOS_CMAKE), yes) - KOKKOS_CXXFLAGS += -I$(QTHREADS_PATH)/include + ifneq ($(KOKKOS_CMAKE), yes) + ifneq ($(QTHREADS_PATH),) + KOKKOS_CPPFLAGS += -I$(QTHREADS_PATH)/include + KOKKOS_LIBDIRS += -L$(QTHREADS_PATH)/lib + KOKKOS_CXXLDFLAGS += -L$(QTHREADS_PATH)/lib + KOKKOS_TPL_INCLUDE_DIRS += $(QTHREADS_PATH)/include + KOKKOS_TPL_LIBRARY_DIRS += $(QTHREADS_PATH)/lib64 endif - KOKKOS_LDFLAGS += -L$(QTHREADS_PATH)/lib - KOKKOS_CXXLDFLAGS += -L$(QTHREADS_PATH)/lib - KOKKOS_TPL_INCLUDE_DIRS += $(QTHREADS_PATH)/include - KOKKOS_TPL_LIBRARY_DIRS += $(QTHREADS_PATH)/lib64 + KOKKOS_LIBS += -lqthread + KOKKOS_TPL_LIBRARY_NAMES += qthread endif - KOKKOS_LIBS += -lqthread - KOKKOS_TPL_LIBRARY_NAMES += qthread endif ifeq ($(KOKKOS_INTERNAL_USE_HPX), 1) @@ -1173,21 +1201,21 @@ ifeq ($(KOKKOS_INTERNAL_USE_HPX), 1) ifeq ($(KOKKOS_INTERNAL_ENABLE_DEBUG), 1) KOKKOS_CXXFLAGS += $(shell PKG_CONFIG_PATH=$(HPX_PATH)/lib64/pkgconfig pkg-config --cflags hpx_application_debug) KOKKOS_CXXLDFLAGS += $(shell PKG_CONFIG_PATH=$(HPX_PATH)/lib64/pkgconfig pkg-config --libs hpx_application_debug) - KOKKOS_LDFLAGS += $(shell PKG_CONFIG_PATH=$(HPX_PATH)/lib64/pkgconfig pkg-config --libs hpx_application_debug) + KOKKOS_LIBS += $(shell PKG_CONFIG_PATH=$(HPX_PATH)/lib64/pkgconfig pkg-config --libs hpx_application_debug) else KOKKOS_CXXFLAGS += $(shell PKG_CONFIG_PATH=$(HPX_PATH)/lib64/pkgconfig pkg-config --cflags hpx_application) KOKKOS_CXXLDFLAGS += $(shell PKG_CONFIG_PATH=$(HPX_PATH)/lib64/pkgconfig pkg-config --libs hpx_application) - KOKKOS_LDFLAGS += $(shell PKG_CONFIG_PATH=$(HPX_PATH)/lib64/pkgconfig pkg-config --libs hpx_application) + KOKKOS_LIBS += $(shell PKG_CONFIG_PATH=$(HPX_PATH)/lib64/pkgconfig pkg-config --libs hpx_application) endif else ifeq ($(KOKKOS_INTERNAL_ENABLE_DEBUG), 1) KOKKOS_CXXFLAGS += $(shell pkg-config --cflags hpx_application_debug) KOKKOS_CXXLDFLAGS += $(shell pkg-config --libs hpx_application_debug) - KOKKOS_LDFLAGS += $(shell pkg-config --libs hpx_application_debug) + KOKKOS_LIBS += $(shell pkg-config --libs hpx_application_debug) else KOKKOS_CXXFLAGS += $(shell pkg-config --cflags hpx_application) KOKKOS_CXXLDFLAGS += $(shell pkg-config --libs hpx_application) - KOKKOS_LDFLAGS += $(shell pkg-config --libs hpx_application) + KOKKOS_LIBS += $(shell pkg-config --libs hpx_application) endif endif KOKKOS_TPL_LIBRARY_NAMES += hpx @@ -1248,4 +1276,16 @@ libkokkos.a: $(KOKKOS_OBJ_LINK) $(KOKKOS_SRC) $(KOKKOS_HEADERS) ar cr libkokkos.a $(KOKKOS_OBJ_LINK) ranlib libkokkos.a +print-cxx-flags: + echo "$(KOKKOS_CXXFLAGS)" + KOKKOS_LINK_DEPENDS=libkokkos.a + +#we have carefully separated LDFLAGS from LIBS and LIBDIRS +#we have also separated CPPFLAGS from CXXFLAGS +#if this is not cmake, for backwards compatibility +#we just jam everything together into the CXXFLAGS and LDFLAGS +ifneq ($(KOKKOS_CMAKE), yes) + KOKKOS_CXXFLAGS += $(KOKKOS_CPPFLAGS) + KOKKOS_LDFLAGS += $(KOKKOS_LIBDIRS) +endif diff --git a/lib/kokkos/Makefile.targets b/lib/kokkos/Makefile.targets index e7d5a3c907..0a1f522016 100644 --- a/lib/kokkos/Makefile.targets +++ b/lib/kokkos/Makefile.targets @@ -6,6 +6,8 @@ Kokkos_CPUDiscovery.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/impl/Kokkos $(CXX) $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS) $(CXXFLAGS) -c $(KOKKOS_PATH)/core/src/impl/Kokkos_CPUDiscovery.cpp Kokkos_Error.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/impl/Kokkos_Error.cpp $(CXX) $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS) $(CXXFLAGS) -c $(KOKKOS_PATH)/core/src/impl/Kokkos_Error.cpp +Kokkos_Stacktrace.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/impl/Kokkos_Stacktrace.cpp + $(CXX) $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS) $(CXXFLAGS) -c $(KOKKOS_PATH)/core/src/impl/Kokkos_Stacktrace.cpp Kokkos_ExecPolicy.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/impl/Kokkos_ExecPolicy.cpp $(CXX) $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS) $(CXXFLAGS) -c $(KOKKOS_PATH)/core/src/impl/Kokkos_ExecPolicy.cpp Kokkos_HostSpace.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/impl/Kokkos_HostSpace.cpp diff --git a/lib/kokkos/README b/lib/kokkos/README deleted file mode 100644 index cb6ceb5581..0000000000 --- a/lib/kokkos/README +++ /dev/null @@ -1,193 +0,0 @@ -Kokkos Core implements a programming model in C++ for writing performance portable -applications targeting all major HPC platforms. For that purpose it provides -abstractions for both parallel execution of code and data management. -Kokkos is designed to target complex node architectures with N-level memory -hierarchies and multiple types of execution resources. It currently can use -OpenMP, Pthreads and CUDA as backend programming models. - -Kokkos Core is part of the Kokkos C++ Performance Portability Programming EcoSystem, -which also provides math kernels (https://github.com/kokkos/kokkos-kernels), as well as -profiling and debugging tools (https://github.com/kokkos/kokkos-tools). - -# Learning about Kokkos - -A programming guide can be found on the Wiki, the API reference is under development. - -For questions find us on Slack: https://kokkosteam.slack.com or open a github issue. - -For non-public questions send an email to -crtrott(at)sandia.gov - -A separate repository with extensive tutorial material can be found under -https://github.com/kokkos/kokkos-tutorials. - -Furthermore, the 'example/tutorial' directory provides step by step tutorial -examples which explain many of the features of Kokkos. They work with -simple Makefiles. To build with g++ and OpenMP simply type 'make' -in the 'example/tutorial' directory. This will build all examples in the -subfolders. To change the build options refer to the Programming Guide -in the compilation section. - -To learn more about Kokkos consider watching one of our presentations: -* GTC 2015: - - http://on-demand.gputechconf.com/gtc/2015/video/S5166.html - - http://on-demand.gputechconf.com/gtc/2015/presentation/S5166-H-Carter-Edwards.pdf - - -# Contributing to Kokkos - -We are open and try to encourage contributions from external developers. -To do so please first open an issue describing the contribution and then issue -a pull request against the develop branch. For larger features it may be good -to get guidance from the core development team first through the github issue. - -Note that Kokkos Core is licensed under standard 3-clause BSD terms of use. -Which means contributing to Kokkos allows anyone else to use your contributions -not just for public purposes but also for closed source commercial projects. -For specifics see the LICENSE file contained in the repository or distribution. - -# Requirements - -### Primary tested compilers on X86 are: - * GCC 4.8.4 - * GCC 4.9.3 - * GCC 5.1.0 - * GCC 5.5.0 - * GCC 6.1.0 - * GCC 7.2.0 - * GCC 7.3.0 - * GCC 8.1.0 - * Intel 15.0.2 - * Intel 16.0.1 - * Intel 17.0.1 - * Intel 17.4.196 - * Intel 18.2.128 - * Clang 3.6.1 - * Clang 3.7.1 - * Clang 3.8.1 - * Clang 3.9.0 - * Clang 4.0.0 - * Clang 6.0.0 for CUDA (CUDA Toolkit 9.0) - * Clang 7.0.0 for CUDA (CUDA Toolkit 9.1) - * PGI 18.7 - * NVCC 7.5 for CUDA (with gcc 4.8.4) - * NVCC 8.0.44 for CUDA (with gcc 5.3.0) - * NVCC 9.1 for CUDA (with gcc 6.1.0) - * NVCC 9.2 for CUDA (with gcc 7.2.0) - * NVCC 10.0 for CUDA (with gcc 7.4.0) - -### Primary tested compilers on Power 8 are: - * GCC 6.4.0 (OpenMP,Serial) - * GCC 7.2.0 (OpenMP,Serial) - * IBM XL 16.1.0 (OpenMP, Serial) - * NVCC 9.2.88 for CUDA (with gcc 7.2.0 and XL 16.1.0) - -### Primary tested compilers on Intel KNL are: - * Intel 16.4.258 (with gcc 4.7.2) - * Intel 17.2.174 (with gcc 4.9.3) - * Intel 18.2.199 (with gcc 4.9.3) - -### Primary tested compilers on ARM (Cavium ThunderX2) - * GCC 7.2.0 - * ARM/Clang 18.4.0 - -### Other compilers working: - * X86: - - Cygwin 2.1.0 64bit with gcc 4.9.3 - - GCC 8.1.0 (not warning free) - -### Known non-working combinations: - * Power8: - - Pthreads backend - * ARM - - Pthreads backend - - -Primary tested compiler are passing in release mode -with warnings as errors. They also are tested with a comprehensive set of -backend combinations (i.e. OpenMP, Pthreads, Serial, OpenMP+Serial, ...). -We are using the following set of flags: -GCC: -Wall -Wshadow -pedantic -Werror -Wsign-compare -Wtype-limits - -Wignored-qualifiers -Wempty-body -Wclobbered -Wuninitialized -Intel: -Wall -Wshadow -pedantic -Werror -Wsign-compare -Wtype-limits -Wuninitialized -Clang: -Wall -Wshadow -pedantic -Werror -Wsign-compare -Wtype-limits -Wuninitialized -NVCC: -Wall -Wshadow -pedantic -Werror -Wsign-compare -Wtype-limits -Wuninitialized - -Other compilers are tested occasionally, in particular when pushing from develop to -master branch, without -Werror and only for a select set of backends. - -# Running Unit Tests - -To run the unit tests create a build directory and run the following commands - -KOKKOS_PATH/generate_makefile.bash -make build-test -make test - -Run KOKKOS_PATH/generate_makefile.bash --help for more detailed options such as -changing the device type for which to build. - -# Installing the library - -To install Kokkos as a library create a build directory and run the following - -KOKKOS_PATH/generate_makefile.bash --prefix=INSTALL_PATH -make kokkoslib -make install - -KOKKOS_PATH/generate_makefile.bash --help for more detailed options such as -changing the device type for which to build. - -Note that in many cases it is preferable to build Kokkos inline with an -application. The main reason is that you may otherwise need many different -configurations of Kokkos installed depending on the required compile time -features an application needs. For example there is only one default -execution space, which means you need different installations to have OpenMP -or Pthreads as the default space. Also for the CUDA backend there are certain -choices, such as allowing relocatable device code, which must be made at -installation time. Building Kokkos inline uses largely the same process -as compiling an application against an installed Kokkos library. See for -example benchmarks/bytes_and_flops/Makefile which can be used with an installed -library and for an inline build. - -### CMake - -Kokkos supports being build as part of a CMake applications. An example can -be found in example/cmake_build. - -# Kokkos and CUDA UVM - -Kokkos does support UVM as a specific memory space called CudaUVMSpace. -Allocations made with that space are accessible from host and device. -You can tell Kokkos to use that as the default space for Cuda allocations. -In either case UVM comes with a number of restrictions: -(i) You can't access allocations on the host while a kernel is potentially -running. This will lead to segfaults. To avoid that you either need to -call Kokkos::Cuda::fence() (or just Kokkos::fence()), after kernels, or -you can set the environment variable CUDA_LAUNCH_BLOCKING=1. -Furthermore in multi socket multi GPU machines without NVLINK, UVM defaults -to using zero copy allocations for technical reasons related to using multiple -GPUs from the same process. If an executable doesn't do that (e.g. each -MPI rank of an application uses a single GPU [can be the same GPU for -multiple MPI ranks]) you can set CUDA_MANAGED_FORCE_DEVICE_ALLOC=1. -This will enforce proper UVM allocations, but can lead to errors if -more than a single GPU is used by a single process. - - -# Citing Kokkos - -If you publish work which mentions Kokkos, please cite the following paper: - -@article{CarterEdwards20143202, -title = "Kokkos: Enabling manycore performance portability through polymorphic memory access patterns ", -journal = "Journal of Parallel and Distributed Computing ", -volume = "74", -number = "12", -pages = "3202 - 3216", -year = "2014", -note = "Domain-Specific Languages and High-Level Frameworks for High-Performance Computing ", -issn = "0743-7315", -doi = "https://doi.org/10.1016/j.jpdc.2014.07.003", -url = "http://www.sciencedirect.com/science/article/pii/S0743731514001257", -author = "H. Carter Edwards and Christian R. Trott and Daniel Sunderland" -} diff --git a/lib/kokkos/README.md b/lib/kokkos/README.md new file mode 100644 index 0000000000..322dabfdab --- /dev/null +++ b/lib/kokkos/README.md @@ -0,0 +1,299 @@ +![Kokkos](https://avatars2.githubusercontent.com/u/10199860?s=200&v=4) + +# Kokkos: Core Libraries + +Kokkos Core implements a programming model in C++ for writing performance portable +applications targeting all major HPC platforms. For that purpose it provides +abstractions for both parallel execution of code and data management. +Kokkos is designed to target complex node architectures with N-level memory +hierarchies and multiple types of execution resources. It currently can use +CUDA, HPX, OpenMP and Pthreads as backend programming models with several other +backends in development. + +Kokkos Core is part of the Kokkos C++ Performance Portability Programming EcoSystem, +which also provides math kernels (https://github.com/kokkos/kokkos-kernels), as well as +profiling and debugging tools (https://github.com/kokkos/kokkos-tools). + +# Learning about Kokkos + +A programming guide can be found on the Wiki, the API reference is under development. + +For questions find us on Slack: https://kokkosteam.slack.com or open a github issue. + +For non-public questions send an email to +crtrott(at)sandia.gov + +A separate repository with extensive tutorial material can be found under +https://github.com/kokkos/kokkos-tutorials. + +Furthermore, the 'example/tutorial' directory provides step by step tutorial +examples which explain many of the features of Kokkos. They work with +simple Makefiles. To build with g++ and OpenMP simply type 'make' +in the 'example/tutorial' directory. This will build all examples in the +subfolders. To change the build options refer to the Programming Guide +in the compilation section. + +To learn more about Kokkos consider watching one of our presentations: +* GTC 2015: + - http://on-demand.gputechconf.com/gtc/2015/video/S5166.html + - http://on-demand.gputechconf.com/gtc/2015/presentation/S5166-H-Carter-Edwards.pdf + + +# Contributing to Kokkos + +We are open and try to encourage contributions from external developers. +To do so please first open an issue describing the contribution and then issue +a pull request against the develop branch. For larger features it may be good +to get guidance from the core development team first through the github issue. + +Note that Kokkos Core is licensed under standard 3-clause BSD terms of use. +Which means contributing to Kokkos allows anyone else to use your contributions +not just for public purposes but also for closed source commercial projects. +For specifics see the LICENSE file contained in the repository or distribution. + +# Requirements + +### Primary tested compilers on X86 are: +* GCC 4.8.4 +* GCC 4.9.3 +* GCC 5.1.0 +* GCC 5.4.0 +* GCC 5.5.0 +* GCC 6.1.0 +* GCC 7.2.0 +* GCC 7.3.0 +* GCC 8.1.0 +* Intel 15.0.2 +* Intel 16.0.1 +* Intel 17.0.1 +* Intel 17.4.196 +* Intel 18.2.128 +* Clang 3.6.1 +* Clang 3.7.1 +* Clang 3.8.1 +* Clang 3.9.0 +* Clang 4.0.0 +* Clang 6.0.0 for CUDA (CUDA Toolkit 9.0) +* Clang 7.0.0 for CUDA (CUDA Toolkit 9.1) +* Clang 8.0.0 for CUDA (CUDA Toolkit 9.2) +* PGI 18.7 +* NVCC 9.1 for CUDA (with gcc 6.1.0) +* NVCC 9.2 for CUDA (with gcc 7.2.0) +* NVCC 10.0 for CUDA (with gcc 7.4.0) +* NVCC 10.1 for CUDA (with gcc 7.4.0) + +### Primary tested compilers on Power 8 are: +* GCC 6.4.0 (OpenMP,Serial) +* GCC 7.2.0 (OpenMP,Serial) +* IBM XL 16.1.0 (OpenMP, Serial) +* NVCC 9.2.88 for CUDA (with gcc 7.2.0 and XL 16.1.0) + +### Primary tested compilers on Intel KNL are: +* Intel 16.4.258 (with gcc 4.7.2) +* Intel 17.2.174 (with gcc 4.9.3) +* Intel 18.2.199 (with gcc 4.9.3) + +### Primary tested compilers on ARM (Cavium ThunderX2) +* GCC 7.2.0 +* ARM/Clang 18.4.0 + +### Other compilers working: +* X86: + * Cygwin 2.1.0 64bit with gcc 4.9.3 + * GCC 8.1.0 (not warning free) + +### Known non-working combinations: +* Power8: + * Pthreads backend +* ARM + * Pthreads backend + + +Primary tested compiler are passing in release mode +with warnings as errors. They also are tested with a comprehensive set of +backend combinations (i.e. OpenMP, Pthreads, Serial, OpenMP+Serial, ...). +We are using the following set of flags: +* GCC: + ```` + -Wall -Wshadow -pedantic + -Werror -Wsign-compare -Wtype-limits + -Wignored-qualifiers -Wempty-body + -Wclobbered -Wuninitialized + ```` +* Intel: + ```` + -Wall -Wshadow -pedantic + -Werror -Wsign-compare -Wtype-limits + -Wuninitialized + ```` +* Clang: + ```` + -Wall -Wshadow -pedantic + -Werror -Wsign-compare -Wtype-limits + -Wuninitialized + ```` + +* NVCC: + ```` + -Wall -Wshadow -pedantic + -Werror -Wsign-compare -Wtype-limits + -Wuninitialized + ```` + +Other compilers are tested occasionally, in particular when pushing from develop to +master branch. These are tested less rigorously without `-Werror` and only for a select set of backends. + +# Building and Installing Kokkos +Kokkos provide a CMake build system and a raw Makefile build system. +The CMake build system is strongly encouraged and will be the most rigorously supported in future releases. +Full details are given in the [build instructions](BUILD.md). Basic setups are shown here: + +## CMake + +The best way to install Kokkos is using the CMake build system. Assuming Kokkos lives in `$srcdir`: +```` +cmake $srcdir \ + -DCMAKE_CXX_COMPILER=$path_to_compiler \ + -DCMAKE_INSTALL_PREFIX=$path_to_install \ + -DKokkos_ENABLE_OPENMP=On \ + -DKokkos_ARCH_HSW=On \ + -DKokkos_ENABLE_HWLOC=On \ + -DKokkos_HWLOC_DIR=$path_to_hwloc +```` +then simply type `make install`. The Kokkos CMake package will then be installed in `$path_to_install` to be used by downstream packages. + +To validate the Kokkos build, configure with +```` + -DKokkos_ENABLE_TESTS=On +```` +and run `make test` after completing the build. + +For your CMake project using Kokkos, code such as the following: + +```` +find_package(Kokkos) +... +target_link_libraries(myTarget Kokkos::kokkos) +```` +should be added to your CMakeLists.txt. Your configure should additionally include +```` +-DKokkos_DIR=$path_to_install/cmake/lib/Kokkos +```` +or +```` +-DKokkos_ROOT=$path_to_install +```` +for the install location given above. + +## Spack +An alternative to manually building with the CMake is to use the Spack package manager. +To do so, download the `kokkos-spack` git repo and add to the package list: +```` +spack repo add $path-to-kokkos-spack +```` +A basic installation would be done as: +```` +spack install kokkos +```` +Spack allows options and and compilers to be tuned in the install command. +```` +spack install kokkos@3.0 %gcc@7.3.0 +openmp +```` +This example illustrates the three most common parameters to Spack: +* Variants: specified with, e.g. `+openmp`, this activates (or deactivates with, e.g. `~openmp`) certain options. +* Version: immediately following `kokkos` the `@version` can specify a particular Kokkos to build +* Compiler: a default compiler will be chosen if not specified, but an exact compiler version can be given with the `%`option. + +For a complete list of Kokkos options, run: +```` +spack info kokkos +```` +Spack currently installs packages to a location determined by a unique hash. This hash name is not really "human readable". +Generally, Spack usage should never really require you to reference the computer-generated unique install folder. +More details are given in the [build instructions](BUILD.md). If you must know, you can locate Spack Kokkos installations with: +```` +spack find -p kokkos ... +```` +where `...` is the unique spec identifying the particular Kokkos configuration and version. + + +## Raw Makefile +A bash script is provided to generate raw makefiles. +To install Kokkos as a library create a build directory and run the following +```` +$KOKKOS_PATH/generate_makefile.bash --prefix=$path_to_install +```` +Once the Makefile is generated, run: +```` +make kokkoslib +make install +```` +To additionally run the unit tests: +```` +make build-test +make test +```` +Run `generate_makefile.bash --help` for more detailed options such as +changing the device type for which to build. + +## Inline Builds vs. Installed Package +For individual projects, it may be preferable to build Kokkos inline rather than link to an installed package. +The main reason is that you may otherwise need many different +configurations of Kokkos installed depending on the required compile time +features an application needs. For example there is only one default +execution space, which means you need different installations to have OpenMP +or Pthreads as the default space. Also for the CUDA backend there are certain +choices, such as allowing relocatable device code, which must be made at +installation time. Building Kokkos inline uses largely the same process +as compiling an application against an installed Kokkos library. + +For CMake, this means copying over the Kokkos source code into your project and adding `add_subdirectory(kokkos)` to your CMakeLists.txt. + +For raw Makefiles, see the example benchmarks/bytes_and_flops/Makefile which can be used with an installed library and or an inline build. + +# Kokkos and CUDA UVM + +Kokkos does support UVM as a specific memory space called CudaUVMSpace. +Allocations made with that space are accessible from host and device. +You can tell Kokkos to use that as the default space for Cuda allocations. +In either case UVM comes with a number of restrictions: +* You can't access allocations on the host while a kernel is potentially +running. This will lead to segfaults. To avoid that you either need to +call Kokkos::Cuda::fence() (or just Kokkos::fence()), after kernels, or +you can set the environment variable CUDA_LAUNCH_BLOCKING=1. +* In multi socket multi GPU machines without NVLINK, UVM defaults +to using zero copy allocations for technical reasons related to using multiple +GPUs from the same process. If an executable doesn't do that (e.g. each +MPI rank of an application uses a single GPU [can be the same GPU for +multiple MPI ranks]) you can set CUDA_MANAGED_FORCE_DEVICE_ALLOC=1. +This will enforce proper UVM allocations, but can lead to errors if +more than a single GPU is used by a single process. + + +# Citing Kokkos + +If you publish work which mentions Kokkos, please cite the following paper: + +```` +@article{CarterEdwards20143202, + title = "Kokkos: Enabling manycore performance portability through polymorphic memory access patterns ", + journal = "Journal of Parallel and Distributed Computing ", + volume = "74", + number = "12", + pages = "3202 - 3216", + year = "2014", + note = "Domain-Specific Languages and High-Level Frameworks for High-Performance Computing ", + issn = "0743-7315", + doi = "https://doi.org/10.1016/j.jpdc.2014.07.003", + url = "http://www.sciencedirect.com/science/article/pii/S0743731514001257", + author = "H. Carter Edwards and Christian R. Trott and Daniel Sunderland" +} +```` + +##### [LICENSE](https://github.com/kokkos/kokkos/blob/master/LICENSE) + +[![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) + +Under the terms of Contract DE-NA0003525 with NTESS, +the U.S. Government retains certain rights in this software. + diff --git a/lib/kokkos/algorithms/CMakeLists.txt b/lib/kokkos/algorithms/CMakeLists.txt index 507c9f2fdb..38747c152c 100644 --- a/lib/kokkos/algorithms/CMakeLists.txt +++ b/lib/kokkos/algorithms/CMakeLists.txt @@ -1,12 +1,12 @@ - - -TRIBITS_SUBPACKAGE(Algorithms) - -IF(KOKKOS_HAS_TRILINOS) - ADD_SUBDIRECTORY(src) -ENDIF() - -TRIBITS_ADD_TEST_DIRECTORIES(unit_tests) -#TRIBITS_ADD_TEST_DIRECTORIES(performance_tests) - -TRIBITS_SUBPACKAGE_POSTPROCESS() + + +KOKKOS_SUBPACKAGE(Algorithms) + +ADD_SUBDIRECTORY(src) + +KOKKOS_ADD_TEST_DIRECTORIES(unit_tests) + +KOKKOS_SUBPACKAGE_POSTPROCESS() + + + diff --git a/lib/kokkos/algorithms/src/CMakeLists.txt b/lib/kokkos/algorithms/src/CMakeLists.txt index dfbf3323c2..5afd319fcc 100644 --- a/lib/kokkos/algorithms/src/CMakeLists.txt +++ b/lib/kokkos/algorithms/src/CMakeLists.txt @@ -1,8 +1,9 @@ -TRIBITS_CONFIGURE_FILE(${PACKAGE_NAME}_config.h) +KOKKOS_CONFIGURE_FILE(${PACKAGE_NAME}_config.h) -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) +#I have to leave these here for tribits +KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) #----------------------------------------------------------------------------- @@ -12,10 +13,18 @@ LIST(APPEND HEADERS ${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME}_config.h) #----------------------------------------------------------------------------- -TRIBITS_ADD_LIBRARY( - kokkosalgorithms - HEADERS ${HEADERS} - SOURCES ${SOURCES} - DEPLIBS - ) +# We have to pass the sources in here for Tribits +# These will get ignored for standalone CMake and a true interface library made +KOKKOS_ADD_INTERFACE_LIBRARY( + kokkosalgorithms + HEADERS ${HEADERS} + SOURCES ${SOURCES} +) +KOKKOS_LIB_INCLUDE_DIRECTORIES(kokkosalgorithms + ${KOKKOS_TOP_BUILD_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} +) + + diff --git a/lib/kokkos/algorithms/src/Kokkos_Random.hpp b/lib/kokkos/algorithms/src/Kokkos_Random.hpp index da781de4fe..078db18edd 100644 --- a/lib/kokkos/algorithms/src/Kokkos_Random.hpp +++ b/lib/kokkos/algorithms/src/Kokkos_Random.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -59,6 +60,7 @@ namespace Kokkos { +// clang-format off /*Template functions to get equidistributed random numbers from a generator for a specific Scalar type template @@ -229,1019 +231,979 @@ namespace Kokkos { ViewType::value_type start, ViewType::value_type end); */ +// clang-format on - template - struct rand; - - - template - struct rand { - - KOKKOS_INLINE_FUNCTION - static short max(){return 127;} - KOKKOS_INLINE_FUNCTION - static short draw(Generator& gen) - {return short((gen.rand()&0xff+256)%256);} - KOKKOS_INLINE_FUNCTION - static short draw(Generator& gen, const char& range) - {return char(gen.rand(range));} - KOKKOS_INLINE_FUNCTION - static short draw(Generator& gen, const char& start, const char& end) - {return char(gen.rand(start,end));} - - }; - - template - struct rand { - KOKKOS_INLINE_FUNCTION - static short max(){return 32767;} - KOKKOS_INLINE_FUNCTION - static short draw(Generator& gen) - {return short((gen.rand()&0xffff+65536)%32768);} - KOKKOS_INLINE_FUNCTION - static short draw(Generator& gen, const short& range) - {return short(gen.rand(range));} - KOKKOS_INLINE_FUNCTION - static short draw(Generator& gen, const short& start, const short& end) - {return short(gen.rand(start,end));} - - }; - - template - struct rand { - KOKKOS_INLINE_FUNCTION - static int max(){return Generator::MAX_RAND;} - KOKKOS_INLINE_FUNCTION - static int draw(Generator& gen) - {return gen.rand();} - KOKKOS_INLINE_FUNCTION - static int draw(Generator& gen, const int& range) - {return gen.rand(range);} - KOKKOS_INLINE_FUNCTION - static int draw(Generator& gen, const int& start, const int& end) - {return gen.rand(start,end);} +template +struct rand; - }; +template +struct rand { + KOKKOS_INLINE_FUNCTION + static short max() { return 127; } + KOKKOS_INLINE_FUNCTION + static short draw(Generator& gen) { + return short((gen.rand() & 0xff + 256) % 256); + } + KOKKOS_INLINE_FUNCTION + static short draw(Generator& gen, const char& range) { + return char(gen.rand(range)); + } + KOKKOS_INLINE_FUNCTION + static short draw(Generator& gen, const char& start, const char& end) { + return char(gen.rand(start, end)); + } +}; - template - struct rand { - KOKKOS_INLINE_FUNCTION - static unsigned int max () { - return Generator::MAX_URAND; - } - KOKKOS_INLINE_FUNCTION - static unsigned int draw (Generator& gen) { - return gen.urand (); - } - KOKKOS_INLINE_FUNCTION - static unsigned int draw(Generator& gen, const unsigned int& range) { - return gen.urand (range); - } - KOKKOS_INLINE_FUNCTION - static unsigned int - draw (Generator& gen, const unsigned int& start, const unsigned int& end) { - return gen.urand (start, end); - } - }; +template +struct rand { + KOKKOS_INLINE_FUNCTION + static short max() { return 32767; } + KOKKOS_INLINE_FUNCTION + static short draw(Generator& gen) { + return short((gen.rand() & 0xffff + 65536) % 32768); + } + KOKKOS_INLINE_FUNCTION + static short draw(Generator& gen, const short& range) { + return short(gen.rand(range)); + } + KOKKOS_INLINE_FUNCTION + static short draw(Generator& gen, const short& start, const short& end) { + return short(gen.rand(start, end)); + } +}; - template - struct rand { - KOKKOS_INLINE_FUNCTION - static long max () { - // FIXME (mfh 26 Oct 2014) It would be better to select the - // return value at compile time, using something like enable_if. - return sizeof (long) == 4 ? - static_cast (Generator::MAX_RAND) : - static_cast (Generator::MAX_RAND64); - } - KOKKOS_INLINE_FUNCTION - static long draw (Generator& gen) { - // FIXME (mfh 26 Oct 2014) It would be better to select the - // return value at compile time, using something like enable_if. - return sizeof (long) == 4 ? - static_cast (gen.rand ()) : - static_cast (gen.rand64 ()); - } - KOKKOS_INLINE_FUNCTION - static long draw (Generator& gen, const long& range) { - // FIXME (mfh 26 Oct 2014) It would be better to select the - // return value at compile time, using something like enable_if. - return sizeof (long) == 4 ? - static_cast (gen.rand (static_cast (range))) : - static_cast (gen.rand64 (range)); - } - KOKKOS_INLINE_FUNCTION - static long draw (Generator& gen, const long& start, const long& end) { - // FIXME (mfh 26 Oct 2014) It would be better to select the - // return value at compile time, using something like enable_if. - return sizeof (long) == 4 ? - static_cast (gen.rand (static_cast (start), - static_cast (end))) : - static_cast (gen.rand64 (start, end)); - } - }; +template +struct rand { + KOKKOS_INLINE_FUNCTION + static int max() { return Generator::MAX_RAND; } + KOKKOS_INLINE_FUNCTION + static int draw(Generator& gen) { return gen.rand(); } + KOKKOS_INLINE_FUNCTION + static int draw(Generator& gen, const int& range) { return gen.rand(range); } + KOKKOS_INLINE_FUNCTION + static int draw(Generator& gen, const int& start, const int& end) { + return gen.rand(start, end); + } +}; - template - struct rand { - KOKKOS_INLINE_FUNCTION - static unsigned long max () { - // FIXME (mfh 26 Oct 2014) It would be better to select the - // return value at compile time, using something like enable_if. - return sizeof (unsigned long) == 4 ? - static_cast (Generator::MAX_URAND) : - static_cast (Generator::MAX_URAND64); - } - KOKKOS_INLINE_FUNCTION - static unsigned long draw (Generator& gen) { - // FIXME (mfh 26 Oct 2014) It would be better to select the - // return value at compile time, using something like enable_if. - return sizeof (unsigned long) == 4 ? - static_cast (gen.urand ()) : - static_cast (gen.urand64 ()); - } - KOKKOS_INLINE_FUNCTION - static unsigned long draw(Generator& gen, const unsigned long& range) { - // FIXME (mfh 26 Oct 2014) It would be better to select the - // return value at compile time, using something like enable_if. - return sizeof (unsigned long) == 4 ? - static_cast (gen.urand (static_cast (range))) : - static_cast (gen.urand64 (range)); - } - KOKKOS_INLINE_FUNCTION - static unsigned long - draw (Generator& gen, const unsigned long& start, const unsigned long& end) { - // FIXME (mfh 26 Oct 2014) It would be better to select the - // return value at compile time, using something like enable_if. - return sizeof (unsigned long) == 4 ? - static_cast (gen.urand (static_cast (start), - static_cast (end))) : - static_cast (gen.urand64 (start, end)); - } - }; +template +struct rand { + KOKKOS_INLINE_FUNCTION + static unsigned int max() { return Generator::MAX_URAND; } + KOKKOS_INLINE_FUNCTION + static unsigned int draw(Generator& gen) { return gen.urand(); } + KOKKOS_INLINE_FUNCTION + static unsigned int draw(Generator& gen, const unsigned int& range) { + return gen.urand(range); + } + KOKKOS_INLINE_FUNCTION + static unsigned int draw(Generator& gen, const unsigned int& start, + const unsigned int& end) { + return gen.urand(start, end); + } +}; - // NOTE (mfh 26 oct 2014) This is a partial specialization for long - // long, a C99 / C++11 signed type which is guaranteed to be at - // least 64 bits. Do NOT write a partial specialization for - // int64_t!!! This is just a typedef! It could be either long or - // long long. We don't know which a priori, and I've seen both. - // The types long and long long are guaranteed to differ, so it's - // always safe to specialize for both. - template - struct rand { - KOKKOS_INLINE_FUNCTION - static long long max () { - // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. - return Generator::MAX_RAND64; - } - KOKKOS_INLINE_FUNCTION - static long long draw (Generator& gen) { - // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. - return gen.rand64 (); - } - KOKKOS_INLINE_FUNCTION - static long long draw (Generator& gen, const long long& range) { - // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. - return gen.rand64 (range); - } - KOKKOS_INLINE_FUNCTION - static long long draw (Generator& gen, const long long& start, const long long& end) { - // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. - return gen.rand64 (start, end); - } - }; +template +struct rand { + KOKKOS_INLINE_FUNCTION + static long max() { + // FIXME (mfh 26 Oct 2014) It would be better to select the + // return value at compile time, using something like enable_if. + return sizeof(long) == 4 ? static_cast(Generator::MAX_RAND) + : static_cast(Generator::MAX_RAND64); + } + KOKKOS_INLINE_FUNCTION + static long draw(Generator& gen) { + // FIXME (mfh 26 Oct 2014) It would be better to select the + // return value at compile time, using something like enable_if. + return sizeof(long) == 4 ? static_cast(gen.rand()) + : static_cast(gen.rand64()); + } + KOKKOS_INLINE_FUNCTION + static long draw(Generator& gen, const long& range) { + // FIXME (mfh 26 Oct 2014) It would be better to select the + // return value at compile time, using something like enable_if. + return sizeof(long) == 4 + ? static_cast(gen.rand(static_cast(range))) + : static_cast(gen.rand64(range)); + } + KOKKOS_INLINE_FUNCTION + static long draw(Generator& gen, const long& start, const long& end) { + // FIXME (mfh 26 Oct 2014) It would be better to select the + // return value at compile time, using something like enable_if. + return sizeof(long) == 4 + ? static_cast( + gen.rand(static_cast(start), static_cast(end))) + : static_cast(gen.rand64(start, end)); + } +}; - // NOTE (mfh 26 oct 2014) This is a partial specialization for - // unsigned long long, a C99 / C++11 unsigned type which is - // guaranteed to be at least 64 bits. Do NOT write a partial - // specialization for uint64_t!!! This is just a typedef! It could - // be either unsigned long or unsigned long long. We don't know - // which a priori, and I've seen both. The types unsigned long and - // unsigned long long are guaranteed to differ, so it's always safe - // to specialize for both. - template - struct rand { - KOKKOS_INLINE_FUNCTION - static unsigned long long max () { - // FIXME (mfh 26 Oct 2014) It's legal for unsigned long long to be > 64 bits. - return Generator::MAX_URAND64; - } - KOKKOS_INLINE_FUNCTION - static unsigned long long draw (Generator& gen) { - // FIXME (mfh 26 Oct 2014) It's legal for unsigned long long to be > 64 bits. - return gen.urand64 (); - } - KOKKOS_INLINE_FUNCTION - static unsigned long long draw (Generator& gen, const unsigned long long& range) { - // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. - return gen.urand64 (range); - } - KOKKOS_INLINE_FUNCTION - static unsigned long long - draw (Generator& gen, const unsigned long long& start, const unsigned long long& end) { - // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. - return gen.urand64 (start, end); - } - }; +template +struct rand { + KOKKOS_INLINE_FUNCTION + static unsigned long max() { + // FIXME (mfh 26 Oct 2014) It would be better to select the + // return value at compile time, using something like enable_if. + return sizeof(unsigned long) == 4 + ? static_cast(Generator::MAX_URAND) + : static_cast(Generator::MAX_URAND64); + } + KOKKOS_INLINE_FUNCTION + static unsigned long draw(Generator& gen) { + // FIXME (mfh 26 Oct 2014) It would be better to select the + // return value at compile time, using something like enable_if. + return sizeof(unsigned long) == 4 + ? static_cast(gen.urand()) + : static_cast(gen.urand64()); + } + KOKKOS_INLINE_FUNCTION + static unsigned long draw(Generator& gen, const unsigned long& range) { + // FIXME (mfh 26 Oct 2014) It would be better to select the + // return value at compile time, using something like enable_if. + return sizeof(unsigned long) == 4 + ? static_cast( + gen.urand(static_cast(range))) + : static_cast(gen.urand64(range)); + } + KOKKOS_INLINE_FUNCTION + static unsigned long draw(Generator& gen, const unsigned long& start, + const unsigned long& end) { + // FIXME (mfh 26 Oct 2014) It would be better to select the + // return value at compile time, using something like enable_if. + return sizeof(unsigned long) == 4 + ? static_cast( + gen.urand(static_cast(start), + static_cast(end))) + : static_cast(gen.urand64(start, end)); + } +}; - template - struct rand { - KOKKOS_INLINE_FUNCTION - static float max(){return 1.0f;} - KOKKOS_INLINE_FUNCTION - static float draw(Generator& gen) - {return gen.frand();} - KOKKOS_INLINE_FUNCTION - static float draw(Generator& gen, const float& range) - {return gen.frand(range);} - KOKKOS_INLINE_FUNCTION - static float draw(Generator& gen, const float& start, const float& end) - {return gen.frand(start,end);} +// NOTE (mfh 26 oct 2014) This is a partial specialization for long +// long, a C99 / C++11 signed type which is guaranteed to be at +// least 64 bits. Do NOT write a partial specialization for +// int64_t!!! This is just a typedef! It could be either long or +// long long. We don't know which a priori, and I've seen both. +// The types long and long long are guaranteed to differ, so it's +// always safe to specialize for both. +template +struct rand { + KOKKOS_INLINE_FUNCTION + static long long max() { + // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. + return Generator::MAX_RAND64; + } + KOKKOS_INLINE_FUNCTION + static long long draw(Generator& gen) { + // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. + return gen.rand64(); + } + KOKKOS_INLINE_FUNCTION + static long long draw(Generator& gen, const long long& range) { + // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. + return gen.rand64(range); + } + KOKKOS_INLINE_FUNCTION + static long long draw(Generator& gen, const long long& start, + const long long& end) { + // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. + return gen.rand64(start, end); + } +}; - }; +// NOTE (mfh 26 oct 2014) This is a partial specialization for +// unsigned long long, a C99 / C++11 unsigned type which is +// guaranteed to be at least 64 bits. Do NOT write a partial +// specialization for uint64_t!!! This is just a typedef! It could +// be either unsigned long or unsigned long long. We don't know +// which a priori, and I've seen both. The types unsigned long and +// unsigned long long are guaranteed to differ, so it's always safe +// to specialize for both. +template +struct rand { + KOKKOS_INLINE_FUNCTION + static unsigned long long max() { + // FIXME (mfh 26 Oct 2014) It's legal for unsigned long long to be > 64 + // bits. + return Generator::MAX_URAND64; + } + KOKKOS_INLINE_FUNCTION + static unsigned long long draw(Generator& gen) { + // FIXME (mfh 26 Oct 2014) It's legal for unsigned long long to be > 64 + // bits. + return gen.urand64(); + } + KOKKOS_INLINE_FUNCTION + static unsigned long long draw(Generator& gen, + const unsigned long long& range) { + // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. + return gen.urand64(range); + } + KOKKOS_INLINE_FUNCTION + static unsigned long long draw(Generator& gen, + const unsigned long long& start, + const unsigned long long& end) { + // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. + return gen.urand64(start, end); + } +}; - template - struct rand { - KOKKOS_INLINE_FUNCTION - static double max(){return 1.0;} - KOKKOS_INLINE_FUNCTION - static double draw(Generator& gen) - {return gen.drand();} - KOKKOS_INLINE_FUNCTION - static double draw(Generator& gen, const double& range) - {return gen.drand(range);} - KOKKOS_INLINE_FUNCTION - static double draw(Generator& gen, const double& start, const double& end) - {return gen.drand(start,end);} +template +struct rand { + KOKKOS_INLINE_FUNCTION + static float max() { return 1.0f; } + KOKKOS_INLINE_FUNCTION + static float draw(Generator& gen) { return gen.frand(); } + KOKKOS_INLINE_FUNCTION + static float draw(Generator& gen, const float& range) { + return gen.frand(range); + } + KOKKOS_INLINE_FUNCTION + static float draw(Generator& gen, const float& start, const float& end) { + return gen.frand(start, end); + } +}; - }; +template +struct rand { + KOKKOS_INLINE_FUNCTION + static double max() { return 1.0; } + KOKKOS_INLINE_FUNCTION + static double draw(Generator& gen) { return gen.drand(); } + KOKKOS_INLINE_FUNCTION + static double draw(Generator& gen, const double& range) { + return gen.drand(range); + } + KOKKOS_INLINE_FUNCTION + static double draw(Generator& gen, const double& start, const double& end) { + return gen.drand(start, end); + } +}; - template - struct rand > { - KOKKOS_INLINE_FUNCTION - static Kokkos::complex max () { - return Kokkos::complex (1.0, 1.0); - } - KOKKOS_INLINE_FUNCTION - static Kokkos::complex draw (Generator& gen) { - const float re = gen.frand (); - const float im = gen.frand (); - return Kokkos::complex (re, im); - } - KOKKOS_INLINE_FUNCTION - static Kokkos::complex draw (Generator& gen, const Kokkos::complex& range) { - const float re = gen.frand (real (range)); - const float im = gen.frand (imag (range)); - return Kokkos::complex (re, im); - } - KOKKOS_INLINE_FUNCTION - static Kokkos::complex draw (Generator& gen, const Kokkos::complex& start, const Kokkos::complex& end) { - const float re = gen.frand (real (start), real (end)); - const float im = gen.frand (imag (start), imag (end)); - return Kokkos::complex (re, im); - } - }; +template +struct rand > { + KOKKOS_INLINE_FUNCTION + static Kokkos::complex max() { + return Kokkos::complex(1.0, 1.0); + } + KOKKOS_INLINE_FUNCTION + static Kokkos::complex draw(Generator& gen) { + const float re = gen.frand(); + const float im = gen.frand(); + return Kokkos::complex(re, im); + } + KOKKOS_INLINE_FUNCTION + static Kokkos::complex draw(Generator& gen, + const Kokkos::complex& range) { + const float re = gen.frand(real(range)); + const float im = gen.frand(imag(range)); + return Kokkos::complex(re, im); + } + KOKKOS_INLINE_FUNCTION + static Kokkos::complex draw(Generator& gen, + const Kokkos::complex& start, + const Kokkos::complex& end) { + const float re = gen.frand(real(start), real(end)); + const float im = gen.frand(imag(start), imag(end)); + return Kokkos::complex(re, im); + } +}; - template - struct rand > { - KOKKOS_INLINE_FUNCTION - static Kokkos::complex max () { - return Kokkos::complex (1.0, 1.0); - } - KOKKOS_INLINE_FUNCTION - static Kokkos::complex draw (Generator& gen) { - const double re = gen.drand (); - const double im = gen.drand (); - return Kokkos::complex (re, im); - } - KOKKOS_INLINE_FUNCTION - static Kokkos::complex draw (Generator& gen, const Kokkos::complex& range) { - const double re = gen.drand (real (range)); - const double im = gen.drand (imag (range)); - return Kokkos::complex (re, im); - } - KOKKOS_INLINE_FUNCTION - static Kokkos::complex draw (Generator& gen, const Kokkos::complex& start, const Kokkos::complex& end) { - const double re = gen.drand (real (start), real (end)); - const double im = gen.drand (imag (start), imag (end)); - return Kokkos::complex (re, im); - } - }; +template +struct rand > { + KOKKOS_INLINE_FUNCTION + static Kokkos::complex max() { + return Kokkos::complex(1.0, 1.0); + } + KOKKOS_INLINE_FUNCTION + static Kokkos::complex draw(Generator& gen) { + const double re = gen.drand(); + const double im = gen.drand(); + return Kokkos::complex(re, im); + } + KOKKOS_INLINE_FUNCTION + static Kokkos::complex draw(Generator& gen, + const Kokkos::complex& range) { + const double re = gen.drand(real(range)); + const double im = gen.drand(imag(range)); + return Kokkos::complex(re, im); + } + KOKKOS_INLINE_FUNCTION + static Kokkos::complex draw(Generator& gen, + const Kokkos::complex& start, + const Kokkos::complex& end) { + const double re = gen.drand(real(start), real(end)); + const double im = gen.drand(imag(start), imag(end)); + return Kokkos::complex(re, im); + } +}; - template - class Random_XorShift64_Pool; +template +class Random_XorShift64_Pool; - template - class Random_XorShift64 { - private: - uint64_t state_; - const int state_idx_; - friend class Random_XorShift64_Pool; - public: +template +class Random_XorShift64 { + private: + uint64_t state_; + const int state_idx_; + friend class Random_XorShift64_Pool; - typedef DeviceType device_type; + public: + typedef DeviceType device_type; - enum {MAX_URAND = 0xffffffffU}; - enum {MAX_URAND64 = 0xffffffffffffffffULL-1}; - enum {MAX_RAND = static_cast(0xffffffff/2)}; - enum {MAX_RAND64 = static_cast(0xffffffffffffffffLL/2-1)}; + enum { MAX_URAND = 0xffffffffU }; + enum { MAX_URAND64 = 0xffffffffffffffffULL - 1 }; + enum { MAX_RAND = static_cast(0xffffffff / 2) }; + enum { MAX_RAND64 = static_cast(0xffffffffffffffffLL / 2 - 1) }; - KOKKOS_INLINE_FUNCTION - Random_XorShift64 (uint64_t state, int state_idx = 0) - : state_(state==0?uint64_t(1318319):state),state_idx_(state_idx){} + KOKKOS_INLINE_FUNCTION + Random_XorShift64(uint64_t state, int state_idx = 0) + : state_(state == 0 ? uint64_t(1318319) : state), state_idx_(state_idx) {} - KOKKOS_INLINE_FUNCTION - uint32_t urand() { - state_ ^= state_ >> 12; - state_ ^= state_ << 25; - state_ ^= state_ >> 27; - - uint64_t tmp = state_ * 2685821657736338717ULL; - tmp = tmp>>16; - return static_cast(tmp&MAX_URAND); - } + KOKKOS_INLINE_FUNCTION + uint32_t urand() { + state_ ^= state_ >> 12; + state_ ^= state_ << 25; + state_ ^= state_ >> 27; + + uint64_t tmp = state_ * 2685821657736338717ULL; + tmp = tmp >> 16; + return static_cast(tmp & MAX_URAND); + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64() { - state_ ^= state_ >> 12; - state_ ^= state_ << 25; - state_ ^= state_ >> 27; - return (state_ * 2685821657736338717ULL) - 1; - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64() { + state_ ^= state_ >> 12; + state_ ^= state_ << 25; + state_ ^= state_ >> 27; + return (state_ * 2685821657736338717ULL) - 1; + } - KOKKOS_INLINE_FUNCTION - uint32_t urand(const uint32_t& range) { - const uint32_t max_val = (MAX_URAND/range)*range; - uint32_t tmp = urand(); - while(tmp>=max_val) - tmp = urand(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + uint32_t urand(const uint32_t& range) { + const uint32_t max_val = (MAX_URAND / range) * range; + uint32_t tmp = urand(); + while (tmp >= max_val) tmp = urand(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - uint32_t urand(const uint32_t& start, const uint32_t& end ) { - return urand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + uint32_t urand(const uint32_t& start, const uint32_t& end) { + return urand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64(const uint64_t& range) { - const uint64_t max_val = (MAX_URAND64/range)*range; - uint64_t tmp = urand64(); - while(tmp>=max_val) - tmp = urand64(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64(const uint64_t& range) { + const uint64_t max_val = (MAX_URAND64 / range) * range; + uint64_t tmp = urand64(); + while (tmp >= max_val) tmp = urand64(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64(const uint64_t& start, const uint64_t& end ) { - return urand64(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64(const uint64_t& start, const uint64_t& end) { + return urand64(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - int rand() { - return static_cast(urand()/2); - } + KOKKOS_INLINE_FUNCTION + int rand() { return static_cast(urand() / 2); } - KOKKOS_INLINE_FUNCTION - int rand(const int& range) { - const int max_val = (MAX_RAND/range)*range; - int tmp = rand(); - while(tmp>=max_val) - tmp = rand(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + int rand(const int& range) { + const int max_val = (MAX_RAND / range) * range; + int tmp = rand(); + while (tmp >= max_val) tmp = rand(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - int rand(const int& start, const int& end ) { - return rand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + int rand(const int& start, const int& end) { + return rand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - int64_t rand64() { - return static_cast(urand64()/2); - } + KOKKOS_INLINE_FUNCTION + int64_t rand64() { return static_cast(urand64() / 2); } - KOKKOS_INLINE_FUNCTION - int64_t rand64(const int64_t& range) { - const int64_t max_val = (MAX_RAND64/range)*range; - int64_t tmp = rand64(); - while(tmp>=max_val) - tmp = rand64(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + int64_t rand64(const int64_t& range) { + const int64_t max_val = (MAX_RAND64 / range) * range; + int64_t tmp = rand64(); + while (tmp >= max_val) tmp = rand64(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - int64_t rand64(const int64_t& start, const int64_t& end ) { - return rand64(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + int64_t rand64(const int64_t& start, const int64_t& end) { + return rand64(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - float frand() { - return 1.0f * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + float frand() { return 1.0f * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - float frand(const float& range) { - return range * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + float frand(const float& range) { return range * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - float frand(const float& start, const float& end ) { - return frand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + float frand(const float& start, const float& end) { + return frand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - double drand() { - return 1.0 * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + double drand() { return 1.0 * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - double drand(const double& range) { - return range * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + double drand(const double& range) { return range * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - double drand(const double& start, const double& end ) { - return drand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + double drand(const double& start, const double& end) { + return drand(end - start) + start; + } - //Marsaglia polar method for drawing a standard normal distributed random number - KOKKOS_INLINE_FUNCTION - double normal() { - double S = 2.0; - double U; - while(S>=1.0) { - U = 2.0*drand() - 1.0; - const double V = 2.0*drand() - 1.0; - S = U*U+V*V; - } - return U*std::sqrt(-2.0*log(S)/S); - } + // Marsaglia polar method for drawing a standard normal distributed random + // number + KOKKOS_INLINE_FUNCTION + double normal() { + double S = 2.0; + double U; + while (S >= 1.0) { + U = 2.0 * drand() - 1.0; + const double V = 2.0 * drand() - 1.0; + S = U * U + V * V; + } + return U * std::sqrt(-2.0 * log(S) / S); + } - KOKKOS_INLINE_FUNCTION - double normal(const double& mean, const double& std_dev=1.0) { - return mean + normal()*std_dev; - } + KOKKOS_INLINE_FUNCTION + double normal(const double& mean, const double& std_dev = 1.0) { + return mean + normal() * std_dev; + } +}; - }; +template +class Random_XorShift64_Pool { + private: + typedef View lock_type; + typedef View state_data_type; + lock_type locks_; + state_data_type state_; + int num_states_; - template - class Random_XorShift64_Pool { - private: - typedef View lock_type; - typedef View state_data_type; - lock_type locks_; - state_data_type state_; - int num_states_; - - public: - typedef Random_XorShift64 generator_type; - typedef DeviceType device_type; + public: + typedef Random_XorShift64 generator_type; + typedef DeviceType device_type; - KOKKOS_INLINE_FUNCTION - Random_XorShift64_Pool() { - num_states_ = 0; - } - Random_XorShift64_Pool(uint64_t seed) { - num_states_ = 0; + KOKKOS_INLINE_FUNCTION + Random_XorShift64_Pool() { num_states_ = 0; } + Random_XorShift64_Pool(uint64_t seed) { + num_states_ = 0; #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - init(seed,DeviceType::max_hardware_threads()); + init(seed, DeviceType::max_hardware_threads()); #else - init(seed,DeviceType::impl_max_hardware_threads()); + init(seed, DeviceType::impl_max_hardware_threads()); #endif - } + } - KOKKOS_INLINE_FUNCTION - Random_XorShift64_Pool(const Random_XorShift64_Pool& src): - locks_(src.locks_), - state_(src.state_), - num_states_(src.num_states_) - {} + KOKKOS_INLINE_FUNCTION + Random_XorShift64_Pool(const Random_XorShift64_Pool& src) + : locks_(src.locks_), state_(src.state_), num_states_(src.num_states_) {} - KOKKOS_INLINE_FUNCTION - Random_XorShift64_Pool operator = (const Random_XorShift64_Pool& src) { - locks_ = src.locks_; - state_ = src.state_; - num_states_ = src.num_states_; - return *this; - } + KOKKOS_INLINE_FUNCTION + Random_XorShift64_Pool operator=(const Random_XorShift64_Pool& src) { + locks_ = src.locks_; + state_ = src.state_; + num_states_ = src.num_states_; + return *this; + } - void init(uint64_t seed, int num_states) { - if(seed==0) - seed = uint64_t(1318319); - - num_states_ = num_states; - - locks_ = lock_type("Kokkos::Random_XorShift64::locks",num_states_); - state_ = state_data_type("Kokkos::Random_XorShift64::state",num_states_); - - typename state_data_type::HostMirror h_state = create_mirror_view(state_); - typename lock_type::HostMirror h_lock = create_mirror_view(locks_); - - // Execute on the HostMirror's default execution space. - Random_XorShift64 gen(seed,0); - for(int i = 0; i < 17; i++) - gen.rand(); - for(int i = 0; i < num_states_; i++) { - int n1 = gen.rand(); - int n2 = gen.rand(); - int n3 = gen.rand(); - int n4 = gen.rand(); - h_state(i) = (((static_cast(n1)) & 0xffff)<<00) | - (((static_cast(n2)) & 0xffff)<<16) | - (((static_cast(n3)) & 0xffff)<<32) | - (((static_cast(n4)) & 0xffff)<<48); - h_lock(i) = 0; - } - deep_copy(state_,h_state); - deep_copy(locks_,h_lock); - } + void init(uint64_t seed, int num_states) { + if (seed == 0) seed = uint64_t(1318319); + + num_states_ = num_states; + + locks_ = lock_type("Kokkos::Random_XorShift64::locks", num_states_); + state_ = state_data_type("Kokkos::Random_XorShift64::state", num_states_); + + typename state_data_type::HostMirror h_state = create_mirror_view(state_); + typename lock_type::HostMirror h_lock = create_mirror_view(locks_); + + // Execute on the HostMirror's default execution space. + Random_XorShift64 + gen(seed, 0); + for (int i = 0; i < 17; i++) gen.rand(); + for (int i = 0; i < num_states_; i++) { + int n1 = gen.rand(); + int n2 = gen.rand(); + int n3 = gen.rand(); + int n4 = gen.rand(); + h_state(i) = (((static_cast(n1)) & 0xffff) << 00) | + (((static_cast(n2)) & 0xffff) << 16) | + (((static_cast(n3)) & 0xffff) << 32) | + (((static_cast(n4)) & 0xffff) << 48); + h_lock(i) = 0; + } + deep_copy(state_, h_state); + deep_copy(locks_, h_lock); + } - KOKKOS_INLINE_FUNCTION - Random_XorShift64 get_state() const { + KOKKOS_INLINE_FUNCTION + Random_XorShift64 get_state() const { #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - const int i = DeviceType::hardware_thread_id();; + const int i = DeviceType::hardware_thread_id(); + ; #else - const int i = DeviceType::impl_hardware_thread_id();; + const int i = DeviceType::impl_hardware_thread_id(); + ; #endif - return Random_XorShift64(state_(i),i); - } - - // NOTE: state_idx MUST be unique and less than num_states - KOKKOS_INLINE_FUNCTION - Random_XorShift64 get_state(const int state_idx) const { - return Random_XorShift64(state_(state_idx),state_idx); - } - - KOKKOS_INLINE_FUNCTION - void free_state(const Random_XorShift64& state) const { - state_(state.state_idx_) = state.state_; - } - }; + return Random_XorShift64(state_(i), i); + } + // NOTE: state_idx MUST be unique and less than num_states + KOKKOS_INLINE_FUNCTION + Random_XorShift64 get_state(const int state_idx) const { + return Random_XorShift64(state_(state_idx), state_idx); + } - template - class Random_XorShift1024_Pool; + KOKKOS_INLINE_FUNCTION + void free_state(const Random_XorShift64& state) const { + state_(state.state_idx_) = state.state_; + } +}; - template - class Random_XorShift1024 { - private: - int p_; - const int state_idx_; - uint64_t state_[16]; - friend class Random_XorShift1024_Pool; - public: +template +class Random_XorShift1024_Pool; - typedef Random_XorShift1024_Pool pool_type; - typedef DeviceType device_type; +template +class Random_XorShift1024 { + private: + int p_; + const int state_idx_; + uint64_t state_[16]; + friend class Random_XorShift1024_Pool; - enum {MAX_URAND = 0xffffffffU}; - enum {MAX_URAND64 = 0xffffffffffffffffULL-1}; - enum {MAX_RAND = static_cast(0xffffffffU/2)}; - enum {MAX_RAND64 = static_cast(0xffffffffffffffffULL/2-1)}; + public: + typedef Random_XorShift1024_Pool pool_type; + typedef DeviceType device_type; - KOKKOS_INLINE_FUNCTION - Random_XorShift1024 (const typename pool_type::state_data_type& state, int p, int state_idx = 0): - p_(p),state_idx_(state_idx){ - for(int i=0 ; i<16; i++) - state_[i] = state(state_idx,i); - } + enum { MAX_URAND = 0xffffffffU }; + enum { MAX_URAND64 = 0xffffffffffffffffULL - 1 }; + enum { MAX_RAND = static_cast(0xffffffffU / 2) }; + enum { MAX_RAND64 = static_cast(0xffffffffffffffffULL / 2 - 1) }; - KOKKOS_INLINE_FUNCTION - uint32_t urand() { - uint64_t state_0 = state_[ p_ ]; - uint64_t state_1 = state_[ p_ = ( p_ + 1 ) & 15 ]; - state_1 ^= state_1 << 31; - state_1 ^= state_1 >> 11; - state_0 ^= state_0 >> 30; - uint64_t tmp = ( state_[ p_ ] = state_0 ^ state_1 ) * 1181783497276652981ULL; - tmp = tmp>>16; - return static_cast(tmp&MAX_URAND); - } + KOKKOS_INLINE_FUNCTION + Random_XorShift1024(const typename pool_type::state_data_type& state, int p, + int state_idx = 0) + : p_(p), state_idx_(state_idx) { + for (int i = 0; i < 16; i++) state_[i] = state(state_idx, i); + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64() { - uint64_t state_0 = state_[ p_ ]; - uint64_t state_1 = state_[ p_ = ( p_ + 1 ) & 15 ]; - state_1 ^= state_1 << 31; - state_1 ^= state_1 >> 11; - state_0 ^= state_0 >> 30; - return (( state_[ p_ ] = state_0 ^ state_1 ) * 1181783497276652981LL) - 1; - } + KOKKOS_INLINE_FUNCTION + uint32_t urand() { + uint64_t state_0 = state_[p_]; + uint64_t state_1 = state_[p_ = (p_ + 1) & 15]; + state_1 ^= state_1 << 31; + state_1 ^= state_1 >> 11; + state_0 ^= state_0 >> 30; + uint64_t tmp = (state_[p_] = state_0 ^ state_1) * 1181783497276652981ULL; + tmp = tmp >> 16; + return static_cast(tmp & MAX_URAND); + } - KOKKOS_INLINE_FUNCTION - uint32_t urand(const uint32_t& range) { - const uint32_t max_val = (MAX_URAND/range)*range; - uint32_t tmp = urand(); - while(tmp>=max_val) - tmp = urand(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64() { + uint64_t state_0 = state_[p_]; + uint64_t state_1 = state_[p_ = (p_ + 1) & 15]; + state_1 ^= state_1 << 31; + state_1 ^= state_1 >> 11; + state_0 ^= state_0 >> 30; + return ((state_[p_] = state_0 ^ state_1) * 1181783497276652981LL) - 1; + } - KOKKOS_INLINE_FUNCTION - uint32_t urand(const uint32_t& start, const uint32_t& end ) { - return urand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + uint32_t urand(const uint32_t& range) { + const uint32_t max_val = (MAX_URAND / range) * range; + uint32_t tmp = urand(); + while (tmp >= max_val) tmp = urand(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64(const uint64_t& range) { - const uint64_t max_val = (MAX_URAND64/range)*range; - uint64_t tmp = urand64(); - while(tmp>=max_val) - tmp = urand64(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + uint32_t urand(const uint32_t& start, const uint32_t& end) { + return urand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64(const uint64_t& start, const uint64_t& end ) { - return urand64(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64(const uint64_t& range) { + const uint64_t max_val = (MAX_URAND64 / range) * range; + uint64_t tmp = urand64(); + while (tmp >= max_val) tmp = urand64(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - int rand() { - return static_cast(urand()/2); - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64(const uint64_t& start, const uint64_t& end) { + return urand64(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - int rand(const int& range) { - const int max_val = (MAX_RAND/range)*range; - int tmp = rand(); - while(tmp>=max_val) - tmp = rand(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + int rand() { return static_cast(urand() / 2); } - KOKKOS_INLINE_FUNCTION - int rand(const int& start, const int& end ) { - return rand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + int rand(const int& range) { + const int max_val = (MAX_RAND / range) * range; + int tmp = rand(); + while (tmp >= max_val) tmp = rand(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - int64_t rand64() { - return static_cast(urand64()/2); - } + KOKKOS_INLINE_FUNCTION + int rand(const int& start, const int& end) { + return rand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - int64_t rand64(const int64_t& range) { - const int64_t max_val = (MAX_RAND64/range)*range; - int64_t tmp = rand64(); - while(tmp>=max_val) - tmp = rand64(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + int64_t rand64() { return static_cast(urand64() / 2); } - KOKKOS_INLINE_FUNCTION - int64_t rand64(const int64_t& start, const int64_t& end ) { - return rand64(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + int64_t rand64(const int64_t& range) { + const int64_t max_val = (MAX_RAND64 / range) * range; + int64_t tmp = rand64(); + while (tmp >= max_val) tmp = rand64(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - float frand() { - return 1.0f * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + int64_t rand64(const int64_t& start, const int64_t& end) { + return rand64(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - float frand(const float& range) { - return range * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + float frand() { return 1.0f * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - float frand(const float& start, const float& end ) { - return frand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + float frand(const float& range) { return range * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - double drand() { - return 1.0 * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + float frand(const float& start, const float& end) { + return frand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - double drand(const double& range) { - return range * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + double drand() { return 1.0 * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - double drand(const double& start, const double& end ) { - return frand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + double drand(const double& range) { return range * urand64() / MAX_URAND64; } - //Marsaglia polar method for drawing a standard normal distributed random number - KOKKOS_INLINE_FUNCTION - double normal() { - double S = 2.0; - double U; - while(S>=1.0) { - U = 2.0*drand() - 1.0; - const double V = 2.0*drand() - 1.0; - S = U*U+V*V; - } - return U*std::sqrt(-2.0*log(S)/S); - } + KOKKOS_INLINE_FUNCTION + double drand(const double& start, const double& end) { + return frand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - double normal(const double& mean, const double& std_dev=1.0) { - return mean + normal()*std_dev; - } - }; + // Marsaglia polar method for drawing a standard normal distributed random + // number + KOKKOS_INLINE_FUNCTION + double normal() { + double S = 2.0; + double U; + while (S >= 1.0) { + U = 2.0 * drand() - 1.0; + const double V = 2.0 * drand() - 1.0; + S = U * U + V * V; + } + return U * std::sqrt(-2.0 * log(S) / S); + } + KOKKOS_INLINE_FUNCTION + double normal(const double& mean, const double& std_dev = 1.0) { + return mean + normal() * std_dev; + } +}; - template - class Random_XorShift1024_Pool { - private: - typedef View int_view_type; - typedef View state_data_type; +template +class Random_XorShift1024_Pool { + private: + typedef View int_view_type; + typedef View state_data_type; - int_view_type locks_; - state_data_type state_; - int_view_type p_; - int num_states_; - friend class Random_XorShift1024; + int_view_type locks_; + state_data_type state_; + int_view_type p_; + int num_states_; + friend class Random_XorShift1024; - public: - typedef Random_XorShift1024 generator_type; + public: + typedef Random_XorShift1024 generator_type; - typedef DeviceType device_type; + typedef DeviceType device_type; - KOKKOS_INLINE_FUNCTION - Random_XorShift1024_Pool() { - num_states_ = 0; - } + KOKKOS_INLINE_FUNCTION + Random_XorShift1024_Pool() { num_states_ = 0; } - inline - Random_XorShift1024_Pool(uint64_t seed){ - num_states_ = 0; + inline Random_XorShift1024_Pool(uint64_t seed) { + num_states_ = 0; #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - init(seed,DeviceType::max_hardware_threads()); + init(seed, DeviceType::max_hardware_threads()); #else - init(seed,DeviceType::impl_max_hardware_threads()); + init(seed, DeviceType::impl_max_hardware_threads()); #endif - } + } - KOKKOS_INLINE_FUNCTION - Random_XorShift1024_Pool(const Random_XorShift1024_Pool& src): - locks_(src.locks_), - state_(src.state_), - p_(src.p_), - num_states_(src.num_states_) - {} + KOKKOS_INLINE_FUNCTION + Random_XorShift1024_Pool(const Random_XorShift1024_Pool& src) + : locks_(src.locks_), + state_(src.state_), + p_(src.p_), + num_states_(src.num_states_) {} - KOKKOS_INLINE_FUNCTION - Random_XorShift1024_Pool operator = (const Random_XorShift1024_Pool& src) { - locks_ = src.locks_; - state_ = src.state_; - p_ = src.p_; - num_states_ = src.num_states_; - return *this; - } + KOKKOS_INLINE_FUNCTION + Random_XorShift1024_Pool operator=(const Random_XorShift1024_Pool& src) { + locks_ = src.locks_; + state_ = src.state_; + p_ = src.p_; + num_states_ = src.num_states_; + return *this; + } - inline - void init(uint64_t seed, int num_states) { - if(seed==0) - seed = uint64_t(1318319); - num_states_ = num_states; - locks_ = int_view_type("Kokkos::Random_XorShift1024::locks",num_states_); - state_ = state_data_type("Kokkos::Random_XorShift1024::state",num_states_); - p_ = int_view_type("Kokkos::Random_XorShift1024::p",num_states_); - - typename state_data_type::HostMirror h_state = create_mirror_view(state_); - typename int_view_type::HostMirror h_lock = create_mirror_view(locks_); - typename int_view_type::HostMirror h_p = create_mirror_view(p_); - - // Execute on the HostMirror's default execution space. - Random_XorShift64 gen(seed,0); - for(int i = 0; i < 17; i++) - gen.rand(); - for(int i = 0; i < num_states_; i++) { - for(int j = 0; j < 16 ; j++) { - int n1 = gen.rand(); - int n2 = gen.rand(); - int n3 = gen.rand(); - int n4 = gen.rand(); - h_state(i,j) = (((static_cast(n1)) & 0xffff)<<00) | - (((static_cast(n2)) & 0xffff)<<16) | - (((static_cast(n3)) & 0xffff)<<32) | - (((static_cast(n4)) & 0xffff)<<48); - } - h_p(i) = 0; - h_lock(i) = 0; + inline void init(uint64_t seed, int num_states) { + if (seed == 0) seed = uint64_t(1318319); + num_states_ = num_states; + locks_ = int_view_type("Kokkos::Random_XorShift1024::locks", num_states_); + state_ = state_data_type("Kokkos::Random_XorShift1024::state", num_states_); + p_ = int_view_type("Kokkos::Random_XorShift1024::p", num_states_); + + typename state_data_type::HostMirror h_state = create_mirror_view(state_); + typename int_view_type::HostMirror h_lock = create_mirror_view(locks_); + typename int_view_type::HostMirror h_p = create_mirror_view(p_); + + // Execute on the HostMirror's default execution space. + Random_XorShift64 + gen(seed, 0); + for (int i = 0; i < 17; i++) gen.rand(); + for (int i = 0; i < num_states_; i++) { + for (int j = 0; j < 16; j++) { + int n1 = gen.rand(); + int n2 = gen.rand(); + int n3 = gen.rand(); + int n4 = gen.rand(); + h_state(i, j) = (((static_cast(n1)) & 0xffff) << 00) | + (((static_cast(n2)) & 0xffff) << 16) | + (((static_cast(n3)) & 0xffff) << 32) | + (((static_cast(n4)) & 0xffff) << 48); } - deep_copy(state_,h_state); - deep_copy(locks_,h_lock); + h_p(i) = 0; + h_lock(i) = 0; } + deep_copy(state_, h_state); + deep_copy(locks_, h_lock); + } - KOKKOS_INLINE_FUNCTION - Random_XorShift1024 get_state() const { + KOKKOS_INLINE_FUNCTION + Random_XorShift1024 get_state() const { #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - const int i = DeviceType::hardware_thread_id(); + const int i = DeviceType::hardware_thread_id(); #else - const int i = DeviceType::impl_hardware_thread_id(); + const int i = DeviceType::impl_hardware_thread_id(); #endif - return Random_XorShift1024(state_,p_(i),i); - }; + return Random_XorShift1024(state_, p_(i), i); + }; - // NOTE: state_idx MUST be unique and less than num_states - KOKKOS_INLINE_FUNCTION - Random_XorShift1024 get_state(const int state_idx) const { - return Random_XorShift1024(state_,p_(state_idx),state_idx); - } + // NOTE: state_idx MUST be unique and less than num_states + KOKKOS_INLINE_FUNCTION + Random_XorShift1024 get_state(const int state_idx) const { + return Random_XorShift1024(state_, p_(state_idx), state_idx); + } - KOKKOS_INLINE_FUNCTION - void free_state(const Random_XorShift1024& state) const { - for(int i = 0; i<16; i++) - state_(state.state_idx_,i) = state.state_[i]; - p_(state.state_idx_) = state.p_; - } - }; + KOKKOS_INLINE_FUNCTION + void free_state(const Random_XorShift1024& state) const { + for (int i = 0; i < 16; i++) state_(state.state_idx_, i) = state.state_[i]; + p_(state.state_idx_) = state.p_; + } +}; #if defined(KOKKOS_ENABLE_CUDA) && defined(__CUDACC__) - template<> - class Random_XorShift1024 { - private: - int p_; - const int state_idx_; - uint64_t* state_; - const int stride_; - friend class Random_XorShift1024_Pool; - public: +template <> +class Random_XorShift1024 { + private: + int p_; + const int state_idx_; + uint64_t* state_; + const int stride_; + friend class Random_XorShift1024_Pool; - typedef Kokkos::Cuda device_type; - typedef Random_XorShift1024_Pool pool_type; + public: + typedef Kokkos::Cuda device_type; + typedef Random_XorShift1024_Pool pool_type; - enum {MAX_URAND = 0xffffffffU}; - enum {MAX_URAND64 = 0xffffffffffffffffULL-1}; - enum {MAX_RAND = static_cast(0xffffffffU/2)}; - enum {MAX_RAND64 = static_cast(0xffffffffffffffffULL/2-1)}; + enum { MAX_URAND = 0xffffffffU }; + enum { MAX_URAND64 = 0xffffffffffffffffULL - 1 }; + enum { MAX_RAND = static_cast(0xffffffffU / 2) }; + enum { MAX_RAND64 = static_cast(0xffffffffffffffffULL / 2 - 1) }; - KOKKOS_INLINE_FUNCTION - Random_XorShift1024 (const typename pool_type::state_data_type& state, int p, int state_idx = 0): - p_(p),state_idx_(state_idx),state_(&state(state_idx,0)),stride_(state.stride_1()){ - } + KOKKOS_INLINE_FUNCTION + Random_XorShift1024(const typename pool_type::state_data_type& state, int p, + int state_idx = 0) + : p_(p), + state_idx_(state_idx), + state_(&state(state_idx, 0)), + stride_(state.stride_1()) {} - KOKKOS_INLINE_FUNCTION - uint32_t urand() { - uint64_t state_0 = state_[ p_ * stride_ ]; - uint64_t state_1 = state_[ (p_ = ( p_ + 1 ) & 15) * stride_ ]; - state_1 ^= state_1 << 31; - state_1 ^= state_1 >> 11; - state_0 ^= state_0 >> 30; - uint64_t tmp = ( state_[ p_ * stride_ ] = state_0 ^ state_1 ) * 1181783497276652981ULL; - tmp = tmp>>16; - return static_cast(tmp&MAX_URAND); - } + KOKKOS_INLINE_FUNCTION + uint32_t urand() { + uint64_t state_0 = state_[p_ * stride_]; + uint64_t state_1 = state_[(p_ = (p_ + 1) & 15) * stride_]; + state_1 ^= state_1 << 31; + state_1 ^= state_1 >> 11; + state_0 ^= state_0 >> 30; + uint64_t tmp = + (state_[p_ * stride_] = state_0 ^ state_1) * 1181783497276652981ULL; + tmp = tmp >> 16; + return static_cast(tmp & MAX_URAND); + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64() { - uint64_t state_0 = state_[ p_ * stride_ ]; - uint64_t state_1 = state_[ (p_ = ( p_ + 1 ) & 15) * stride_ ]; - state_1 ^= state_1 << 31; - state_1 ^= state_1 >> 11; - state_0 ^= state_0 >> 30; - return (( state_[ p_ * stride_ ] = state_0 ^ state_1 ) * 1181783497276652981LL) - 1; - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64() { + uint64_t state_0 = state_[p_ * stride_]; + uint64_t state_1 = state_[(p_ = (p_ + 1) & 15) * stride_]; + state_1 ^= state_1 << 31; + state_1 ^= state_1 >> 11; + state_0 ^= state_0 >> 30; + return ((state_[p_ * stride_] = state_0 ^ state_1) * + 1181783497276652981LL) - + 1; + } - KOKKOS_INLINE_FUNCTION - uint32_t urand(const uint32_t& range) { - const uint32_t max_val = (MAX_URAND/range)*range; - uint32_t tmp = urand(); - while(tmp>=max_val) - urand(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + uint32_t urand(const uint32_t& range) { + const uint32_t max_val = (MAX_URAND / range) * range; + uint32_t tmp = urand(); + while (tmp >= max_val) urand(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - uint32_t urand(const uint32_t& start, const uint32_t& end ) { - return urand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + uint32_t urand(const uint32_t& start, const uint32_t& end) { + return urand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64(const uint64_t& range) { - const uint64_t max_val = (MAX_URAND64/range)*range; - uint64_t tmp = urand64(); - while(tmp>=max_val) - urand64(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64(const uint64_t& range) { + const uint64_t max_val = (MAX_URAND64 / range) * range; + uint64_t tmp = urand64(); + while (tmp >= max_val) urand64(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64(const uint64_t& start, const uint64_t& end ) { - return urand64(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64(const uint64_t& start, const uint64_t& end) { + return urand64(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - int rand() { - return static_cast(urand()/2); - } + KOKKOS_INLINE_FUNCTION + int rand() { return static_cast(urand() / 2); } - KOKKOS_INLINE_FUNCTION - int rand(const int& range) { - const int max_val = (MAX_RAND/range)*range; - int tmp = rand(); - while(tmp>=max_val) - rand(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + int rand(const int& range) { + const int max_val = (MAX_RAND / range) * range; + int tmp = rand(); + while (tmp >= max_val) rand(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - int rand(const int& start, const int& end ) { - return rand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + int rand(const int& start, const int& end) { + return rand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - int64_t rand64() { - return static_cast(urand64()/2); - } + KOKKOS_INLINE_FUNCTION + int64_t rand64() { return static_cast(urand64() / 2); } - KOKKOS_INLINE_FUNCTION - int64_t rand64(const int64_t& range) { - const int64_t max_val = (MAX_RAND64/range)*range; - int64_t tmp = rand64(); - while(tmp>=max_val) - rand64(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + int64_t rand64(const int64_t& range) { + const int64_t max_val = (MAX_RAND64 / range) * range; + int64_t tmp = rand64(); + while (tmp >= max_val) rand64(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - int64_t rand64(const int64_t& start, const int64_t& end ) { - return rand64(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + int64_t rand64(const int64_t& start, const int64_t& end) { + return rand64(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - float frand() { - return 1.0f * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + float frand() { return 1.0f * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - float frand(const float& range) { - return range * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + float frand(const float& range) { return range * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - float frand(const float& start, const float& end ) { - return frand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + float frand(const float& start, const float& end) { + return frand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - double drand() { - return 1.0 * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + double drand() { return 1.0 * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - double drand(const double& range) { - return range * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + double drand(const double& range) { return range * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - double drand(const double& start, const double& end ) { - return frand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + double drand(const double& start, const double& end) { + return frand(end - start) + start; + } - //Marsaglia polar method for drawing a standard normal distributed random number - KOKKOS_INLINE_FUNCTION - double normal() { - double S = 2.0; - double U; - while(S>=1.0) { - U = 2.0*drand() - 1.0; - const double V = 2.0*drand() - 1.0; - S = U*U+V*V; - } - return U*std::sqrt(-2.0*log(S)/S); - } + // Marsaglia polar method for drawing a standard normal distributed random + // number + KOKKOS_INLINE_FUNCTION + double normal() { + double S = 2.0; + double U; + while (S >= 1.0) { + U = 2.0 * drand() - 1.0; + const double V = 2.0 * drand() - 1.0; + S = U * U + V * V; + } + return U * std::sqrt(-2.0 * log(S) / S); + } - KOKKOS_INLINE_FUNCTION - double normal(const double& mean, const double& std_dev=1.0) { - return mean + normal()*std_dev; - } - }; + KOKKOS_INLINE_FUNCTION + double normal(const double& mean, const double& std_dev = 1.0) { + return mean + normal() * std_dev; + } +}; -template<> -inline -Random_XorShift64_Pool::Random_XorShift64_Pool(uint64_t seed) { +template <> +inline Random_XorShift64_Pool::Random_XorShift64_Pool( + uint64_t seed) { num_states_ = 0; - init(seed,4*32768); + init(seed, 4 * 32768); } -template<> -KOKKOS_INLINE_FUNCTION -Random_XorShift64 Random_XorShift64_Pool::get_state() const { +template <> +KOKKOS_INLINE_FUNCTION Random_XorShift64 +Random_XorShift64_Pool::get_state() const { #ifdef __CUDA_ARCH__ - const int i_offset = (threadIdx.x*blockDim.y + threadIdx.y)*blockDim.z+threadIdx.z; - int i = (((blockIdx.x*gridDim.y+blockIdx.y)*gridDim.z + blockIdx.z) * - blockDim.x*blockDim.y*blockDim.z + i_offset)%num_states_; - while(Kokkos::atomic_compare_exchange(&locks_(i),0,1)) { - i+=blockDim.x*blockDim.y*blockDim.z; - if(i>=num_states_) {i = i_offset;} + const int i_offset = + (threadIdx.x * blockDim.y + threadIdx.y) * blockDim.z + threadIdx.z; + int i = (((blockIdx.x * gridDim.y + blockIdx.y) * gridDim.z + blockIdx.z) * + blockDim.x * blockDim.y * blockDim.z + + i_offset) % + num_states_; + while (Kokkos::atomic_compare_exchange(&locks_(i), 0, 1)) { + i += blockDim.x * blockDim.y * blockDim.z; + if (i >= num_states_) { + i = i_offset; + } } - return Random_XorShift64(state_(i),i); + return Random_XorShift64(state_(i), i); #else - return Random_XorShift64(state_(0),0); + return Random_XorShift64(state_(0), 0); #endif } -template<> -KOKKOS_INLINE_FUNCTION -void Random_XorShift64_Pool::free_state(const Random_XorShift64 &state) const { +template <> +KOKKOS_INLINE_FUNCTION void Random_XorShift64_Pool::free_state( + const Random_XorShift64& state) const { state_(state.state_idx_) = state.state_; #ifdef __CUDA_ARCH__ locks_(state.state_idx_) = 0; @@ -1249,24 +1211,28 @@ void Random_XorShift64_Pool::free_state(const Random_XorShift64 -inline -Random_XorShift1024_Pool::Random_XorShift1024_Pool(uint64_t seed) { +template <> +inline Random_XorShift1024_Pool::Random_XorShift1024_Pool( + uint64_t seed) { num_states_ = 0; - init(seed,4*32768); + init(seed, 4 * 32768); } -template<> -KOKKOS_INLINE_FUNCTION -Random_XorShift1024 Random_XorShift1024_Pool::get_state() const { +template <> +KOKKOS_INLINE_FUNCTION Random_XorShift1024 +Random_XorShift1024_Pool::get_state() const { #ifdef __CUDA_ARCH__ - const int i_offset = (threadIdx.x*blockDim.y + threadIdx.y)*blockDim.z+threadIdx.z; - int i = (((blockIdx.x*gridDim.y+blockIdx.y)*gridDim.z + blockIdx.z) * - blockDim.x*blockDim.y*blockDim.z + i_offset)%num_states_; - while(Kokkos::atomic_compare_exchange(&locks_(i),0,1)) { - i+=blockDim.x*blockDim.y*blockDim.z; - if(i>=num_states_) {i = i_offset;} + const int i_offset = + (threadIdx.x * blockDim.y + threadIdx.y) * blockDim.z + threadIdx.z; + int i = (((blockIdx.x * gridDim.y + blockIdx.y) * gridDim.z + blockIdx.z) * + blockDim.x * blockDim.y * blockDim.z + + i_offset) % + num_states_; + while (Kokkos::atomic_compare_exchange(&locks_(i), 0, 1)) { + i += blockDim.x * blockDim.y * blockDim.z; + if (i >= num_states_) { + i = i_offset; + } } return Random_XorShift1024(state_, p_(i), i); @@ -1275,210 +1241,205 @@ Random_XorShift1024 Random_XorShift1024_Pool::get_st #endif } -template<> -KOKKOS_INLINE_FUNCTION -void Random_XorShift1024_Pool::free_state(const Random_XorShift1024 &state) const { - for(int i=0; i<16; i++) - state_(state.state_idx_,i) = state.state_[i]; +template <> +KOKKOS_INLINE_FUNCTION void Random_XorShift1024_Pool::free_state( + const Random_XorShift1024& state) const { + for (int i = 0; i < 16; i++) state_(state.state_idx_, i) = state.state_[i]; #ifdef __CUDA_ARCH__ locks_(state.state_idx_) = 0; return; #endif } - #endif -#if defined(KOKKOS_ENABLE_ROCM) +#if defined(KOKKOS_ENABLE_ROCM) - template<> - class Random_XorShift1024 { - private: - int p_; - const int state_idx_; - uint64_t* state_; - const int stride_; - friend class Random_XorShift1024_Pool; - public: +template <> +class Random_XorShift1024 { + private: + int p_; + const int state_idx_; + uint64_t* state_; + const int stride_; + friend class Random_XorShift1024_Pool; - typedef Kokkos::Experimental::ROCm device_type; - typedef Random_XorShift1024_Pool pool_type; + public: + typedef Kokkos::Experimental::ROCm device_type; + typedef Random_XorShift1024_Pool pool_type; - enum {MAX_URAND = 0xffffffffU}; - enum {MAX_URAND64 = 0xffffffffffffffffULL-1}; - enum {MAX_RAND = static_cast(0xffffffffU/2)}; - enum {MAX_RAND64 = static_cast(0xffffffffffffffffULL/2-1)}; + enum { MAX_URAND = 0xffffffffU }; + enum { MAX_URAND64 = 0xffffffffffffffffULL - 1 }; + enum { MAX_RAND = static_cast(0xffffffffU / 2) }; + enum { MAX_RAND64 = static_cast(0xffffffffffffffffULL / 2 - 1) }; - KOKKOS_INLINE_FUNCTION - Random_XorShift1024 (const typename pool_type::state_data_type& state, int p, int state_idx = 0): - p_(p),state_idx_(state_idx),state_(&state(state_idx,0)),stride_(state.stride_1()){ - } + KOKKOS_INLINE_FUNCTION + Random_XorShift1024(const typename pool_type::state_data_type& state, int p, + int state_idx = 0) + : p_(p), + state_idx_(state_idx), + state_(&state(state_idx, 0)), + stride_(state.stride_1()) {} - KOKKOS_INLINE_FUNCTION - uint32_t urand() { - uint64_t state_0 = state_[ p_ * stride_ ]; - uint64_t state_1 = state_[ (p_ = ( p_ + 1 ) & 15) * stride_ ]; - state_1 ^= state_1 << 31; - state_1 ^= state_1 >> 11; - state_0 ^= state_0 >> 30; - uint64_t tmp = ( state_[ p_ * stride_ ] = state_0 ^ state_1 ) * 1181783497276652981ULL; - tmp = tmp>>16; - return static_cast(tmp&MAX_URAND); - } + KOKKOS_INLINE_FUNCTION + uint32_t urand() { + uint64_t state_0 = state_[p_ * stride_]; + uint64_t state_1 = state_[(p_ = (p_ + 1) & 15) * stride_]; + state_1 ^= state_1 << 31; + state_1 ^= state_1 >> 11; + state_0 ^= state_0 >> 30; + uint64_t tmp = + (state_[p_ * stride_] = state_0 ^ state_1) * 1181783497276652981ULL; + tmp = tmp >> 16; + return static_cast(tmp & MAX_URAND); + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64() { - uint64_t state_0 = state_[ p_ * stride_ ]; - uint64_t state_1 = state_[ (p_ = ( p_ + 1 ) & 15) * stride_ ]; - state_1 ^= state_1 << 31; - state_1 ^= state_1 >> 11; - state_0 ^= state_0 >> 30; - return (( state_[ p_ * stride_ ] = state_0 ^ state_1 ) * 1181783497276652981LL) - 1; - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64() { + uint64_t state_0 = state_[p_ * stride_]; + uint64_t state_1 = state_[(p_ = (p_ + 1) & 15) * stride_]; + state_1 ^= state_1 << 31; + state_1 ^= state_1 >> 11; + state_0 ^= state_0 >> 30; + return ((state_[p_ * stride_] = state_0 ^ state_1) * + 1181783497276652981LL) - + 1; + } - KOKKOS_INLINE_FUNCTION - uint32_t urand(const uint32_t& range) { - const uint32_t max_val = (MAX_URAND/range)*range; - uint32_t tmp = urand(); - while(tmp>=max_val) - urand(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + uint32_t urand(const uint32_t& range) { + const uint32_t max_val = (MAX_URAND / range) * range; + uint32_t tmp = urand(); + while (tmp >= max_val) urand(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - uint32_t urand(const uint32_t& start, const uint32_t& end ) { - return urand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + uint32_t urand(const uint32_t& start, const uint32_t& end) { + return urand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64(const uint64_t& range) { - const uint64_t max_val = (MAX_URAND64/range)*range; - uint64_t tmp = urand64(); - while(tmp>=max_val) - urand64(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64(const uint64_t& range) { + const uint64_t max_val = (MAX_URAND64 / range) * range; + uint64_t tmp = urand64(); + while (tmp >= max_val) urand64(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64(const uint64_t& start, const uint64_t& end ) { - return urand64(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64(const uint64_t& start, const uint64_t& end) { + return urand64(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - int rand() { - return static_cast(urand()/2); - } + KOKKOS_INLINE_FUNCTION + int rand() { return static_cast(urand() / 2); } - KOKKOS_INLINE_FUNCTION - int rand(const int& range) { - const int max_val = (MAX_RAND/range)*range; - int tmp = rand(); - while(tmp>=max_val) - rand(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + int rand(const int& range) { + const int max_val = (MAX_RAND / range) * range; + int tmp = rand(); + while (tmp >= max_val) rand(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - int rand(const int& start, const int& end ) { - return rand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + int rand(const int& start, const int& end) { + return rand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - int64_t rand64() { - return static_cast(urand64()/2); - } + KOKKOS_INLINE_FUNCTION + int64_t rand64() { return static_cast(urand64() / 2); } - KOKKOS_INLINE_FUNCTION - int64_t rand64(const int64_t& range) { - const int64_t max_val = (MAX_RAND64/range)*range; - int64_t tmp = rand64(); - while(tmp>=max_val) - rand64(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + int64_t rand64(const int64_t& range) { + const int64_t max_val = (MAX_RAND64 / range) * range; + int64_t tmp = rand64(); + while (tmp >= max_val) rand64(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - int64_t rand64(const int64_t& start, const int64_t& end ) { - return rand64(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + int64_t rand64(const int64_t& start, const int64_t& end) { + return rand64(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - float frand() { - return 1.0f * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + float frand() { return 1.0f * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - float frand(const float& range) { - return range * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + float frand(const float& range) { return range * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - float frand(const float& start, const float& end ) { - return frand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + float frand(const float& start, const float& end) { + return frand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - double drand() { - return 1.0 * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + double drand() { return 1.0 * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - double drand(const double& range) { - return range * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + double drand(const double& range) { return range * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - double drand(const double& start, const double& end ) { - return frand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + double drand(const double& start, const double& end) { + return frand(end - start) + start; + } - //Marsaglia polar method for drawing a standard normal distributed random number - KOKKOS_INLINE_FUNCTION - double normal() { - double S = 2.0; - double U; - while(S>=1.0) { - U = 2.0*drand() - 1.0; - const double V = 2.0*drand() - 1.0; - S = U*U+V*V; - } - return U*std::sqrt(-2.0*log(S)/S); - } + // Marsaglia polar method for drawing a standard normal distributed random + // number + KOKKOS_INLINE_FUNCTION + double normal() { + double S = 2.0; + double U; + while (S >= 1.0) { + U = 2.0 * drand() - 1.0; + const double V = 2.0 * drand() - 1.0; + S = U * U + V * V; + } + return U * std::sqrt(-2.0 * log(S) / S); + } - KOKKOS_INLINE_FUNCTION - double normal(const double& mean, const double& std_dev=1.0) { - return mean + normal()*std_dev; - } - }; + KOKKOS_INLINE_FUNCTION + double normal(const double& mean, const double& std_dev = 1.0) { + return mean + normal() * std_dev; + } +}; -template<> -inline -Random_XorShift64_Pool::Random_XorShift64_Pool(uint64_t seed) { +template <> +inline Random_XorShift64_Pool< + Kokkos::Experimental::ROCm>::Random_XorShift64_Pool(uint64_t seed) { num_states_ = 0; - init(seed,4*32768); + init(seed, 4 * 32768); } -template<> -KOKKOS_INLINE_FUNCTION -Random_XorShift64 Random_XorShift64_Pool::get_state() const { +template <> +KOKKOS_INLINE_FUNCTION Random_XorShift64 +Random_XorShift64_Pool::get_state() const { #ifdef __HCC_ACCELERATOR__ - const int i_offset = (threadIdx_x*blockDim_y + threadIdx_y)*blockDim_z+threadIdx_z; - int i = (((blockIdx_x*gridDim_y+blockIdx_y)*gridDim_z + blockIdx_z) * - blockDim_x*blockDim_y*blockDim_z + i_offset)%num_states_; - while(Kokkos::atomic_compare_exchange(&locks_(i),0,1)) { - i+=blockDim_x*blockDim_y*blockDim_z; - if(i>=num_states_) {i = i_offset;} + const int i_offset = + (threadIdx_x * blockDim_y + threadIdx_y) * blockDim_z + threadIdx_z; + int i = (((blockIdx_x * gridDim_y + blockIdx_y) * gridDim_z + blockIdx_z) * + blockDim_x * blockDim_y * blockDim_z + + i_offset) % + num_states_; + while (Kokkos::atomic_compare_exchange(&locks_(i), 0, 1)) { + i += blockDim_x * blockDim_y * blockDim_z; + if (i >= num_states_) { + i = i_offset; + } } - return Random_XorShift64(state_(i),i); + return Random_XorShift64(state_(i), i); #else - return Random_XorShift64(state_(0),0); + return Random_XorShift64(state_(0), 0); #endif } -template<> -KOKKOS_INLINE_FUNCTION -void Random_XorShift64_Pool::free_state(const Random_XorShift64 &state) const { +template <> +KOKKOS_INLINE_FUNCTION void +Random_XorShift64_Pool::free_state( + const Random_XorShift64& state) const { #ifdef __HCC_ACCELERATOR__ state_(state.state_idx_) = state.state_; locks_(state.state_idx_) = 0; @@ -1486,24 +1447,28 @@ void Random_XorShift64_Pool::free_state(const Random #endif } - -template<> -inline -Random_XorShift1024_Pool::Random_XorShift1024_Pool(uint64_t seed) { +template <> +inline Random_XorShift1024_Pool< + Kokkos::Experimental::ROCm>::Random_XorShift1024_Pool(uint64_t seed) { num_states_ = 0; - init(seed,4*32768); + init(seed, 4 * 32768); } -template<> -KOKKOS_INLINE_FUNCTION -Random_XorShift1024 Random_XorShift1024_Pool::get_state() const { +template <> +KOKKOS_INLINE_FUNCTION Random_XorShift1024 +Random_XorShift1024_Pool::get_state() const { #ifdef __HCC_ACCELERATOR__ - const int i_offset = (threadIdx_x*blockDim_y + threadIdx_y)*blockDim_z+threadIdx_z; - int i = (((blockIdx_x*gridDim_y+blockIdx_y)*gridDim_z + blockIdx_z) * - blockDim_x*blockDim_y*blockDim_z + i_offset)%num_states_; - while(Kokkos::atomic_compare_exchange(&locks_(i),0,1)) { - i+=blockDim_x*blockDim_y*blockDim_z; - if(i>=num_states_) {i = i_offset;} + const int i_offset = + (threadIdx_x * blockDim_y + threadIdx_y) * blockDim_z + threadIdx_z; + int i = (((blockIdx_x * gridDim_y + blockIdx_y) * gridDim_z + blockIdx_z) * + blockDim_x * blockDim_y * blockDim_z + + i_offset) % + num_states_; + while (Kokkos::atomic_compare_exchange(&locks_(i), 0, 1)) { + i += blockDim_x * blockDim_y * blockDim_z; + if (i >= num_states_) { + i = i_offset; + } } return Random_XorShift1024(state_, p_(i), i); @@ -1512,515 +1477,589 @@ Random_XorShift1024 Random_XorShift1024_Pool -KOKKOS_INLINE_FUNCTION -void Random_XorShift1024_Pool::free_state(const Random_XorShift1024 &state) const { +template <> +KOKKOS_INLINE_FUNCTION void +Random_XorShift1024_Pool::free_state( + const Random_XorShift1024& state) const { #ifdef __HCC_ACCELERATOR__ - for(int i=0; i<16; i++) - state_(state.state_idx_,i) = state.state_[i]; + for (int i = 0; i < 16; i++) state_(state.state_idx_, i) = state.state_[i]; locks_(state.state_idx_) = 0; return; #endif } - #endif - namespace Impl { -template +template struct fill_random_functor_range; -template +template struct fill_random_functor_begin_end; -template -struct fill_random_functor_range{ +template +struct fill_random_functor_range { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; typename ViewType::const_value_type range; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_range(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type range_): - a(a_),rand_pool(rand_pool_),range(range_) {} + typename ViewType::const_value_type range_) + : a(a_), rand_pool(rand_pool_), range(range_) {} KOKKOS_INLINE_FUNCTION - void operator() (const IndexType& i) const { + void operator()(const IndexType& i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) - a(idx) = Rand::draw(gen,range); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) + a(idx) = Rand::draw(gen, range); } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_range{ +template +struct fill_random_functor_range { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; typename ViewType::const_value_type range; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_range(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type range_): - a(a_),rand_pool(rand_pool_),range(range_) {} + typename ViewType::const_value_type range_) + : a(a_), rand_pool(rand_pool_), range(range_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - a(idx,k) = Rand::draw(gen,range); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + a(idx, k) = Rand::draw(gen, range); } } rand_pool.free_state(gen); } }; - -template -struct fill_random_functor_range{ +template +struct fill_random_functor_range { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; typename ViewType::const_value_type range; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_range(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type range_): - a(a_),rand_pool(rand_pool_),range(range_) {} + typename ViewType::const_value_type range_) + : a(a_), rand_pool(rand_pool_), range(range_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - for(IndexType l=0;l(a.extent(2));l++) - a(idx,k,l) = Rand::draw(gen,range); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + for (IndexType l = 0; l < static_cast(a.extent(2)); l++) + a(idx, k, l) = Rand::draw(gen, range); } } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_range{ +template +struct fill_random_functor_range { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; typename ViewType::const_value_type range; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_range(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type range_): - a(a_),rand_pool(rand_pool_),range(range_) {} + typename ViewType::const_value_type range_) + : a(a_), rand_pool(rand_pool_), range(range_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - for(IndexType l=0;l(a.extent(2));l++) - for(IndexType m=0;m(a.extent(3));m++) - a(idx,k,l,m) = Rand::draw(gen,range); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + for (IndexType l = 0; l < static_cast(a.extent(2)); l++) + for (IndexType m = 0; m < static_cast(a.extent(3)); m++) + a(idx, k, l, m) = Rand::draw(gen, range); } } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_range{ +template +struct fill_random_functor_range { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; typename ViewType::const_value_type range; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_range(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type range_): - a(a_),rand_pool(rand_pool_),range(range_) {} + typename ViewType::const_value_type range_) + : a(a_), rand_pool(rand_pool_), range(range_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - for(IndexType l=0;l(a.extent(2));l++) - for(IndexType m=0;m(a.extent(3));m++) - for(IndexType n=0;n(a.extent(4));n++) - a(idx,k,l,m,n) = Rand::draw(gen,range); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + for (IndexType l = 0; l < static_cast(a.extent(2)); l++) + for (IndexType m = 0; m < static_cast(a.extent(3)); m++) + for (IndexType n = 0; n < static_cast(a.extent(4)); + n++) + a(idx, k, l, m, n) = Rand::draw(gen, range); } } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_range{ +template +struct fill_random_functor_range { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; typename ViewType::const_value_type range; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_range(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type range_): - a(a_),rand_pool(rand_pool_),range(range_) {} + typename ViewType::const_value_type range_) + : a(a_), rand_pool(rand_pool_), range(range_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - for(IndexType l=0;l(a.extent(2));l++) - for(IndexType m=0;m(a.extent(3));m++) - for(IndexType n=0;n(a.extent(4));n++) - for(IndexType o=0;o(a.extent(5));o++) - a(idx,k,l,m,n,o) = Rand::draw(gen,range); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + for (IndexType l = 0; l < static_cast(a.extent(2)); l++) + for (IndexType m = 0; m < static_cast(a.extent(3)); m++) + for (IndexType n = 0; n < static_cast(a.extent(4)); + n++) + for (IndexType o = 0; o < static_cast(a.extent(5)); + o++) + a(idx, k, l, m, n, o) = Rand::draw(gen, range); } } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_range{ +template +struct fill_random_functor_range { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; typename ViewType::const_value_type range; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_range(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type range_): - a(a_),rand_pool(rand_pool_),range(range_) {} + typename ViewType::const_value_type range_) + : a(a_), rand_pool(rand_pool_), range(range_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - for(IndexType l=0;l(a.extent(2));l++) - for(IndexType m=0;m(a.extent(3));m++) - for(IndexType n=0;n(a.extent(4));n++) - for(IndexType o=0;o(a.extent(5));o++) - for(IndexType p=0;p(a.extent(6));p++) - a(idx,k,l,m,n,o,p) = Rand::draw(gen,range); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + for (IndexType l = 0; l < static_cast(a.extent(2)); l++) + for (IndexType m = 0; m < static_cast(a.extent(3)); m++) + for (IndexType n = 0; n < static_cast(a.extent(4)); + n++) + for (IndexType o = 0; o < static_cast(a.extent(5)); + o++) + for (IndexType p = 0; p < static_cast(a.extent(6)); + p++) + a(idx, k, l, m, n, o, p) = Rand::draw(gen, range); } } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_range{ +template +struct fill_random_functor_range { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; typename ViewType::const_value_type range; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_range(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type range_): - a(a_),rand_pool(rand_pool_),range(range_) {} + typename ViewType::const_value_type range_) + : a(a_), rand_pool(rand_pool_), range(range_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - for(IndexType l=0;l(a.extent(2));l++) - for(IndexType m=0;m(a.extent(3));m++) - for(IndexType n=0;n(a.extent(4));n++) - for(IndexType o=0;o(a.extent(5));o++) - for(IndexType p=0;p(a.extent(6));p++) - for(IndexType q=0;q(a.extent(7));q++) - a(idx,k,l,m,n,o,p,q) = Rand::draw(gen,range); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + for (IndexType l = 0; l < static_cast(a.extent(2)); l++) + for (IndexType m = 0; m < static_cast(a.extent(3)); m++) + for (IndexType n = 0; n < static_cast(a.extent(4)); + n++) + for (IndexType o = 0; o < static_cast(a.extent(5)); + o++) + for (IndexType p = 0; p < static_cast(a.extent(6)); + p++) + for (IndexType q = 0; + q < static_cast(a.extent(7)); q++) + a(idx, k, l, m, n, o, p, q) = Rand::draw(gen, range); } } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_begin_end{ +template +struct fill_random_functor_begin_end { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; - typename ViewType::const_value_type begin,end; + typename ViewType::const_value_type begin, end; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_begin_end(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type begin_, typename ViewType::const_value_type end_): - a(a_),rand_pool(rand_pool_),begin(begin_),end(end_) {} + typename ViewType::const_value_type begin_, + typename ViewType::const_value_type end_) + : a(a_), rand_pool(rand_pool_), begin(begin_), end(end_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) - a(idx) = Rand::draw(gen,begin,end); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) + a(idx) = Rand::draw(gen, begin, end); } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_begin_end{ +template +struct fill_random_functor_begin_end { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; - typename ViewType::const_value_type begin,end; + typename ViewType::const_value_type begin, end; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_begin_end(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type begin_, typename ViewType::const_value_type end_): - a(a_),rand_pool(rand_pool_),begin(begin_),end(end_) {} + typename ViewType::const_value_type begin_, + typename ViewType::const_value_type end_) + : a(a_), rand_pool(rand_pool_), begin(begin_), end(end_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - a(idx,k) = Rand::draw(gen,begin,end); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + a(idx, k) = Rand::draw(gen, begin, end); } } rand_pool.free_state(gen); } }; - -template -struct fill_random_functor_begin_end{ +template +struct fill_random_functor_begin_end { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; - typename ViewType::const_value_type begin,end; + typename ViewType::const_value_type begin, end; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_begin_end(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type begin_, typename ViewType::const_value_type end_): - a(a_),rand_pool(rand_pool_),begin(begin_),end(end_) {} + typename ViewType::const_value_type begin_, + typename ViewType::const_value_type end_) + : a(a_), rand_pool(rand_pool_), begin(begin_), end(end_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - for(IndexType l=0;l(a.extent(2));l++) - a(idx,k,l) = Rand::draw(gen,begin,end); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + for (IndexType l = 0; l < static_cast(a.extent(2)); l++) + a(idx, k, l) = Rand::draw(gen, begin, end); } } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_begin_end{ +template +struct fill_random_functor_begin_end { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; - typename ViewType::const_value_type begin,end; + typename ViewType::const_value_type begin, end; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_begin_end(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type begin_, typename ViewType::const_value_type end_): - a(a_),rand_pool(rand_pool_),begin(begin_),end(end_) {} + typename ViewType::const_value_type begin_, + typename ViewType::const_value_type end_) + : a(a_), rand_pool(rand_pool_), begin(begin_), end(end_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - for(IndexType l=0;l(a.extent(2));l++) - for(IndexType m=0;m(a.extent(3));m++) - a(idx,k,l,m) = Rand::draw(gen,begin,end); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + for (IndexType l = 0; l < static_cast(a.extent(2)); l++) + for (IndexType m = 0; m < static_cast(a.extent(3)); m++) + a(idx, k, l, m) = Rand::draw(gen, begin, end); } } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_begin_end{ +template +struct fill_random_functor_begin_end { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; - typename ViewType::const_value_type begin,end; + typename ViewType::const_value_type begin, end; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_begin_end(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type begin_, typename ViewType::const_value_type end_): - a(a_),rand_pool(rand_pool_),begin(begin_),end(end_) {} + typename ViewType::const_value_type begin_, + typename ViewType::const_value_type end_) + : a(a_), rand_pool(rand_pool_), begin(begin_), end(end_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))){ - for(IndexType l=0;l(a.extent(1));l++) - for(IndexType m=0;m(a.extent(2));m++) - for(IndexType n=0;n(a.extent(3));n++) - for(IndexType o=0;o(a.extent(4));o++) - a(idx,l,m,n,o) = Rand::draw(gen,begin,end); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType l = 0; l < static_cast(a.extent(1)); l++) + for (IndexType m = 0; m < static_cast(a.extent(2)); m++) + for (IndexType n = 0; n < static_cast(a.extent(3)); n++) + for (IndexType o = 0; o < static_cast(a.extent(4)); + o++) + a(idx, l, m, n, o) = Rand::draw(gen, begin, end); } } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_begin_end{ +template +struct fill_random_functor_begin_end { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; - typename ViewType::const_value_type begin,end; + typename ViewType::const_value_type begin, end; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_begin_end(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type begin_, typename ViewType::const_value_type end_): - a(a_),rand_pool(rand_pool_),begin(begin_),end(end_) {} + typename ViewType::const_value_type begin_, + typename ViewType::const_value_type end_) + : a(a_), rand_pool(rand_pool_), begin(begin_), end(end_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - for(IndexType l=0;l(a.extent(2));l++) - for(IndexType m=0;m(a.extent(3));m++) - for(IndexType n=0;n(a.extent(4));n++) - for(IndexType o=0;o(a.extent(5));o++) - a(idx,k,l,m,n,o) = Rand::draw(gen,begin,end); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + for (IndexType l = 0; l < static_cast(a.extent(2)); l++) + for (IndexType m = 0; m < static_cast(a.extent(3)); m++) + for (IndexType n = 0; n < static_cast(a.extent(4)); + n++) + for (IndexType o = 0; o < static_cast(a.extent(5)); + o++) + a(idx, k, l, m, n, o) = Rand::draw(gen, begin, end); } } rand_pool.free_state(gen); } }; - -template -struct fill_random_functor_begin_end{ +template +struct fill_random_functor_begin_end { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; - typename ViewType::const_value_type begin,end; + typename ViewType::const_value_type begin, end; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_begin_end(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type begin_, typename ViewType::const_value_type end_): - a(a_),rand_pool(rand_pool_),begin(begin_),end(end_) {} + typename ViewType::const_value_type begin_, + typename ViewType::const_value_type end_) + : a(a_), rand_pool(rand_pool_), begin(begin_), end(end_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - for(IndexType l=0;l(a.extent(2));l++) - for(IndexType m=0;m(a.extent(3));m++) - for(IndexType n=0;n(a.extent(4));n++) - for(IndexType o=0;o(a.extent(5));o++) - for(IndexType p=0;p(a.extent(6));p++) - a(idx,k,l,m,n,o,p) = Rand::draw(gen,begin,end); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + for (IndexType l = 0; l < static_cast(a.extent(2)); l++) + for (IndexType m = 0; m < static_cast(a.extent(3)); m++) + for (IndexType n = 0; n < static_cast(a.extent(4)); + n++) + for (IndexType o = 0; o < static_cast(a.extent(5)); + o++) + for (IndexType p = 0; p < static_cast(a.extent(6)); + p++) + a(idx, k, l, m, n, o, p) = Rand::draw(gen, begin, end); } } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_begin_end{ +template +struct fill_random_functor_begin_end { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; - typename ViewType::const_value_type begin,end; + typename ViewType::const_value_type begin, end; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_begin_end(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type begin_, typename ViewType::const_value_type end_): - a(a_),rand_pool(rand_pool_),begin(begin_),end(end_) {} + typename ViewType::const_value_type begin_, + typename ViewType::const_value_type end_) + : a(a_), rand_pool(rand_pool_), begin(begin_), end(end_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - for(IndexType l=0;l(a.extent(2));l++) - for(IndexType m=0;m(a.extent(3));m++) - for(IndexType n=0;n(a.extent(4));n++) - for(IndexType o=0;o(a.extent(5));o++) - for(IndexType p=0;p(a.extent(6));p++) - for(IndexType q=0;q(a.extent(7));q++) - a(idx,k,l,m,n,o,p,q) = Rand::draw(gen,begin,end); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + for (IndexType l = 0; l < static_cast(a.extent(2)); l++) + for (IndexType m = 0; m < static_cast(a.extent(3)); m++) + for (IndexType n = 0; n < static_cast(a.extent(4)); + n++) + for (IndexType o = 0; o < static_cast(a.extent(5)); + o++) + for (IndexType p = 0; p < static_cast(a.extent(6)); + p++) + for (IndexType q = 0; + q < static_cast(a.extent(7)); q++) + a(idx, k, l, m, n, o, p, q) = Rand::draw(gen, begin, end); } } rand_pool.free_state(gen); } }; -} +} // namespace Impl -template -void fill_random(ViewType a, RandomPool g, typename ViewType::const_value_type range) { +template +void fill_random(ViewType a, RandomPool g, + typename ViewType::const_value_type range) { int64_t LDA = a.extent(0); - if(LDA>0) - parallel_for((LDA+127)/128,Impl::fill_random_functor_range(a,g,range)); + if (LDA > 0) + parallel_for((LDA + 127) / 128, + Impl::fill_random_functor_range( + a, g, range)); } -template -void fill_random(ViewType a, RandomPool g, typename ViewType::const_value_type begin,typename ViewType::const_value_type end ) { +template +void fill_random(ViewType a, RandomPool g, + typename ViewType::const_value_type begin, + typename ViewType::const_value_type end) { int64_t LDA = a.extent(0); - if(LDA>0) - parallel_for((LDA+127)/128,Impl::fill_random_functor_begin_end(a,g,begin,end)); -} + if (LDA > 0) + parallel_for((LDA + 127) / 128, + Impl::fill_random_functor_begin_end( + a, g, begin, end)); } +} // namespace Kokkos #endif diff --git a/lib/kokkos/algorithms/src/Kokkos_Sort.hpp b/lib/kokkos/algorithms/src/Kokkos_Sort.hpp index 7fb8505fe5..b7a988361f 100644 --- a/lib/kokkos/algorithms/src/Kokkos_Sort.hpp +++ b/lib/kokkos/algorithms/src/Kokkos_Sort.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,12 +37,11 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ - #ifndef KOKKOS_SORT_HPP_ #define KOKKOS_SORT_HPP_ @@ -51,125 +51,107 @@ namespace Kokkos { - namespace Impl { +namespace Impl { - template< class DstViewType , class SrcViewType - , int Rank = DstViewType::Rank > - struct CopyOp; +template +struct CopyOp; - template< class DstViewType , class SrcViewType > - struct CopyOp { - KOKKOS_INLINE_FUNCTION - static void copy(DstViewType const& dst, size_t i_dst, - SrcViewType const& src, size_t i_src ) { - dst(i_dst) = src(i_src); - } - }; +template +struct CopyOp { + KOKKOS_INLINE_FUNCTION + static void copy(DstViewType const& dst, size_t i_dst, SrcViewType const& src, + size_t i_src) { + dst(i_dst) = src(i_src); + } +}; - template< class DstViewType , class SrcViewType > - struct CopyOp { - KOKKOS_INLINE_FUNCTION - static void copy(DstViewType const& dst, size_t i_dst, - SrcViewType const& src, size_t i_src ) { - for(int j = 0;j< (int) dst.extent(1); j++) - dst(i_dst,j) = src(i_src,j); - } - }; +template +struct CopyOp { + KOKKOS_INLINE_FUNCTION + static void copy(DstViewType const& dst, size_t i_dst, SrcViewType const& src, + size_t i_src) { + for (int j = 0; j < (int)dst.extent(1); j++) dst(i_dst, j) = src(i_src, j); + } +}; - template< class DstViewType , class SrcViewType > - struct CopyOp { - KOKKOS_INLINE_FUNCTION - static void copy(DstViewType const& dst, size_t i_dst, - SrcViewType const& src, size_t i_src ) { - for(int j = 0; j +struct CopyOp { + KOKKOS_INLINE_FUNCTION + static void copy(DstViewType const& dst, size_t i_dst, SrcViewType const& src, + size_t i_src) { + for (int j = 0; j < dst.extent(1); j++) + for (int k = 0; k < dst.extent(2); k++) + dst(i_dst, j, k) = src(i_src, j, k); } +}; +} // namespace Impl //---------------------------------------------------------------------------- -template< class KeyViewType - , class BinSortOp - , class Space = typename KeyViewType::device_type - , class SizeType = typename KeyViewType::memory_space::size_type - > +template class BinSort { -public: - - template< class DstViewType , class SrcViewType > + public: + template struct copy_functor { + typedef typename SrcViewType::const_type src_view_type; - typedef typename SrcViewType::const_type src_view_type ; + typedef Impl::CopyOp copy_op; - typedef Impl::CopyOp< DstViewType , src_view_type > copy_op ; + DstViewType dst_values; + src_view_type src_values; + int dst_offset; - DstViewType dst_values ; - src_view_type src_values ; - int dst_offset ; - - copy_functor( DstViewType const & dst_values_ - , int const & dst_offset_ - , SrcViewType const & src_values_ - ) - : dst_values( dst_values_ ) - , src_values( src_values_ ) - , dst_offset( dst_offset_ ) - {} + copy_functor(DstViewType const& dst_values_, int const& dst_offset_, + SrcViewType const& src_values_) + : dst_values(dst_values_), + src_values(src_values_), + dst_offset(dst_offset_) {} KOKKOS_INLINE_FUNCTION - void operator() (const int& i) const { - copy_op::copy(dst_values,i+dst_offset,src_values,i); + void operator()(const int& i) const { + copy_op::copy(dst_values, i + dst_offset, src_values, i); } }; - template< class DstViewType - , class PermuteViewType - , class SrcViewType - > + template struct copy_permute_functor { - // If a Kokkos::View then can generate constant random access // otherwise can only use the constant type. - typedef typename std::conditional - < Kokkos::is_view< SrcViewType >::value - , Kokkos::View< typename SrcViewType::const_data_type - , typename SrcViewType::array_layout - , typename SrcViewType::device_type - , Kokkos::MemoryTraits - > - , typename SrcViewType::const_type - >::type src_view_type ; - - typedef typename PermuteViewType::const_type perm_view_type ; - - typedef Impl::CopyOp< DstViewType , src_view_type > copy_op ; - - DstViewType dst_values ; - perm_view_type sort_order ; - src_view_type src_values ; - int src_offset ; - - copy_permute_functor( DstViewType const & dst_values_ - , PermuteViewType const & sort_order_ - , SrcViewType const & src_values_ - , int const & src_offset_ - ) - : dst_values( dst_values_ ) - , sort_order( sort_order_ ) - , src_values( src_values_ ) - , src_offset( src_offset_ ) - {} + typedef typename std::conditional< + Kokkos::is_view::value, + Kokkos::View >, + typename SrcViewType::const_type>::type src_view_type; + + typedef typename PermuteViewType::const_type perm_view_type; + + typedef Impl::CopyOp copy_op; + + DstViewType dst_values; + perm_view_type sort_order; + src_view_type src_values; + int src_offset; + + copy_permute_functor(DstViewType const& dst_values_, + PermuteViewType const& sort_order_, + SrcViewType const& src_values_, int const& src_offset_) + : dst_values(dst_values_), + sort_order(sort_order_), + src_values(src_values_), + src_offset(src_offset_) {} KOKKOS_INLINE_FUNCTION - void operator() (const int& i) const { - copy_op::copy(dst_values,i,src_values,src_offset+sort_order(i)); + void operator()(const int& i) const { + copy_op::copy(dst_values, i, src_values, src_offset + sort_order(i)); } }; - typedef typename Space::execution_space execution_space; + typedef typename Space::execution_space execution_space; typedef BinSortOp bin_op_type; struct bin_count_tag {}; @@ -177,221 +159,236 @@ public: struct bin_binning_tag {}; struct bin_sort_bins_tag {}; -public: - + public: typedef SizeType size_type; typedef size_type value_type; typedef Kokkos::View offset_type; typedef Kokkos::View bin_count_type; - typedef typename KeyViewType::const_type const_key_view_type ; + typedef typename KeyViewType::const_type const_key_view_type; // If a Kokkos::View then can generate constant random access // otherwise can only use the constant type. - typedef typename std::conditional - < Kokkos::is_view< KeyViewType >::value - , Kokkos::View< typename KeyViewType::const_data_type, - typename KeyViewType::array_layout, - typename KeyViewType::device_type, - Kokkos::MemoryTraits > - , const_key_view_type - >::type const_rnd_key_view_type; + typedef typename std::conditional< + Kokkos::is_view::value, + Kokkos::View >, + const_key_view_type>::type const_rnd_key_view_type; typedef typename KeyViewType::non_const_value_type non_const_key_scalar; - typedef typename KeyViewType::const_value_type const_key_scalar; - - typedef Kokkos::View > bin_count_atomic_type ; + typedef typename KeyViewType::const_value_type const_key_scalar; -private: + typedef Kokkos::View > + bin_count_atomic_type; + private: const_key_view_type keys; const_rnd_key_view_type keys_rnd; -public: - - BinSortOp bin_op ; - offset_type bin_offsets ; - bin_count_atomic_type bin_count_atomic ; - bin_count_type bin_count_const ; - offset_type sort_order ; + public: + BinSortOp bin_op; + offset_type bin_offsets; + bin_count_atomic_type bin_count_atomic; + bin_count_type bin_count_const; + offset_type sort_order; - int range_begin ; - int range_end ; - bool sort_within_bins ; - -public: + int range_begin; + int range_end; + bool sort_within_bins; + public: BinSort() {} //---------------------------------------- - // Constructor: takes the keys, the binning_operator and optionally whether to sort within bins (default false) - BinSort( const_key_view_type keys_ - , int range_begin_ - , int range_end_ - , BinSortOp bin_op_ - , bool sort_within_bins_ = false - ) - : keys(keys_) - , keys_rnd(keys_) - , bin_op(bin_op_) - , bin_offsets() - , bin_count_atomic() - , bin_count_const() - , sort_order() - , range_begin( range_begin_ ) - , range_end( range_end_ ) - , sort_within_bins( sort_within_bins_ ) - { - bin_count_atomic = Kokkos::View("Kokkos::SortImpl::BinSortFunctor::bin_count",bin_op.max_bins()); - bin_count_const = bin_count_atomic; - bin_offsets = offset_type(ViewAllocateWithoutInitializing("Kokkos::SortImpl::BinSortFunctor::bin_offsets"),bin_op.max_bins()); - sort_order = offset_type(ViewAllocateWithoutInitializing("Kokkos::SortImpl::BinSortFunctor::sort_order"),range_end-range_begin); + // Constructor: takes the keys, the binning_operator and optionally whether to + // sort within bins (default false) + BinSort(const_key_view_type keys_, int range_begin_, int range_end_, + BinSortOp bin_op_, bool sort_within_bins_ = false) + : keys(keys_), + keys_rnd(keys_), + bin_op(bin_op_), + bin_offsets(), + bin_count_atomic(), + bin_count_const(), + sort_order(), + range_begin(range_begin_), + range_end(range_end_), + sort_within_bins(sort_within_bins_) { + bin_count_atomic = Kokkos::View( + "Kokkos::SortImpl::BinSortFunctor::bin_count", bin_op.max_bins()); + bin_count_const = bin_count_atomic; + bin_offsets = + offset_type(ViewAllocateWithoutInitializing( + "Kokkos::SortImpl::BinSortFunctor::bin_offsets"), + bin_op.max_bins()); + sort_order = + offset_type(ViewAllocateWithoutInitializing( + "Kokkos::SortImpl::BinSortFunctor::sort_order"), + range_end - range_begin); } - BinSort( const_key_view_type keys_ - , BinSortOp bin_op_ - , bool sort_within_bins_ = false - ) - : BinSort( keys_ , 0 , keys_.extent(0), bin_op_ , sort_within_bins_ ) {} + BinSort(const_key_view_type keys_, BinSortOp bin_op_, + bool sort_within_bins_ = false) + : BinSort(keys_, 0, keys_.extent(0), bin_op_, sort_within_bins_) {} //---------------------------------------- - // Create the permutation vector, the bin_offset array and the bin_count array. Can be called again if keys changed + // Create the permutation vector, the bin_offset array and the bin_count + // array. Can be called again if keys changed void create_permute_vector() { - const size_t len = range_end - range_begin ; - Kokkos::parallel_for ("Kokkos::Sort::BinCount",Kokkos::RangePolicy (0,len),*this); - Kokkos::parallel_scan("Kokkos::Sort::BinOffset",Kokkos::RangePolicy (0,bin_op.max_bins()) ,*this); - - Kokkos::deep_copy(bin_count_atomic,0); - Kokkos::parallel_for ("Kokkos::Sort::BinBinning",Kokkos::RangePolicy (0,len),*this); - - if(sort_within_bins) - Kokkos::parallel_for ("Kokkos::Sort::BinSort",Kokkos::RangePolicy(0,bin_op.max_bins()) ,*this); + const size_t len = range_end - range_begin; + Kokkos::parallel_for( + "Kokkos::Sort::BinCount", + Kokkos::RangePolicy(0, len), *this); + Kokkos::parallel_scan("Kokkos::Sort::BinOffset", + Kokkos::RangePolicy( + 0, bin_op.max_bins()), + *this); + + Kokkos::deep_copy(bin_count_atomic, 0); + Kokkos::parallel_for( + "Kokkos::Sort::BinBinning", + Kokkos::RangePolicy(0, len), *this); + + if (sort_within_bins) + Kokkos::parallel_for( + "Kokkos::Sort::BinSort", + Kokkos::RangePolicy( + 0, bin_op.max_bins()), + *this); } - // Sort a subset of a view with respect to the first dimension using the permutation array - template - void sort( ValuesViewType const & values - , int values_range_begin - , int values_range_end) const - { - typedef - Kokkos::View< typename ValuesViewType::data_type, - typename ValuesViewType::array_layout, - typename ValuesViewType::device_type > - scratch_view_type ; - - const size_t len = range_end - range_begin ; - const size_t values_len = values_range_end - values_range_begin ; + // Sort a subset of a view with respect to the first dimension using the + // permutation array + template + void sort(ValuesViewType const& values, int values_range_begin, + int values_range_end) const { + typedef Kokkos::View + scratch_view_type; + + const size_t len = range_end - range_begin; + const size_t values_len = values_range_end - values_range_begin; if (len != values_len) { - Kokkos::abort("BinSort::sort: values range length != permutation vector length"); + Kokkos::abort( + "BinSort::sort: values range length != permutation vector length"); } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - scratch_view_type - sorted_values(ViewAllocateWithoutInitializing("Kokkos::SortImpl::BinSortFunctor::sorted_values"), - len, - values.extent(1), - values.extent(2), - values.extent(3), - values.extent(4), - values.extent(5), - values.extent(6), - values.extent(7)); + scratch_view_type sorted_values( + ViewAllocateWithoutInitializing( + "Kokkos::SortImpl::BinSortFunctor::sorted_values"), + len, values.extent(1), values.extent(2), values.extent(3), + values.extent(4), values.extent(5), values.extent(6), values.extent(7)); #else - scratch_view_type - sorted_values(ViewAllocateWithoutInitializing("Kokkos::SortImpl::BinSortFunctor::sorted_values"), - values.rank_dynamic > 0 ? len : KOKKOS_IMPL_CTOR_DEFAULT_ARG, - values.rank_dynamic > 1 ? values.extent(1) : KOKKOS_IMPL_CTOR_DEFAULT_ARG , - values.rank_dynamic > 2 ? values.extent(2) : KOKKOS_IMPL_CTOR_DEFAULT_ARG, - values.rank_dynamic > 3 ? values.extent(3) : KOKKOS_IMPL_CTOR_DEFAULT_ARG, - values.rank_dynamic > 4 ? values.extent(4) : KOKKOS_IMPL_CTOR_DEFAULT_ARG, - values.rank_dynamic > 5 ? values.extent(5) : KOKKOS_IMPL_CTOR_DEFAULT_ARG, - values.rank_dynamic > 6 ? values.extent(6) : KOKKOS_IMPL_CTOR_DEFAULT_ARG, - values.rank_dynamic > 7 ? values.extent(7) : KOKKOS_IMPL_CTOR_DEFAULT_ARG); + scratch_view_type sorted_values( + ViewAllocateWithoutInitializing( + "Kokkos::SortImpl::BinSortFunctor::sorted_values"), + values.rank_dynamic > 0 ? len : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + values.rank_dynamic > 1 ? values.extent(1) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + values.rank_dynamic > 2 ? values.extent(2) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + values.rank_dynamic > 3 ? values.extent(3) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + values.rank_dynamic > 4 ? values.extent(4) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + values.rank_dynamic > 5 ? values.extent(5) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + values.rank_dynamic > 6 ? values.extent(6) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + values.rank_dynamic > 7 ? values.extent(7) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG); #endif { - copy_permute_functor< scratch_view_type /* DstViewType */ - , offset_type /* PermuteViewType */ - , ValuesViewType /* SrcViewType */ - > - functor( sorted_values , sort_order , values, values_range_begin - range_begin ); - - parallel_for("Kokkos::Sort::CopyPermute", Kokkos::RangePolicy(0,len),functor); + copy_permute_functor + functor(sorted_values, sort_order, values, + values_range_begin - range_begin); + + parallel_for("Kokkos::Sort::CopyPermute", + Kokkos::RangePolicy(0, len), functor); } { - copy_functor< ValuesViewType , scratch_view_type > - functor( values , range_begin , sorted_values ); + copy_functor functor( + values, range_begin, sorted_values); - parallel_for("Kokkos::Sort::Copy", Kokkos::RangePolicy(0,len),functor); + parallel_for("Kokkos::Sort::Copy", + Kokkos::RangePolicy(0, len), functor); } Kokkos::fence(); } - template - void sort( ValuesViewType const & values ) const - { - this->sort( values, 0, /*values.extent(0)*/ range_end - range_begin ); + template + void sort(ValuesViewType const& values) const { + this->sort(values, 0, /*values.extent(0)*/ range_end - range_begin); } // Get the permutation vector KOKKOS_INLINE_FUNCTION - offset_type get_permute_vector() const { return sort_order;} + offset_type get_permute_vector() const { return sort_order; } // Get the start offsets for each bin KOKKOS_INLINE_FUNCTION - offset_type get_bin_offsets() const { return bin_offsets;} + offset_type get_bin_offsets() const { return bin_offsets; } // Get the count for each bin KOKKOS_INLINE_FUNCTION - bin_count_type get_bin_count() const {return bin_count_const;} - -public: + bin_count_type get_bin_count() const { return bin_count_const; } + public: KOKKOS_INLINE_FUNCTION - void operator() (const bin_count_tag& tag, const int& i) const { - const int j = range_begin + i ; + void operator()(const bin_count_tag& tag, const int& i) const { + const int j = range_begin + i; bin_count_atomic(bin_op.bin(keys, j))++; } KOKKOS_INLINE_FUNCTION - void operator() (const bin_offset_tag& tag, const int& i, value_type& offset, const bool& final) const { - if(final) { + void operator()(const bin_offset_tag& tag, const int& i, value_type& offset, + const bool& final) const { + if (final) { bin_offsets(i) = offset; } - offset+=bin_count_const(i); + offset += bin_count_const(i); } KOKKOS_INLINE_FUNCTION - void operator() (const bin_binning_tag& tag, const int& i) const { - const int j = range_begin + i ; - const int bin = bin_op.bin(keys,j); + void operator()(const bin_binning_tag& tag, const int& i) const { + const int j = range_begin + i; + const int bin = bin_op.bin(keys, j); const int count = bin_count_atomic(bin)++; - sort_order(bin_offsets(bin) + count) = j ; + sort_order(bin_offsets(bin) + count) = j; } KOKKOS_INLINE_FUNCTION - void operator() (const bin_sort_bins_tag& tag, const int&i ) const { + void operator()(const bin_sort_bins_tag& tag, const int& i) const { auto bin_size = bin_count_const(i); if (bin_size <= 1) return; - int upper_bound = bin_offsets(i)+bin_size; - bool sorted = false; - while(!sorted) { - sorted = true; + int upper_bound = bin_offsets(i) + bin_size; + bool sorted = false; + while (!sorted) { + sorted = true; int old_idx = sort_order(bin_offsets(i)); int new_idx; - for(int k=bin_offsets(i)+1; k +template struct BinOp1D { int max_bins_; double mul_; typename KeyViewType::const_value_type range_; typename KeyViewType::const_value_type min_; - BinOp1D():max_bins_(0),mul_(0.0), - range_(typename KeyViewType::const_value_type()), - min_(typename KeyViewType::const_value_type()) {} + BinOp1D() + : max_bins_(0), + mul_(0.0), + range_(typename KeyViewType::const_value_type()), + min_(typename KeyViewType::const_value_type()) {} - //Construct BinOp with number of bins, minimum value and maxuimum value + // Construct BinOp with number of bins, minimum value and maxuimum value BinOp1D(int max_bins__, typename KeyViewType::const_value_type min, - typename KeyViewType::const_value_type max ) - :max_bins_(max_bins__+1),mul_(1.0*max_bins__/(max-min)),range_(max-min),min_(min) {} - - //Determine bin index from key value - template - KOKKOS_INLINE_FUNCTION - int bin(ViewType& keys, const int& i) const { - return int(mul_*(keys(i)-min_)); + typename KeyViewType::const_value_type max) + : max_bins_(max_bins__ + 1), + mul_(1.0 * max_bins__ / (max - min)), + range_(max - min), + min_(min) {} + + // Determine bin index from key value + template + KOKKOS_INLINE_FUNCTION int bin(ViewType& keys, const int& i) const { + return int(mul_ * (keys(i) - min_)); } - //Return maximum bin index + 1 + // Return maximum bin index + 1 KOKKOS_INLINE_FUNCTION - int max_bins() const { - return max_bins_; - } + int max_bins() const { return max_bins_; } - //Compare to keys within a bin if true new_val will be put before old_val - template - KOKKOS_INLINE_FUNCTION - bool operator()(ViewType& keys, iType1& i1, iType2& i2) const { - return keys(i1) + KOKKOS_INLINE_FUNCTION bool operator()(ViewType& keys, iType1& i1, + iType2& i2) const { + return keys(i1) < keys(i2); } }; -template +template struct BinOp3D { int max_bins_[3]; double mul_[3]; @@ -450,43 +449,42 @@ struct BinOp3D { BinOp3D() {} BinOp3D(int max_bins__[], typename KeyViewType::const_value_type min[], - typename KeyViewType::const_value_type max[] ) - { + typename KeyViewType::const_value_type max[]) { max_bins_[0] = max_bins__[0]; max_bins_[1] = max_bins__[1]; max_bins_[2] = max_bins__[2]; - mul_[0] = 1.0*max_bins__[0]/(max[0]-min[0]); - mul_[1] = 1.0*max_bins__[1]/(max[1]-min[1]); - mul_[2] = 1.0*max_bins__[2]/(max[2]-min[2]); - range_[0] = max[0]-min[0]; - range_[1] = max[1]-min[1]; - range_[2] = max[2]-min[2]; - min_[0] = min[0]; - min_[1] = min[1]; - min_[2] = min[2]; + mul_[0] = 1.0 * max_bins__[0] / (max[0] - min[0]); + mul_[1] = 1.0 * max_bins__[1] / (max[1] - min[1]); + mul_[2] = 1.0 * max_bins__[2] / (max[2] - min[2]); + range_[0] = max[0] - min[0]; + range_[1] = max[1] - min[1]; + range_[2] = max[2] - min[2]; + min_[0] = min[0]; + min_[1] = min[1]; + min_[2] = min[2]; } - template - KOKKOS_INLINE_FUNCTION - int bin(ViewType& keys, const int& i) const { - return int( (((int(mul_[0]*(keys(i,0)-min_[0]))*max_bins_[1]) + - int(mul_[1]*(keys(i,1)-min_[1])))*max_bins_[2]) + - int(mul_[2]*(keys(i,2)-min_[2]))); - } - - KOKKOS_INLINE_FUNCTION - int max_bins() const { - return max_bins_[0]*max_bins_[1]*max_bins_[2]; + template + KOKKOS_INLINE_FUNCTION int bin(ViewType& keys, const int& i) const { + return int((((int(mul_[0] * (keys(i, 0) - min_[0])) * max_bins_[1]) + + int(mul_[1] * (keys(i, 1) - min_[1]))) * + max_bins_[2]) + + int(mul_[2] * (keys(i, 2) - min_[2]))); } - template KOKKOS_INLINE_FUNCTION - bool operator()(ViewType& keys, iType1& i1 , iType2& i2) const { - if (keys(i1,0)>keys(i2,0)) return true; - else if (keys(i1,0)==keys(i2,0)) { - if (keys(i1,1)>keys(i2,1)) return true; - else if (keys(i1,1)==keys(i2,1)) { - if (keys(i1,2)>keys(i2,2)) return true; + int max_bins() const { return max_bins_[0] * max_bins_[1] * max_bins_[2]; } + + template + KOKKOS_INLINE_FUNCTION bool operator()(ViewType& keys, iType1& i1, + iType2& i2) const { + if (keys(i1, 0) > keys(i2, 0)) + return true; + else if (keys(i1, 0) == keys(i2, 0)) { + if (keys(i1, 1) > keys(i2, 1)) + return true; + else if (keys(i1, 1) == keys(i2, 1)) { + if (keys(i1, 2) > keys(i2, 2)) return true; } } return false; @@ -495,85 +493,80 @@ struct BinOp3D { namespace Impl { -template +template bool try_std_sort(ViewType view) { - bool possible = true; - size_t stride[8] = { view.stride_0() - , view.stride_1() - , view.stride_2() - , view.stride_3() - , view.stride_4() - , view.stride_5() - , view.stride_6() - , view.stride_7() - }; - possible = possible && std::is_same::value; - possible = possible && (ViewType::Rank == 1); - possible = possible && (stride[0] == 1); - if(possible) { - std::sort(view.data(),view.data()+view.extent(0)); + bool possible = true; + size_t stride[8] = {view.stride_0(), view.stride_1(), view.stride_2(), + view.stride_3(), view.stride_4(), view.stride_5(), + view.stride_6(), view.stride_7()}; + possible = possible && + std::is_same::value; + possible = possible && (ViewType::Rank == 1); + possible = possible && (stride[0] == 1); + if (possible) { + std::sort(view.data(), view.data() + view.extent(0)); } return possible; } -template +template struct min_max_functor { - typedef Kokkos::MinMaxScalar minmax_scalar; + typedef Kokkos::MinMaxScalar + minmax_scalar; ViewType view; - min_max_functor(const ViewType& view_):view(view_) {} + min_max_functor(const ViewType& view_) : view(view_) {} KOKKOS_INLINE_FUNCTION - void operator() (const size_t& i, minmax_scalar& minmax) const { - if(view(i) < minmax.min_val) minmax.min_val = view(i); - if(view(i) > minmax.max_val) minmax.max_val = view(i); + void operator()(const size_t& i, minmax_scalar& minmax) const { + if (view(i) < minmax.min_val) minmax.min_val = view(i); + if (view(i) > minmax.max_val) minmax.max_val = view(i); } }; -} +} // namespace Impl -template -void sort( ViewType const & view , bool const always_use_kokkos_sort = false) -{ - if(!always_use_kokkos_sort) { - if(Impl::try_std_sort(view)) return; +template +void sort(ViewType const& view, bool const always_use_kokkos_sort = false) { + if (!always_use_kokkos_sort) { + if (Impl::try_std_sort(view)) return; } typedef BinOp1D CompType; Kokkos::MinMaxScalar result; Kokkos::MinMax reducer(result); - parallel_reduce("Kokkos::Sort::FindExtent",Kokkos::RangePolicy(0,view.extent(0)), - Impl::min_max_functor(view),reducer); - if(result.min_val == result.max_val) return; - BinSort bin_sort(view,CompType(view.extent(0)/2,result.min_val,result.max_val),true); + parallel_reduce("Kokkos::Sort::FindExtent", + Kokkos::RangePolicy( + 0, view.extent(0)), + Impl::min_max_functor(view), reducer); + if (result.min_val == result.max_val) return; + BinSort bin_sort( + view, CompType(view.extent(0) / 2, result.min_val, result.max_val), true); bin_sort.create_permute_vector(); bin_sort.sort(view); } -template -void sort( ViewType view - , size_t const begin - , size_t const end - ) -{ - typedef Kokkos::RangePolicy range_policy ; +template +void sort(ViewType view, size_t const begin, size_t const end) { + typedef Kokkos::RangePolicy range_policy; typedef BinOp1D CompType; Kokkos::MinMaxScalar result; Kokkos::MinMax reducer(result); - parallel_reduce("Kokkos::Sort::FindExtent", range_policy( begin , end ) - , Impl::min_max_functor(view),reducer ); + parallel_reduce("Kokkos::Sort::FindExtent", range_policy(begin, end), + Impl::min_max_functor(view), reducer); - if(result.min_val == result.max_val) return; + if (result.min_val == result.max_val) return; - BinSort - bin_sort(view,begin,end,CompType((end-begin)/2,result.min_val,result.max_val),true); + BinSort bin_sort( + view, begin, end, + CompType((end - begin) / 2, result.min_val, result.max_val), true); bin_sort.create_permute_vector(); - bin_sort.sort(view,begin,end); + bin_sort.sort(view, begin, end); } -} +} // namespace Kokkos #endif diff --git a/lib/kokkos/algorithms/unit_tests/CMakeLists.txt b/lib/kokkos/algorithms/unit_tests/CMakeLists.txt index e238b37c8e..6fb08ce2ed 100644 --- a/lib/kokkos/algorithms/unit_tests/CMakeLists.txt +++ b/lib/kokkos/algorithms/unit_tests/CMakeLists.txt @@ -1,18 +1,12 @@ -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) -INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${CMAKE_CURRENT_SOURCE_DIR}) -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../src ) +#Leave these here for now - I don't need transitive deps anyway +KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +KOKKOS_INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${CMAKE_CURRENT_SOURCE_DIR}) +KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../src ) -IF(NOT KOKKOS_HAS_TRILINOS) - IF(KOKKOS_SEPARATE_LIBS) - set(TEST_LINK_TARGETS kokkoscore) - ELSE() - set(TEST_LINK_TARGETS kokkos) - ENDIF() -ENDIF() SET(GTEST_SOURCE_DIR ${${PARENT_PACKAGE_NAME}_SOURCE_DIR}/tpls/gtest) -INCLUDE_DIRECTORIES(${GTEST_SOURCE_DIR}) +KOKKOS_INCLUDE_DIRECTORIES(${GTEST_SOURCE_DIR}) # mfh 03 Nov 2017: The gtest library used here must have a different # name than that of the gtest library built in KokkosCore. We can't @@ -20,23 +14,20 @@ INCLUDE_DIRECTORIES(${GTEST_SOURCE_DIR}) # possible to build only (e.g.,) KokkosAlgorithms tests, without # building KokkosCore tests. -SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGTEST_HAS_PTHREAD=0") -TRIBITS_ADD_LIBRARY( +KOKKOS_ADD_TEST_LIBRARY( kokkosalgorithms_gtest HEADERS ${GTEST_SOURCE_DIR}/gtest/gtest.h SOURCES ${GTEST_SOURCE_DIR}/gtest/gtest-all.cc - TESTONLY - ) +) +KOKKOS_TARGET_COMPILE_DEFINITIONS(kokkosalgorithms_gtest PUBLIC "-DGTEST_HAS_PTHREAD=0") SET(SOURCES UnitTestMain.cpp TestCuda.cpp ) -SET(LIBRARIES kokkoscore) - -IF(Kokkos_ENABLE_OpenMP) +IF(Kokkos_ENABLE_OPENMP) LIST( APPEND SOURCES TestOpenMP.cpp ) @@ -48,23 +39,19 @@ IF(Kokkos_ENABLE_HPX) ) ENDIF() -IF(Kokkos_ENABLE_Serial) +IF(Kokkos_ENABLE_SERIAL) LIST( APPEND SOURCES TestSerial.cpp ) ENDIF() -IF(Kokkos_ENABLE_Pthread) +IF(Kokkos_ENABLE_PTHREAD) LIST( APPEND SOURCES TestThreads.cpp ) ENDIF() -TRIBITS_ADD_EXECUTABLE_AND_TEST( +KOKKOS_ADD_EXECUTABLE_AND_TEST( UnitTest SOURCES ${SOURCES} - COMM serial mpi - NUM_MPI_PROCS 1 - FAIL_REGULAR_EXPRESSION " FAILED " - TESTONLYLIBS kokkosalgorithms_gtest ${TEST_LINK_TARGETS} - ) +) diff --git a/lib/kokkos/algorithms/unit_tests/TestCuda.cpp b/lib/kokkos/algorithms/unit_tests/TestCuda.cpp index 86fdccd0e7..ab727b0326 100644 --- a/lib/kokkos/algorithms/unit_tests/TestCuda.cpp +++ b/lib/kokkos/algorithms/unit_tests/TestCuda.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -57,51 +58,31 @@ namespace Test { -class cuda : public ::testing::Test { -protected: - static void SetUpTestCase() - { - } - static void TearDownTestCase() - { - } -}; - -void cuda_test_random_xorshift64( int num_draws ) -{ +void cuda_test_random_xorshift64(int num_draws) { Impl::test_random >(num_draws); } -void cuda_test_random_xorshift1024( int num_draws ) -{ +void cuda_test_random_xorshift1024(int num_draws) { Impl::test_random >(num_draws); } +#define CUDA_RANDOM_XORSHIFT64(num_draws) \ + TEST(cuda, Random_XorShift64) { cuda_test_random_xorshift64(num_draws); } -#define CUDA_RANDOM_XORSHIFT64( num_draws ) \ - TEST_F( cuda, Random_XorShift64 ) { \ - cuda_test_random_xorshift64(num_draws); \ - } - -#define CUDA_RANDOM_XORSHIFT1024( num_draws ) \ - TEST_F( cuda, Random_XorShift1024 ) { \ - cuda_test_random_xorshift1024(num_draws); \ - } +#define CUDA_RANDOM_XORSHIFT1024(num_draws) \ + TEST(cuda, Random_XorShift1024) { cuda_test_random_xorshift1024(num_draws); } -#define CUDA_SORT_UNSIGNED( size ) \ - TEST_F( cuda, SortUnsigned ) { \ - Impl::test_sort< Kokkos::Cuda, unsigned >(size); \ - } +#define CUDA_SORT_UNSIGNED(size) \ + TEST(cuda, SortUnsigned) { Impl::test_sort(size); } -CUDA_RANDOM_XORSHIFT64( 132141141 ) -CUDA_RANDOM_XORSHIFT1024( 52428813 ) +CUDA_RANDOM_XORSHIFT64(132141141) +CUDA_RANDOM_XORSHIFT1024(52428813) CUDA_SORT_UNSIGNED(171) #undef CUDA_RANDOM_XORSHIFT64 #undef CUDA_RANDOM_XORSHIFT1024 #undef CUDA_SORT_UNSIGNED -} +} // namespace Test #else void KOKKOS_ALGORITHMS_UNITTESTS_TESTCUDA_PREVENT_LINK_ERROR() {} -#endif /* #ifdef KOKKOS_ENABLE_CUDA */ - +#endif /* #ifdef KOKKOS_ENABLE_CUDA */ diff --git a/lib/kokkos/algorithms/unit_tests/TestHPX.cpp b/lib/kokkos/algorithms/unit_tests/TestHPX.cpp index e5b7dbdb7a..2981e97945 100644 --- a/lib/kokkos/algorithms/unit_tests/TestHPX.cpp +++ b/lib/kokkos/algorithms/unit_tests/TestHPX.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,7 +42,6 @@ //@HEADER */ - #include #ifdef KOKKOS_ENABLE_HPX @@ -55,42 +55,33 @@ namespace Test { -class hpx : public ::testing::Test { -protected: - static void SetUpTestCase() - { - std::cout << std::setprecision(5) << std::scientific; - } - - static void TearDownTestCase() - { +#define HPX_RANDOM_XORSHIFT64(num_draws) \ + TEST(hpx, Random_XorShift64) { \ + Impl::test_random< \ + Kokkos::Random_XorShift64_Pool >( \ + num_draws); \ } -}; -#define HPX_RANDOM_XORSHIFT64( num_draws ) \ - TEST_F( hpx, Random_XorShift64 ) { \ - Impl::test_random >(num_draws); \ +#define HPX_RANDOM_XORSHIFT1024(num_draws) \ + TEST(hpx, Random_XorShift1024) { \ + Impl::test_random< \ + Kokkos::Random_XorShift1024_Pool >( \ + num_draws); \ } -#define HPX_RANDOM_XORSHIFT1024( num_draws ) \ - TEST_F( hpx, Random_XorShift1024 ) { \ - Impl::test_random >(num_draws); \ +#define HPX_SORT_UNSIGNED(size) \ + TEST(hpx, SortUnsigned) { \ + Impl::test_sort(size); \ } -#define HPX_SORT_UNSIGNED( size ) \ - TEST_F( hpx, SortUnsigned ) { \ - Impl::test_sort< Kokkos::Experimental::HPX, unsigned >(size); \ - } - -HPX_RANDOM_XORSHIFT64( 10240000 ) -HPX_RANDOM_XORSHIFT1024( 10130144 ) +HPX_RANDOM_XORSHIFT64(10240000) +HPX_RANDOM_XORSHIFT1024(10130144) HPX_SORT_UNSIGNED(171) #undef HPX_RANDOM_XORSHIFT64 #undef HPX_RANDOM_XORSHIFT1024 #undef HPX_SORT_UNSIGNED -} // namespace test +} // namespace Test #else void KOKKOS_ALGORITHMS_UNITTESTS_TESTHPX_PREVENT_LINK_ERROR() {} #endif - diff --git a/lib/kokkos/algorithms/unit_tests/TestOpenMP.cpp b/lib/kokkos/algorithms/unit_tests/TestOpenMP.cpp index c4ddde7b7f..3a9e306014 100644 --- a/lib/kokkos/algorithms/unit_tests/TestOpenMP.cpp +++ b/lib/kokkos/algorithms/unit_tests/TestOpenMP.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,7 +42,6 @@ //@HEADER */ - #include #ifdef KOKKOS_ENABLE_OPENMP @@ -55,42 +55,31 @@ namespace Test { -class openmp : public ::testing::Test { -protected: - static void SetUpTestCase() - { - std::cout << std::setprecision(5) << std::scientific; - } - - static void TearDownTestCase() - { +#define OPENMP_RANDOM_XORSHIFT64(num_draws) \ + TEST(openmp, Random_XorShift64) { \ + Impl::test_random >( \ + num_draws); \ } -}; -#define OPENMP_RANDOM_XORSHIFT64( num_draws ) \ - TEST_F( openmp, Random_XorShift64 ) { \ - Impl::test_random >(num_draws); \ +#define OPENMP_RANDOM_XORSHIFT1024(num_draws) \ + TEST(openmp, Random_XorShift1024) { \ + Impl::test_random >( \ + num_draws); \ } -#define OPENMP_RANDOM_XORSHIFT1024( num_draws ) \ - TEST_F( openmp, Random_XorShift1024 ) { \ - Impl::test_random >(num_draws); \ +#define OPENMP_SORT_UNSIGNED(size) \ + TEST(openmp, SortUnsigned) { \ + Impl::test_sort(size); \ } -#define OPENMP_SORT_UNSIGNED( size ) \ - TEST_F( openmp, SortUnsigned ) { \ - Impl::test_sort< Kokkos::OpenMP, unsigned >(size); \ - } - -OPENMP_RANDOM_XORSHIFT64( 10240000 ) -OPENMP_RANDOM_XORSHIFT1024( 10130144 ) +OPENMP_RANDOM_XORSHIFT64(10240000) +OPENMP_RANDOM_XORSHIFT1024(10130144) OPENMP_SORT_UNSIGNED(171) #undef OPENMP_RANDOM_XORSHIFT64 #undef OPENMP_RANDOM_XORSHIFT1024 #undef OPENMP_SORT_UNSIGNED -} // namespace test +} // namespace Test #else void KOKKOS_ALGORITHMS_UNITTESTS_TESTOPENMP_PREVENT_LINK_ERROR() {} #endif - diff --git a/lib/kokkos/algorithms/unit_tests/TestROCm.cpp b/lib/kokkos/algorithms/unit_tests/TestROCm.cpp index 15179509bb..29814cca3e 100644 --- a/lib/kokkos/algorithms/unit_tests/TestROCm.cpp +++ b/lib/kokkos/algorithms/unit_tests/TestROCm.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -57,52 +58,35 @@ namespace Test { -class rocm : public ::testing::Test { -protected: - static void SetUpTestCase() - { - std::cout << std::setprecision(5) << std::scientific; - } - static void TearDownTestCase() - { - } -}; - -void rocm_test_random_xorshift64( int num_draws ) -{ - Impl::test_random >(num_draws); +void rocm_test_random_xorshift64(int num_draws) { + Impl::test_random< + Kokkos::Random_XorShift64_Pool >(num_draws); } -void rocm_test_random_xorshift1024( int num_draws ) -{ - Impl::test_random >(num_draws); +void rocm_test_random_xorshift1024(int num_draws) { + Impl::test_random< + Kokkos::Random_XorShift1024_Pool >(num_draws); } +#define ROCM_RANDOM_XORSHIFT64(num_draws) \ + TEST(rocm, Random_XorShift64) { rocm_test_random_xorshift64(num_draws); } -#define ROCM_RANDOM_XORSHIFT64( num_draws ) \ - TEST_F( rocm, Random_XorShift64 ) { \ - rocm_test_random_xorshift64(num_draws); \ - } - -#define ROCM_RANDOM_XORSHIFT1024( num_draws ) \ - TEST_F( rocm, Random_XorShift1024 ) { \ - rocm_test_random_xorshift1024(num_draws); \ - } +#define ROCM_RANDOM_XORSHIFT1024(num_draws) \ + TEST(rocm, Random_XorShift1024) { rocm_test_random_xorshift1024(num_draws); } -#define ROCM_SORT_UNSIGNED( size ) \ - TEST_F( rocm, SortUnsigned ) { \ - Impl::test_sort< Kokkos::Experimental::ROCm, unsigned >(size); \ +#define ROCM_SORT_UNSIGNED(size) \ + TEST(rocm, SortUnsigned) { \ + Impl::test_sort(size); \ } -ROCM_RANDOM_XORSHIFT64( 132141141 ) -ROCM_RANDOM_XORSHIFT1024( 52428813 ) +ROCM_RANDOM_XORSHIFT64(132141141) +ROCM_RANDOM_XORSHIFT1024(52428813) ROCM_SORT_UNSIGNED(171) #undef ROCM_RANDOM_XORSHIFT64 #undef ROCM_RANDOM_XORSHIFT1024 #undef ROCM_SORT_UNSIGNED -} +} // namespace Test #else void KOKKOS_ALGORITHMS_UNITTESTS_TESTROCM_PREVENT_LINK_ERROR() {} -#endif /* #ifdef KOKKOS_ENABLE_ROCM */ - +#endif /* #ifdef KOKKOS_ENABLE_ROCM */ diff --git a/lib/kokkos/algorithms/unit_tests/TestRandom.hpp b/lib/kokkos/algorithms/unit_tests/TestRandom.hpp index 73bd416f2a..bc55ebfad3 100644 --- a/lib/kokkos/algorithms/unit_tests/TestRandom.hpp +++ b/lib/kokkos/algorithms/unit_tests/TestRandom.hpp @@ -1,10 +1,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -22,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -54,18 +55,19 @@ namespace Test { -namespace Impl{ +namespace Impl { // This test runs the random number generators and uses some statistic tests to // check the 'goodness' of the random numbers: // (i) mean: the mean is expected to be 0.5*RAND_MAX // (ii) variance: the variance is 1/3*mean*mean // (iii) covariance: the covariance is 0 -// (iv) 1-tupledistr: the mean, variance and covariance of a 1D Histrogram of random numbers -// (v) 3-tupledistr: the mean, variance and covariance of a 3D Histrogram of random numbers +// (iv) 1-tupledistr: the mean, variance and covariance of a 1D Histrogram +// of random numbers (v) 3-tupledistr: the mean, variance and covariance of +// a 3D Histrogram of random numbers #define HIST_DIM3D 24 -#define HIST_DIM1D (HIST_DIM3D*HIST_DIM3D*HIST_DIM3D) +#define HIST_DIM1D (HIST_DIM3D * HIST_DIM3D * HIST_DIM3D) struct RandomProperties { uint64_t count; @@ -77,37 +79,37 @@ struct RandomProperties { KOKKOS_INLINE_FUNCTION RandomProperties() { - count = 0; - mean = 0.0; - variance = 0.0; + count = 0; + mean = 0.0; + variance = 0.0; covariance = 0.0; - min = 1e64; - max = -1e64; + min = 1e64; + max = -1e64; } KOKKOS_INLINE_FUNCTION RandomProperties& operator+=(const RandomProperties& add) { - count += add.count; - mean += add.mean; - variance += add.variance; + count += add.count; + mean += add.mean; + variance += add.variance; covariance += add.covariance; - min = add.minmax?add.max:max; + min = add.min < min ? add.min : min; + max = add.max > max ? add.max : max; return *this; } KOKKOS_INLINE_FUNCTION void operator+=(const volatile RandomProperties& add) volatile { - count += add.count; - mean += add.mean; - variance += add.variance; + count += add.count; + mean += add.mean; + variance += add.variance; covariance += add.covariance; - min = add.minmax?add.max:max; + min = add.min < min ? add.min : min; + max = add.max > max ? add.max : max; } }; -template +template struct test_random_functor { typedef typename GeneratorPool::generator_type rnd_type; @@ -123,38 +125,40 @@ struct test_random_functor { // implementations might violate this upper bound, due to rounding // error. Just in case, we leave an extra space at the end of each // dimension, in the View types below. - typedef Kokkos::View type_1d; + typedef Kokkos::View + type_1d; type_1d density_1d; - typedef Kokkos::View type_3d; + typedef Kokkos::View + type_3d; type_3d density_3d; - test_random_functor (GeneratorPool rand_pool_, type_1d d1d, type_3d d3d) : - rand_pool (rand_pool_), - mean (0.5*Kokkos::rand::max ()), - density_1d (d1d), - density_3d (d3d) - {} + test_random_functor(GeneratorPool rand_pool_, type_1d d1d, type_3d d3d) + : rand_pool(rand_pool_), + mean(0.5 * Kokkos::rand::max()), + density_1d(d1d), + density_3d(d3d) {} KOKKOS_INLINE_FUNCTION - void operator() (int i, RandomProperties& prop) const { + void operator()(int i, RandomProperties& prop) const { using Kokkos::atomic_fetch_add; rnd_type rand_gen = rand_pool.get_state(); for (int k = 0; k < 1024; ++k) { - const Scalar tmp = Kokkos::rand::draw(rand_gen); + const Scalar tmp = Kokkos::rand::draw(rand_gen); prop.count++; prop.mean += tmp; - prop.variance += (tmp-mean)*(tmp-mean); - const Scalar tmp2 = Kokkos::rand::draw(rand_gen); + prop.variance += (tmp - mean) * (tmp - mean); + const Scalar tmp2 = Kokkos::rand::draw(rand_gen); prop.count++; prop.mean += tmp2; - prop.variance += (tmp2-mean)*(tmp2-mean); - prop.covariance += (tmp-mean)*(tmp2-mean); - const Scalar tmp3 = Kokkos::rand::draw(rand_gen); + prop.variance += (tmp2 - mean) * (tmp2 - mean); + prop.covariance += (tmp - mean) * (tmp2 - mean); + const Scalar tmp3 = Kokkos::rand::draw(rand_gen); prop.count++; prop.mean += tmp3; - prop.variance += (tmp3-mean)*(tmp3-mean); - prop.covariance += (tmp2-mean)*(tmp3-mean); + prop.variance += (tmp3 - mean) * (tmp3 - mean); + prop.covariance += (tmp2 - mean) * (tmp3 - mean); // NOTE (mfh 03 Nov 2014): Kokkos::rand::max() is supposed to // define an exclusive upper bound on the range of random @@ -169,26 +173,32 @@ struct test_random_functor { // returns values of max(), the histograms will still catch this // indirectly, since none of the other values will be filled in. - const Scalar theMax = Kokkos::rand::max (); - - const uint64_t ind1_1d = static_cast (1.0 * HIST_DIM1D * tmp / theMax); - const uint64_t ind2_1d = static_cast (1.0 * HIST_DIM1D * tmp2 / theMax); - const uint64_t ind3_1d = static_cast (1.0 * HIST_DIM1D * tmp3 / theMax); - - const uint64_t ind1_3d = static_cast (1.0 * HIST_DIM3D * tmp / theMax); - const uint64_t ind2_3d = static_cast (1.0 * HIST_DIM3D * tmp2 / theMax); - const uint64_t ind3_3d = static_cast (1.0 * HIST_DIM3D * tmp3 / theMax); - - atomic_fetch_add (&density_1d(ind1_1d), 1); - atomic_fetch_add (&density_1d(ind2_1d), 1); - atomic_fetch_add (&density_1d(ind3_1d), 1); - atomic_fetch_add (&density_3d(ind1_3d, ind2_3d, ind3_3d), 1); + const Scalar theMax = Kokkos::rand::max(); + + const uint64_t ind1_1d = + static_cast(1.0 * HIST_DIM1D * tmp / theMax); + const uint64_t ind2_1d = + static_cast(1.0 * HIST_DIM1D * tmp2 / theMax); + const uint64_t ind3_1d = + static_cast(1.0 * HIST_DIM1D * tmp3 / theMax); + + const uint64_t ind1_3d = + static_cast(1.0 * HIST_DIM3D * tmp / theMax); + const uint64_t ind2_3d = + static_cast(1.0 * HIST_DIM3D * tmp2 / theMax); + const uint64_t ind3_3d = + static_cast(1.0 * HIST_DIM3D * tmp3 / theMax); + + atomic_fetch_add(&density_1d(ind1_1d), 1); + atomic_fetch_add(&density_1d(ind2_1d), 1); + atomic_fetch_add(&density_1d(ind3_1d), 1); + atomic_fetch_add(&density_3d(ind1_3d, ind2_3d, ind3_3d), 1); } rand_pool.free_state(rand_gen); } }; -template +template struct test_histogram1d_functor { typedef RandomProperties value_type; typedef typename DeviceType::execution_space execution_space; @@ -200,34 +210,29 @@ struct test_histogram1d_functor { // implementations might violate this upper bound, due to rounding // error. Just in case, we leave an extra space at the end of each // dimension, in the View type below. - typedef Kokkos::View type_1d; + typedef Kokkos::View type_1d; type_1d density_1d; double mean; - test_histogram1d_functor (type_1d d1d, int num_draws) : - density_1d (d1d), - mean (1.0*num_draws/HIST_DIM1D*3) - { - } + test_histogram1d_functor(type_1d d1d, int num_draws) + : density_1d(d1d), mean(1.0 * num_draws / HIST_DIM1D * 3) {} - KOKKOS_INLINE_FUNCTION void - operator() (const typename memory_space::size_type i, - RandomProperties& prop) const - { + KOKKOS_INLINE_FUNCTION void operator()( + const typename memory_space::size_type i, RandomProperties& prop) const { typedef typename memory_space::size_type size_type; const double count = density_1d(i); prop.mean += count; prop.variance += 1.0 * (count - mean) * (count - mean); - //prop.covariance += 1.0*count*count; + // prop.covariance += 1.0*count*count; prop.min = count < prop.min ? count : prop.min; prop.max = count > prop.max ? count : prop.max; - if (i < static_cast (HIST_DIM1D-1)) { - prop.covariance += (count - mean) * (density_1d(i+1) - mean); + if (i < static_cast(HIST_DIM1D - 1)) { + prop.covariance += (count - mean) * (density_1d(i + 1) - mean); } } }; -template +template struct test_histogram3d_functor { typedef RandomProperties value_type; typedef typename DeviceType::execution_space execution_space; @@ -239,29 +244,28 @@ struct test_histogram3d_functor { // implementations might violate this upper bound, due to rounding // error. Just in case, we leave an extra space at the end of each // dimension, in the View type below. - typedef Kokkos::View type_3d; + typedef Kokkos::View + type_3d; type_3d density_3d; double mean; - test_histogram3d_functor (type_3d d3d, int num_draws) : - density_3d (d3d), - mean (1.0*num_draws/HIST_DIM1D) - {} + test_histogram3d_functor(type_3d d3d, int num_draws) + : density_3d(d3d), mean(1.0 * num_draws / HIST_DIM1D) {} - KOKKOS_INLINE_FUNCTION void - operator() (const typename memory_space::size_type i, - RandomProperties& prop) const - { + KOKKOS_INLINE_FUNCTION void operator()( + const typename memory_space::size_type i, RandomProperties& prop) const { typedef typename memory_space::size_type size_type; - const double count = density_3d(i/(HIST_DIM3D*HIST_DIM3D), - (i % (HIST_DIM3D*HIST_DIM3D))/HIST_DIM3D, - i % HIST_DIM3D); + const double count = density_3d( + i / (HIST_DIM3D * HIST_DIM3D), + (i % (HIST_DIM3D * HIST_DIM3D)) / HIST_DIM3D, i % HIST_DIM3D); prop.mean += count; prop.variance += (count - mean) * (count - mean); - if (i < static_cast (HIST_DIM1D-1)) { - const double count_next = density_3d((i+1)/(HIST_DIM3D*HIST_DIM3D), - ((i+1)%(HIST_DIM3D*HIST_DIM3D))/HIST_DIM3D, - (i+1)%HIST_DIM3D); + if (i < static_cast(HIST_DIM1D - 1)) { + const double count_next = + density_3d((i + 1) / (HIST_DIM3D * HIST_DIM3D), + ((i + 1) % (HIST_DIM3D * HIST_DIM3D)) / HIST_DIM3D, + (i + 1) % HIST_DIM3D); prop.covariance += (count - mean) * (count_next - mean); } } @@ -270,212 +274,223 @@ struct test_histogram3d_functor { // // Templated test that uses the above functors. // -template +template struct test_random_scalar { typedef typename RandomGenerator::generator_type rnd_type; - int pass_mean,pass_var,pass_covar; - int pass_hist1d_mean,pass_hist1d_var,pass_hist1d_covar; - int pass_hist3d_mean,pass_hist3d_var,pass_hist3d_covar; + int pass_mean, pass_var, pass_covar; + int pass_hist1d_mean, pass_hist1d_var, pass_hist1d_covar; + int pass_hist3d_mean, pass_hist3d_var, pass_hist3d_covar; - test_random_scalar (typename test_random_functor::type_1d& density_1d, - typename test_random_functor::type_3d& density_3d, - RandomGenerator& pool, - unsigned int num_draws) - { + test_random_scalar( + typename test_random_functor::type_1d& density_1d, + typename test_random_functor::type_3d& density_3d, + RandomGenerator& pool, unsigned int num_draws) { + using Kokkos::parallel_reduce; using std::cout; using std::endl; - using Kokkos::parallel_reduce; { cout << " -- Testing randomness properties" << endl; RandomProperties result; typedef test_random_functor functor_type; - parallel_reduce (num_draws/1024, functor_type (pool, density_1d, density_3d), result); - - //printf("Result: %lf %lf %lf\n",result.mean/num_draws/3,result.variance/num_draws/3,result.covariance/num_draws/2); - double tolerance = 1.6*std::sqrt(1.0/num_draws); - double mean_expect = 0.5*Kokkos::rand::max(); - double variance_expect = 1.0/3.0*mean_expect*mean_expect; - double mean_eps = mean_expect/(result.mean/num_draws/3)-1.0; - double variance_eps = variance_expect/(result.variance/num_draws/3)-1.0; - double covariance_eps = result.covariance/num_draws/2/variance_expect; - pass_mean = ((-tolerance < mean_eps) && - ( tolerance > mean_eps)) ? 1:0; - pass_var = ((-1.5*tolerance < variance_eps) && - ( 1.5*tolerance > variance_eps)) ? 1:0; - pass_covar = ((-2.0*tolerance < covariance_eps) && - ( 2.0*tolerance > covariance_eps)) ? 1:0; - cout << "Pass: " << pass_mean - << " " << pass_var - << " " << mean_eps - << " " << variance_eps - << " " << covariance_eps - << " || " << tolerance << endl; + parallel_reduce(num_draws / 1024, + functor_type(pool, density_1d, density_3d), result); + + // printf("Result: %lf %lf + // %lf\n",result.mean/num_draws/3,result.variance/num_draws/3,result.covariance/num_draws/2); + double tolerance = 1.6 * std::sqrt(1.0 / num_draws); + double mean_expect = 0.5 * Kokkos::rand::max(); + double variance_expect = 1.0 / 3.0 * mean_expect * mean_expect; + double mean_eps = mean_expect / (result.mean / num_draws / 3) - 1.0; + double variance_eps = + variance_expect / (result.variance / num_draws / 3) - 1.0; + double covariance_eps = + result.covariance / num_draws / 2 / variance_expect; + pass_mean = ((-tolerance < mean_eps) && (tolerance > mean_eps)) ? 1 : 0; + pass_var = ((-1.5 * tolerance < variance_eps) && + (1.5 * tolerance > variance_eps)) + ? 1 + : 0; + pass_covar = ((-2.0 * tolerance < covariance_eps) && + (2.0 * tolerance > covariance_eps)) + ? 1 + : 0; + cout << "Pass: " << pass_mean << " " << pass_var << " " << mean_eps << " " + << variance_eps << " " << covariance_eps << " || " << tolerance + << endl; } { cout << " -- Testing 1-D histogram" << endl; RandomProperties result; - typedef test_histogram1d_functor functor_type; - parallel_reduce (HIST_DIM1D, functor_type (density_1d, num_draws), result); - - double tolerance = 6*std::sqrt(1.0/HIST_DIM1D); - double mean_expect = 1.0*num_draws*3/HIST_DIM1D; - double variance_expect = 1.0*num_draws*3/HIST_DIM1D*(1.0-1.0/HIST_DIM1D); - double covariance_expect = -1.0*num_draws*3/HIST_DIM1D/HIST_DIM1D; - double mean_eps = mean_expect/(result.mean/HIST_DIM1D)-1.0; - double variance_eps = variance_expect/(result.variance/HIST_DIM1D)-1.0; - double covariance_eps = (result.covariance/HIST_DIM1D - covariance_expect)/mean_expect; - pass_hist1d_mean = ((-0.0001 < mean_eps) && - ( 0.0001 > mean_eps)) ? 1:0; - pass_hist1d_var = ((-0.07 < variance_eps) && - ( 0.07 > variance_eps)) ? 1:0; - pass_hist1d_covar = ((-0.06 < covariance_eps) && - ( 0.06 > covariance_eps)) ? 1:0; - - cout << "Density 1D: " << mean_eps - << " " << variance_eps - << " " << (result.covariance/HIST_DIM1D/HIST_DIM1D) - << " || " << tolerance - << " " << result.min - << " " << result.max - << " || " << result.variance/HIST_DIM1D - << " " << 1.0*num_draws*3/HIST_DIM1D*(1.0-1.0/HIST_DIM1D) - << " || " << result.covariance/HIST_DIM1D - << " " << -1.0*num_draws*3/HIST_DIM1D/HIST_DIM1D - << endl; + typedef test_histogram1d_functor + functor_type; + parallel_reduce(HIST_DIM1D, functor_type(density_1d, num_draws), result); + + double tolerance = 6 * std::sqrt(1.0 / HIST_DIM1D); + double mean_expect = 1.0 * num_draws * 3 / HIST_DIM1D; + double variance_expect = + 1.0 * num_draws * 3 / HIST_DIM1D * (1.0 - 1.0 / HIST_DIM1D); + double covariance_expect = -1.0 * num_draws * 3 / HIST_DIM1D / HIST_DIM1D; + double mean_eps = mean_expect / (result.mean / HIST_DIM1D) - 1.0; + double variance_eps = + variance_expect / (result.variance / HIST_DIM1D) - 1.0; + double covariance_eps = + (result.covariance / HIST_DIM1D - covariance_expect) / mean_expect; + pass_hist1d_mean = ((-0.0001 < mean_eps) && (0.0001 > mean_eps)) ? 1 : 0; + pass_hist1d_var = + ((-0.07 < variance_eps) && (0.07 > variance_eps)) ? 1 : 0; + pass_hist1d_covar = + ((-0.06 < covariance_eps) && (0.06 > covariance_eps)) ? 1 : 0; + + cout << "Density 1D: " << mean_eps << " " << variance_eps << " " + << (result.covariance / HIST_DIM1D / HIST_DIM1D) << " || " + << tolerance << " " << result.min << " " << result.max << " || " + << result.variance / HIST_DIM1D << " " + << 1.0 * num_draws * 3 / HIST_DIM1D * (1.0 - 1.0 / HIST_DIM1D) + << " || " << result.covariance / HIST_DIM1D << " " + << -1.0 * num_draws * 3 / HIST_DIM1D / HIST_DIM1D << endl; } { cout << " -- Testing 3-D histogram" << endl; RandomProperties result; - typedef test_histogram3d_functor functor_type; - parallel_reduce (HIST_DIM1D, functor_type (density_3d, num_draws), result); - - double tolerance = 6*std::sqrt(1.0/HIST_DIM1D); - double mean_expect = 1.0*num_draws/HIST_DIM1D; - double variance_expect = 1.0*num_draws/HIST_DIM1D*(1.0-1.0/HIST_DIM1D); - double covariance_expect = -1.0*num_draws/HIST_DIM1D/HIST_DIM1D; - double mean_eps = mean_expect/(result.mean/HIST_DIM1D)-1.0; - double variance_eps = variance_expect/(result.variance/HIST_DIM1D)-1.0; - double covariance_eps = (result.covariance/HIST_DIM1D - covariance_expect)/mean_expect; - pass_hist3d_mean = ((-tolerance < mean_eps) && - ( tolerance > mean_eps)) ? 1:0; - pass_hist3d_var = ((-1.2*tolerance < variance_eps) && - ( 1.2*tolerance > variance_eps)) ? 1:0; - pass_hist3d_covar = ((-tolerance < covariance_eps) && - ( tolerance > covariance_eps)) ? 1:0; - - cout << "Density 3D: " << mean_eps - << " " << variance_eps - << " " << result.covariance/HIST_DIM1D/HIST_DIM1D - << " || " << tolerance - << " " << result.min - << " " << result.max << endl; + typedef test_histogram3d_functor + functor_type; + parallel_reduce(HIST_DIM1D, functor_type(density_3d, num_draws), result); + + double tolerance = 6 * std::sqrt(1.0 / HIST_DIM1D); + double mean_expect = 1.0 * num_draws / HIST_DIM1D; + double variance_expect = + 1.0 * num_draws / HIST_DIM1D * (1.0 - 1.0 / HIST_DIM1D); + double covariance_expect = -1.0 * num_draws / HIST_DIM1D / HIST_DIM1D; + double mean_eps = mean_expect / (result.mean / HIST_DIM1D) - 1.0; + double variance_eps = + variance_expect / (result.variance / HIST_DIM1D) - 1.0; + double covariance_eps = + (result.covariance / HIST_DIM1D - covariance_expect) / mean_expect; + pass_hist3d_mean = + ((-tolerance < mean_eps) && (tolerance > mean_eps)) ? 1 : 0; + pass_hist3d_var = ((-1.2 * tolerance < variance_eps) && + (1.2 * tolerance > variance_eps)) + ? 1 + : 0; + pass_hist3d_covar = + ((-tolerance < covariance_eps) && (tolerance > covariance_eps)) ? 1 + : 0; + + cout << "Density 3D: " << mean_eps << " " << variance_eps << " " + << result.covariance / HIST_DIM1D / HIST_DIM1D << " || " << tolerance + << " " << result.min << " " << result.max << endl; } } }; template -void test_random(unsigned int num_draws) -{ +void test_random(unsigned int num_draws) { using std::cout; using std::endl; - typename test_random_functor::type_1d density_1d("D1d"); - typename test_random_functor::type_3d density_3d("D3d"); + typename test_random_functor::type_1d density_1d("D1d"); + typename test_random_functor::type_3d density_3d("D3d"); - - uint64_t ticks = std::chrono::high_resolution_clock::now().time_since_epoch().count(); + uint64_t ticks = + std::chrono::high_resolution_clock::now().time_since_epoch().count(); cout << "Test Seed:" << ticks << endl; RandomGenerator pool(ticks); cout << "Test Scalar=int" << endl; - test_random_scalar test_int(density_1d,density_3d,pool,num_draws); - ASSERT_EQ( test_int.pass_mean,1); - ASSERT_EQ( test_int.pass_var,1); - ASSERT_EQ( test_int.pass_covar,1); - ASSERT_EQ( test_int.pass_hist1d_mean,1); - ASSERT_EQ( test_int.pass_hist1d_var,1); - ASSERT_EQ( test_int.pass_hist1d_covar,1); - ASSERT_EQ( test_int.pass_hist3d_mean,1); - ASSERT_EQ( test_int.pass_hist3d_var,1); - ASSERT_EQ( test_int.pass_hist3d_covar,1); - deep_copy(density_1d,0); - deep_copy(density_3d,0); + test_random_scalar test_int(density_1d, density_3d, + pool, num_draws); + ASSERT_EQ(test_int.pass_mean, 1); + ASSERT_EQ(test_int.pass_var, 1); + ASSERT_EQ(test_int.pass_covar, 1); + ASSERT_EQ(test_int.pass_hist1d_mean, 1); + ASSERT_EQ(test_int.pass_hist1d_var, 1); + ASSERT_EQ(test_int.pass_hist1d_covar, 1); + ASSERT_EQ(test_int.pass_hist3d_mean, 1); + ASSERT_EQ(test_int.pass_hist3d_var, 1); + ASSERT_EQ(test_int.pass_hist3d_covar, 1); + deep_copy(density_1d, 0); + deep_copy(density_3d, 0); cout << "Test Scalar=unsigned int" << endl; - test_random_scalar test_uint(density_1d,density_3d,pool,num_draws); - ASSERT_EQ( test_uint.pass_mean,1); - ASSERT_EQ( test_uint.pass_var,1); - ASSERT_EQ( test_uint.pass_covar,1); - ASSERT_EQ( test_uint.pass_hist1d_mean,1); - ASSERT_EQ( test_uint.pass_hist1d_var,1); - ASSERT_EQ( test_uint.pass_hist1d_covar,1); - ASSERT_EQ( test_uint.pass_hist3d_mean,1); - ASSERT_EQ( test_uint.pass_hist3d_var,1); - ASSERT_EQ( test_uint.pass_hist3d_covar,1); - deep_copy(density_1d,0); - deep_copy(density_3d,0); + test_random_scalar test_uint( + density_1d, density_3d, pool, num_draws); + ASSERT_EQ(test_uint.pass_mean, 1); + ASSERT_EQ(test_uint.pass_var, 1); + ASSERT_EQ(test_uint.pass_covar, 1); + ASSERT_EQ(test_uint.pass_hist1d_mean, 1); + ASSERT_EQ(test_uint.pass_hist1d_var, 1); + ASSERT_EQ(test_uint.pass_hist1d_covar, 1); + ASSERT_EQ(test_uint.pass_hist3d_mean, 1); + ASSERT_EQ(test_uint.pass_hist3d_var, 1); + ASSERT_EQ(test_uint.pass_hist3d_covar, 1); + deep_copy(density_1d, 0); + deep_copy(density_3d, 0); cout << "Test Scalar=int64_t" << endl; - test_random_scalar test_int64(density_1d,density_3d,pool,num_draws); - ASSERT_EQ( test_int64.pass_mean,1); - ASSERT_EQ( test_int64.pass_var,1); - ASSERT_EQ( test_int64.pass_covar,1); - ASSERT_EQ( test_int64.pass_hist1d_mean,1); - ASSERT_EQ( test_int64.pass_hist1d_var,1); - ASSERT_EQ( test_int64.pass_hist1d_covar,1); - ASSERT_EQ( test_int64.pass_hist3d_mean,1); - ASSERT_EQ( test_int64.pass_hist3d_var,1); - ASSERT_EQ( test_int64.pass_hist3d_covar,1); - deep_copy(density_1d,0); - deep_copy(density_3d,0); + test_random_scalar test_int64( + density_1d, density_3d, pool, num_draws); + ASSERT_EQ(test_int64.pass_mean, 1); + ASSERT_EQ(test_int64.pass_var, 1); + ASSERT_EQ(test_int64.pass_covar, 1); + ASSERT_EQ(test_int64.pass_hist1d_mean, 1); + ASSERT_EQ(test_int64.pass_hist1d_var, 1); + ASSERT_EQ(test_int64.pass_hist1d_covar, 1); + ASSERT_EQ(test_int64.pass_hist3d_mean, 1); + ASSERT_EQ(test_int64.pass_hist3d_var, 1); + ASSERT_EQ(test_int64.pass_hist3d_covar, 1); + deep_copy(density_1d, 0); + deep_copy(density_3d, 0); cout << "Test Scalar=uint64_t" << endl; - test_random_scalar test_uint64(density_1d,density_3d,pool,num_draws); - ASSERT_EQ( test_uint64.pass_mean,1); - ASSERT_EQ( test_uint64.pass_var,1); - ASSERT_EQ( test_uint64.pass_covar,1); - ASSERT_EQ( test_uint64.pass_hist1d_mean,1); - ASSERT_EQ( test_uint64.pass_hist1d_var,1); - ASSERT_EQ( test_uint64.pass_hist1d_covar,1); - ASSERT_EQ( test_uint64.pass_hist3d_mean,1); - ASSERT_EQ( test_uint64.pass_hist3d_var,1); - ASSERT_EQ( test_uint64.pass_hist3d_covar,1); - deep_copy(density_1d,0); - deep_copy(density_3d,0); + test_random_scalar test_uint64( + density_1d, density_3d, pool, num_draws); + ASSERT_EQ(test_uint64.pass_mean, 1); + ASSERT_EQ(test_uint64.pass_var, 1); + ASSERT_EQ(test_uint64.pass_covar, 1); + ASSERT_EQ(test_uint64.pass_hist1d_mean, 1); + ASSERT_EQ(test_uint64.pass_hist1d_var, 1); + ASSERT_EQ(test_uint64.pass_hist1d_covar, 1); + ASSERT_EQ(test_uint64.pass_hist3d_mean, 1); + ASSERT_EQ(test_uint64.pass_hist3d_var, 1); + ASSERT_EQ(test_uint64.pass_hist3d_covar, 1); + deep_copy(density_1d, 0); + deep_copy(density_3d, 0); cout << "Test Scalar=float" << endl; - test_random_scalar test_float(density_1d,density_3d,pool,num_draws); - ASSERT_EQ( test_float.pass_mean,1); - ASSERT_EQ( test_float.pass_var,1); - ASSERT_EQ( test_float.pass_covar,1); - ASSERT_EQ( test_float.pass_hist1d_mean,1); - ASSERT_EQ( test_float.pass_hist1d_var,1); - ASSERT_EQ( test_float.pass_hist1d_covar,1); - ASSERT_EQ( test_float.pass_hist3d_mean,1); - ASSERT_EQ( test_float.pass_hist3d_var,1); - ASSERT_EQ( test_float.pass_hist3d_covar,1); - deep_copy(density_1d,0); - deep_copy(density_3d,0); + test_random_scalar test_float(density_1d, density_3d, + pool, num_draws); + ASSERT_EQ(test_float.pass_mean, 1); + ASSERT_EQ(test_float.pass_var, 1); + ASSERT_EQ(test_float.pass_covar, 1); + ASSERT_EQ(test_float.pass_hist1d_mean, 1); + ASSERT_EQ(test_float.pass_hist1d_var, 1); + ASSERT_EQ(test_float.pass_hist1d_covar, 1); + ASSERT_EQ(test_float.pass_hist3d_mean, 1); + ASSERT_EQ(test_float.pass_hist3d_var, 1); + ASSERT_EQ(test_float.pass_hist3d_covar, 1); + deep_copy(density_1d, 0); + deep_copy(density_3d, 0); cout << "Test Scalar=double" << endl; - test_random_scalar test_double(density_1d,density_3d,pool,num_draws); - ASSERT_EQ( test_double.pass_mean,1); - ASSERT_EQ( test_double.pass_var,1); - ASSERT_EQ( test_double.pass_covar,1); - ASSERT_EQ( test_double.pass_hist1d_mean,1); - ASSERT_EQ( test_double.pass_hist1d_var,1); - ASSERT_EQ( test_double.pass_hist1d_covar,1); - ASSERT_EQ( test_double.pass_hist3d_mean,1); - ASSERT_EQ( test_double.pass_hist3d_var,1); - ASSERT_EQ( test_double.pass_hist3d_covar,1); -} + test_random_scalar test_double( + density_1d, density_3d, pool, num_draws); + ASSERT_EQ(test_double.pass_mean, 1); + ASSERT_EQ(test_double.pass_var, 1); + ASSERT_EQ(test_double.pass_covar, 1); + ASSERT_EQ(test_double.pass_hist1d_mean, 1); + ASSERT_EQ(test_double.pass_hist1d_var, 1); + ASSERT_EQ(test_double.pass_hist1d_covar, 1); + ASSERT_EQ(test_double.pass_hist3d_mean, 1); + ASSERT_EQ(test_double.pass_hist3d_var, 1); + ASSERT_EQ(test_double.pass_hist3d_covar, 1); } +} // namespace Impl -} // namespace Test +} // namespace Test -#endif //KOKKOS_TEST_UNORDERED_MAP_HPP +#endif // KOKKOS_TEST_UNORDERED_MAP_HPP diff --git a/lib/kokkos/algorithms/unit_tests/TestSerial.cpp b/lib/kokkos/algorithms/unit_tests/TestSerial.cpp index 9cf998f773..2eacdc2677 100644 --- a/lib/kokkos/algorithms/unit_tests/TestSerial.cpp +++ b/lib/kokkos/algorithms/unit_tests/TestSerial.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -52,49 +53,36 @@ #include #include - //---------------------------------------------------------------------------- - namespace Test { -class serial : public ::testing::Test { -protected: - static void SetUpTestCase() - { - } - - static void TearDownTestCase () - { +#define SERIAL_RANDOM_XORSHIFT64(num_draws) \ + TEST(serial, Random_XorShift64) { \ + Impl::test_random >( \ + num_draws); \ } -}; -#define SERIAL_RANDOM_XORSHIFT64( num_draws ) \ - TEST_F( serial, Random_XorShift64 ) { \ - Impl::test_random >(num_draws); \ +#define SERIAL_RANDOM_XORSHIFT1024(num_draws) \ + TEST(serial, Random_XorShift1024) { \ + Impl::test_random >( \ + num_draws); \ } -#define SERIAL_RANDOM_XORSHIFT1024( num_draws ) \ - TEST_F( serial, Random_XorShift1024 ) { \ - Impl::test_random >(num_draws); \ +#define SERIAL_SORT_UNSIGNED(size) \ + TEST(serial, SortUnsigned) { \ + Impl::test_sort(size); \ } -#define SERIAL_SORT_UNSIGNED( size ) \ - TEST_F( serial, SortUnsigned ) { \ - Impl::test_sort< Kokkos::Serial, unsigned >(size); \ - } - -SERIAL_RANDOM_XORSHIFT64( 10240000 ) -SERIAL_RANDOM_XORSHIFT1024( 10130144 ) +SERIAL_RANDOM_XORSHIFT64(10240000) +SERIAL_RANDOM_XORSHIFT1024(10130144) SERIAL_SORT_UNSIGNED(171) #undef SERIAL_RANDOM_XORSHIFT64 #undef SERIAL_RANDOM_XORSHIFT1024 #undef SERIAL_SORT_UNSIGNED -} // namespace Test +} // namespace Test #else void KOKKOS_ALGORITHMS_UNITTESTS_TESTSERIAL_PREVENT_LINK_ERROR() {} -#endif // KOKKOS_ENABLE_SERIAL - - +#endif // KOKKOS_ENABLE_SERIAL diff --git a/lib/kokkos/algorithms/unit_tests/TestSort.hpp b/lib/kokkos/algorithms/unit_tests/TestSort.hpp index 5fd7f09b50..310a93c93d 100644 --- a/lib/kokkos/algorithms/unit_tests/TestSort.hpp +++ b/lib/kokkos/algorithms/unit_tests/TestSort.hpp @@ -1,10 +1,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -22,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -43,235 +44,248 @@ #define KOKKOS_ALGORITHMS_UNITTESTS_TESTSORT_HPP #include -#include -#include -#include -#include +#include +#include +#include +#include namespace Test { -namespace Impl{ +namespace Impl { -template +template struct is_sorted_struct { typedef unsigned int value_type; typedef ExecutionSpace execution_space; - Kokkos::View keys; + Kokkos::View keys; - is_sorted_struct(Kokkos::View keys_):keys(keys_) {} + is_sorted_struct(Kokkos::View keys_) : keys(keys_) {} KOKKOS_INLINE_FUNCTION - void operator() (int i, unsigned int& count) const { - if(keys(i)>keys(i+1)) count++; + void operator()(int i, unsigned int& count) const { + if (keys(i) > keys(i + 1)) count++; } }; -template +template struct sum { typedef double value_type; typedef ExecutionSpace execution_space; - Kokkos::View keys; + Kokkos::View keys; - sum(Kokkos::View keys_):keys(keys_) {} + sum(Kokkos::View keys_) : keys(keys_) {} KOKKOS_INLINE_FUNCTION - void operator() (int i, double& count) const { - count+=keys(i); - } + void operator()(int i, double& count) const { count += keys(i); } }; -template +template struct bin3d_is_sorted_struct { typedef unsigned int value_type; typedef ExecutionSpace execution_space; - Kokkos::View keys; + Kokkos::View keys; int max_bins; Scalar min; Scalar max; - bin3d_is_sorted_struct(Kokkos::View keys_,int max_bins_,Scalar min_,Scalar max_): - keys(keys_),max_bins(max_bins_),min(min_),max(max_) { - } + bin3d_is_sorted_struct(Kokkos::View keys_, + int max_bins_, Scalar min_, Scalar max_) + : keys(keys_), max_bins(max_bins_), min(min_), max(max_) {} KOKKOS_INLINE_FUNCTION - void operator() (int i, unsigned int& count) const { - int ix1 = int ((keys(i,0)-min)/max * max_bins); - int iy1 = int ((keys(i,1)-min)/max * max_bins); - int iz1 = int ((keys(i,2)-min)/max * max_bins); - int ix2 = int ((keys(i+1,0)-min)/max * max_bins); - int iy2 = int ((keys(i+1,1)-min)/max * max_bins); - int iz2 = int ((keys(i+1,2)-min)/max * max_bins); - - if (ix1>ix2) count++; - else if(ix1==ix2) { - if (iy1>iy2) count++; - else if ((iy1==iy2) && (iz1>iz2)) count++; + void operator()(int i, unsigned int& count) const { + int ix1 = int((keys(i, 0) - min) / max * max_bins); + int iy1 = int((keys(i, 1) - min) / max * max_bins); + int iz1 = int((keys(i, 2) - min) / max * max_bins); + int ix2 = int((keys(i + 1, 0) - min) / max * max_bins); + int iy2 = int((keys(i + 1, 1) - min) / max * max_bins); + int iz2 = int((keys(i + 1, 2) - min) / max * max_bins); + + if (ix1 > ix2) + count++; + else if (ix1 == ix2) { + if (iy1 > iy2) + count++; + else if ((iy1 == iy2) && (iz1 > iz2)) + count++; } } }; -template +template struct sum3D { typedef double value_type; typedef ExecutionSpace execution_space; - Kokkos::View keys; + Kokkos::View keys; - sum3D(Kokkos::View keys_):keys(keys_) {} + sum3D(Kokkos::View keys_) : keys(keys_) {} KOKKOS_INLINE_FUNCTION - void operator() (int i, double& count) const { - count+=keys(i,0); - count+=keys(i,1); - count+=keys(i,2); + void operator()(int i, double& count) const { + count += keys(i, 0); + count += keys(i, 1); + count += keys(i, 2); } }; -template -void test_1D_sort(unsigned int n,bool force_kokkos) { - typedef Kokkos::View KeyViewType; - KeyViewType keys("Keys",n); +template +void test_1D_sort(unsigned int n, bool force_kokkos) { + typedef Kokkos::View KeyViewType; + KeyViewType keys("Keys", n); // Test sorting array with all numbers equal - Kokkos::deep_copy(keys,KeyType(1)); - Kokkos::sort(keys,force_kokkos); + Kokkos::deep_copy(keys, KeyType(1)); + Kokkos::sort(keys, force_kokkos); Kokkos::Random_XorShift64_Pool g(1931); - Kokkos::fill_random(keys,g,Kokkos::Random_XorShift64_Pool::generator_type::MAX_URAND); + Kokkos::fill_random(keys, g, + Kokkos::Random_XorShift64_Pool< + ExecutionSpace>::generator_type::MAX_URAND); - double sum_before = 0.0; - double sum_after = 0.0; + double sum_before = 0.0; + double sum_after = 0.0; unsigned int sort_fails = 0; - Kokkos::parallel_reduce(n,sum(keys),sum_before); + Kokkos::parallel_reduce(n, sum(keys), sum_before); - Kokkos::sort(keys,force_kokkos); + Kokkos::sort(keys, force_kokkos); - Kokkos::parallel_reduce(n,sum(keys),sum_after); - Kokkos::parallel_reduce(n-1,is_sorted_struct(keys),sort_fails); + Kokkos::parallel_reduce(n, sum(keys), sum_after); + Kokkos::parallel_reduce( + n - 1, is_sorted_struct(keys), sort_fails); - double ratio = sum_before/sum_after; + double ratio = sum_before / sum_after; double epsilon = 1e-10; - unsigned int equal_sum = (ratio > (1.0-epsilon)) && (ratio < (1.0+epsilon)) ? 1 : 0; + unsigned int equal_sum = + (ratio > (1.0 - epsilon)) && (ratio < (1.0 + epsilon)) ? 1 : 0; - ASSERT_EQ(sort_fails,0); - ASSERT_EQ(equal_sum,1); + ASSERT_EQ(sort_fails, 0); + ASSERT_EQ(equal_sum, 1); } -template +template void test_3D_sort(unsigned int n) { - typedef Kokkos::View KeyViewType; + typedef Kokkos::View KeyViewType; - KeyViewType keys("Keys",n*n*n); + KeyViewType keys("Keys", n * n * n); Kokkos::Random_XorShift64_Pool g(1931); - Kokkos::fill_random(keys,g,100.0); + Kokkos::fill_random(keys, g, 100.0); - double sum_before = 0.0; - double sum_after = 0.0; + double sum_before = 0.0; + double sum_after = 0.0; unsigned int sort_fails = 0; - Kokkos::parallel_reduce(keys.extent(0),sum3D(keys),sum_before); + Kokkos::parallel_reduce(keys.extent(0), sum3D(keys), + sum_before); int bin_1d = 1; - while( bin_1d*bin_1d*bin_1d*4< (int) keys.extent(0) ) bin_1d*=2; - int bin_max[3] = {bin_1d,bin_1d,bin_1d}; - typename KeyViewType::value_type min[3] = {0,0,0}; - typename KeyViewType::value_type max[3] = {100,100,100}; - - typedef Kokkos::BinOp3D< KeyViewType > BinOp; - BinOp bin_op(bin_max,min,max); - Kokkos::BinSort< KeyViewType , BinOp > - Sorter(keys,bin_op,false); + while (bin_1d * bin_1d * bin_1d * 4 < (int)keys.extent(0)) bin_1d *= 2; + int bin_max[3] = {bin_1d, bin_1d, bin_1d}; + typename KeyViewType::value_type min[3] = {0, 0, 0}; + typename KeyViewType::value_type max[3] = {100, 100, 100}; + + typedef Kokkos::BinOp3D BinOp; + BinOp bin_op(bin_max, min, max); + Kokkos::BinSort Sorter(keys, bin_op, false); Sorter.create_permute_vector(); - Sorter.template sort< KeyViewType >(keys); + Sorter.template sort(keys); - Kokkos::parallel_reduce(keys.extent(0),sum3D(keys),sum_after); - Kokkos::parallel_reduce(keys.extent(0)-1,bin3d_is_sorted_struct(keys,bin_1d,min[0],max[0]),sort_fails); + Kokkos::parallel_reduce(keys.extent(0), sum3D(keys), + sum_after); + Kokkos::parallel_reduce(keys.extent(0) - 1, + bin3d_is_sorted_struct( + keys, bin_1d, min[0], max[0]), + sort_fails); - double ratio = sum_before/sum_after; + double ratio = sum_before / sum_after; double epsilon = 1e-10; - unsigned int equal_sum = (ratio > (1.0-epsilon)) && (ratio < (1.0+epsilon)) ? 1 : 0; + unsigned int equal_sum = + (ratio > (1.0 - epsilon)) && (ratio < (1.0 + epsilon)) ? 1 : 0; - if ( sort_fails ) - printf("3D Sort Sum: %f %f Fails: %u\n",sum_before,sum_after,sort_fails); + if (sort_fails) + printf("3D Sort Sum: %f %f Fails: %u\n", sum_before, sum_after, sort_fails); - ASSERT_EQ(sort_fails,0); - ASSERT_EQ(equal_sum,1); + ASSERT_EQ(sort_fails, 0); + ASSERT_EQ(equal_sum, 1); } //---------------------------------------------------------------------------- -template -void test_dynamic_view_sort(unsigned int n ) -{ - typedef Kokkos::Experimental::DynamicView KeyDynamicViewType; - typedef Kokkos::View KeyViewType; +template +void test_dynamic_view_sort(unsigned int n) { + typedef Kokkos::Experimental::DynamicView + KeyDynamicViewType; + typedef Kokkos::View KeyViewType; - const size_t upper_bound = 2 * n ; + const size_t upper_bound = 2 * n; const size_t min_chunk_size = 1024; KeyDynamicViewType keys("Keys", min_chunk_size, upper_bound); keys.resize_serial(n); - KeyViewType keys_view("KeysTmp", n ); + KeyViewType keys_view("KeysTmp", n); // Test sorting array with all numbers equal - Kokkos::deep_copy(keys_view,KeyType(1)); - Kokkos::deep_copy(keys,keys_view); - Kokkos::sort(keys, 0 /* begin */ , n /* end */ ); + Kokkos::deep_copy(keys_view, KeyType(1)); + Kokkos::deep_copy(keys, keys_view); + Kokkos::sort(keys, 0 /* begin */, n /* end */); Kokkos::Random_XorShift64_Pool g(1931); - Kokkos::fill_random(keys_view,g,Kokkos::Random_XorShift64_Pool::generator_type::MAX_URAND); + Kokkos::fill_random(keys_view, g, + Kokkos::Random_XorShift64_Pool< + ExecutionSpace>::generator_type::MAX_URAND); ExecutionSpace().fence(); - Kokkos::deep_copy(keys,keys_view); - //ExecutionSpace().fence(); + Kokkos::deep_copy(keys, keys_view); + // ExecutionSpace().fence(); - double sum_before = 0.0; - double sum_after = 0.0; + double sum_before = 0.0; + double sum_after = 0.0; unsigned int sort_fails = 0; - Kokkos::parallel_reduce(n,sum(keys_view),sum_before); + Kokkos::parallel_reduce(n, sum(keys_view), + sum_before); - Kokkos::sort(keys, 0 /* begin */ , n /* end */ ); + Kokkos::sort(keys, 0 /* begin */, n /* end */); - ExecutionSpace().fence(); // Need this fence to prevent BusError with Cuda - Kokkos::deep_copy( keys_view , keys ); - //ExecutionSpace().fence(); + ExecutionSpace().fence(); // Need this fence to prevent BusError with Cuda + Kokkos::deep_copy(keys_view, keys); + // ExecutionSpace().fence(); - Kokkos::parallel_reduce(n,sum(keys_view),sum_after); - Kokkos::parallel_reduce(n-1,is_sorted_struct(keys_view),sort_fails); + Kokkos::parallel_reduce(n, sum(keys_view), + sum_after); + Kokkos::parallel_reduce( + n - 1, is_sorted_struct(keys_view), sort_fails); - double ratio = sum_before/sum_after; + double ratio = sum_before / sum_after; double epsilon = 1e-10; - unsigned int equal_sum = (ratio > (1.0-epsilon)) && (ratio < (1.0+epsilon)) ? 1 : 0; - - if ( sort_fails != 0 || equal_sum != 1 ) { - std::cout << " N = " << n - << " ; sum_before = " << sum_before - << " ; sum_after = " << sum_after - << " ; ratio = " << ratio - << std::endl ; + unsigned int equal_sum = + (ratio > (1.0 - epsilon)) && (ratio < (1.0 + epsilon)) ? 1 : 0; + + if (sort_fails != 0 || equal_sum != 1) { + std::cout << " N = " << n << " ; sum_before = " << sum_before + << " ; sum_after = " << sum_after << " ; ratio = " << ratio + << std::endl; } - ASSERT_EQ(sort_fails,0); - ASSERT_EQ(equal_sum,1); + ASSERT_EQ(sort_fails, 0); + ASSERT_EQ(equal_sum, 1); } //---------------------------------------------------------------------------- -template -void test_issue_1160() -{ +template +void test_issue_1160() { Kokkos::View element_("element", 10); Kokkos::View x_("x", 10); Kokkos::View v_("y", 10); auto h_element = Kokkos::create_mirror_view(element_); - auto h_x = Kokkos::create_mirror_view(x_); - auto h_v = Kokkos::create_mirror_view(v_); + auto h_x = Kokkos::create_mirror_view(x_); + auto h_v = Kokkos::create_mirror_view(v_); h_element(0) = 9; h_element(1) = 8; @@ -292,20 +306,21 @@ void test_issue_1160() Kokkos::deep_copy(v_, h_v); typedef decltype(element_) KeyViewType; - typedef Kokkos::BinOp1D< KeyViewType > BinOp; + typedef Kokkos::BinOp1D BinOp; int begin = 3; - int end = 8; - auto max = h_element(begin); - auto min = h_element(end - 1); + int end = 8; + auto max = h_element(begin); + auto min = h_element(end - 1); BinOp binner(end - begin, min, max); - Kokkos::BinSort Sorter(element_,begin,end,binner,false); + Kokkos::BinSort Sorter(element_, begin, end, binner, + false); Sorter.create_permute_vector(); - Sorter.sort(element_,begin,end); + Sorter.sort(element_, begin, end); - Sorter.sort(x_,begin,end); - Sorter.sort(v_,begin,end); + Sorter.sort(x_, begin, end); + Sorter.sort(v_, begin, end); Kokkos::deep_copy(h_element, element_); Kokkos::deep_copy(h_x, x_); @@ -330,18 +345,17 @@ void test_issue_1160() //---------------------------------------------------------------------------- -template -void test_sort(unsigned int N) -{ - test_1D_sort(N*N*N, true); - test_1D_sort(N*N*N, false); +template +void test_sort(unsigned int N) { + test_1D_sort(N * N * N, true); + test_1D_sort(N * N * N, false); #if !defined(KOKKOS_ENABLE_ROCM) - test_3D_sort(N); - test_dynamic_view_sort(N*N); + test_3D_sort(N); + test_dynamic_view_sort(N * N); #endif test_issue_1160(); } -} -} +} // namespace Impl +} // namespace Test #endif /* KOKKOS_ALGORITHMS_UNITTESTS_TESTSORT_HPP */ diff --git a/lib/kokkos/algorithms/unit_tests/TestThreads.cpp b/lib/kokkos/algorithms/unit_tests/TestThreads.cpp index 99cdb7da92..c75e6e8dfb 100644 --- a/lib/kokkos/algorithms/unit_tests/TestThreads.cpp +++ b/lib/kokkos/algorithms/unit_tests/TestThreads.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -52,51 +53,36 @@ #include #include - //---------------------------------------------------------------------------- - namespace Test { -class threads : public ::testing::Test { -protected: - static void SetUpTestCase() - { - std::cout << std::setprecision(5) << std::scientific; +#define THREADS_RANDOM_XORSHIFT64(num_draws) \ + TEST(threads, Random_XorShift64) { \ + Impl::test_random >( \ + num_draws); \ } - static void TearDownTestCase() - { +#define THREADS_RANDOM_XORSHIFT1024(num_draws) \ + TEST(threads, Random_XorShift1024) { \ + Impl::test_random >( \ + num_draws); \ } -}; -#define THREADS_RANDOM_XORSHIFT64( num_draws ) \ - TEST_F( threads, Random_XorShift64 ) { \ - Impl::test_random >(num_draws); \ +#define THREADS_SORT_UNSIGNED(size) \ + TEST(threads, SortUnsigned) { \ + Impl::test_sort(size); \ } -#define THREADS_RANDOM_XORSHIFT1024( num_draws ) \ - TEST_F( threads, Random_XorShift1024 ) { \ - Impl::test_random >(num_draws); \ - } - -#define THREADS_SORT_UNSIGNED( size ) \ - TEST_F( threads, SortUnsigned ) { \ - Impl::test_sort< Kokkos::Threads, double >(size); \ - } - - -THREADS_RANDOM_XORSHIFT64( 10240000 ) -THREADS_RANDOM_XORSHIFT1024( 10130144 ) +THREADS_RANDOM_XORSHIFT64(10240000) +THREADS_RANDOM_XORSHIFT1024(10130144) THREADS_SORT_UNSIGNED(171) #undef THREADS_RANDOM_XORSHIFT64 #undef THREADS_RANDOM_XORSHIFT1024 #undef THREADS_SORT_UNSIGNED -} // namespace Test +} // namespace Test #else void KOKKOS_ALGORITHMS_UNITTESTS_TESTTHREADS_PREVENT_LINK_ERROR() {} #endif - - diff --git a/lib/kokkos/algorithms/unit_tests/UnitTestMain.cpp b/lib/kokkos/algorithms/unit_tests/UnitTestMain.cpp index 8feb08332f..e245aad35f 100644 --- a/lib/kokkos/algorithms/unit_tests/UnitTestMain.cpp +++ b/lib/kokkos/algorithms/unit_tests/UnitTestMain.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,10 +46,9 @@ #include int main(int argc, char *argv[]) { - Kokkos::initialize(argc,argv); - ::testing::InitGoogleTest(&argc,argv); + Kokkos::initialize(argc, argv); + ::testing::InitGoogleTest(&argc, argv); int result = RUN_ALL_TESTS(); Kokkos::finalize(); return result; } - diff --git a/lib/kokkos/benchmarks/atomic/main.cpp b/lib/kokkos/benchmarks/atomic/main.cpp index d86d196249..5f0977f754 100644 --- a/lib/kokkos/benchmarks/atomic/main.cpp +++ b/lib/kokkos/benchmarks/atomic/main.cpp @@ -1,124 +1,120 @@ -#include -#include -#include +#include +#include +#include -template -double test_atomic(int L, int N, int M,int K,int R,Kokkos::View offsets) { - Kokkos::View output("Output",N); +template +double test_atomic(int L, int N, int M, int K, int R, + Kokkos::View offsets) { + Kokkos::View output("Output", N); Kokkos::Impl::Timer timer; - for(int r = 0; r -double test_no_atomic(int L, int N, int M,int K,int R,Kokkos::View offsets) { - Kokkos::View output("Output",N); +template +double test_no_atomic(int L, int N, int M, int K, int R, + Kokkos::View offsets) { + Kokkos::View output("Output", N); Kokkos::Impl::Timer timer; - for(int r = 0; r\n"); - printf("Example Input GPU:\n"); - printf(" Histogram : 1000000 1000 1 1000 1 10 1\n"); - printf(" MD Force : 100000 100000 100 1000 20 10 4\n"); - printf(" Matrix Assembly : 100000 1000000 50 1000 20 10 4\n"); - Kokkos::finalize(); - return 0; - } + Kokkos::initialize(argc, argv); + { + if (argc < 8) { + printf("Arguments: L N M D K R T\n"); + printf(" L: Number of iterations to run\n"); + printf(" N: Length of array to do atomics into\n"); + printf(" M: Number of atomics per iteration to do\n"); + printf(" D: Distance from index i to do atomics into (randomly)\n"); + printf(" K: Number of FMAD per atomic\n"); + printf(" R: Number of repeats of the experiments\n"); + printf(" T: Type of atomic\n"); + printf(" 1 - int\n"); + printf(" 2 - long\n"); + printf(" 3 - float\n"); + printf(" 4 - double\n"); + printf(" 5 - complex\n"); + printf("Example Input GPU:\n"); + printf(" Histogram : 1000000 1000 1 1000 1 10 1\n"); + printf(" MD Force : 100000 100000 100 1000 20 10 4\n"); + printf(" Matrix Assembly : 100000 1000000 50 1000 20 10 4\n"); + Kokkos::finalize(); + return 0; + } + int L = atoi(argv[1]); + int N = atoi(argv[2]); + int M = atoi(argv[3]); + int D = atoi(argv[4]); + int K = atoi(argv[5]); + int R = atoi(argv[6]); + int type = atoi(argv[7]); - int L = atoi(argv[1]); - int N = atoi(argv[2]); - int M = atoi(argv[3]); - int D = atoi(argv[4]); - int K = atoi(argv[5]); - int R = atoi(argv[6]); - int type = atoi(argv[7]); - - Kokkos::View offsets("Offsets",L,M); - Kokkos::Random_XorShift64_Pool<> pool(12371); - Kokkos::fill_random(offsets,pool,D); - double time = 0; - if(type==1) - time = test_atomic(L,N,M,K,R,offsets); - if(type==2) - time = test_atomic(L,N,M,K,R,offsets); - if(type==3) - time = test_atomic(L,N,M,K,R,offsets); - if(type==4) - time = test_atomic(L,N,M,K,R,offsets); - if(type==5) - time = test_atomic >(L,N,M,K,R,offsets); + Kokkos::View offsets("Offsets", L, M); + Kokkos::Random_XorShift64_Pool<> pool(12371); + Kokkos::fill_random(offsets, pool, D); + double time = 0; + if (type == 1) time = test_atomic(L, N, M, K, R, offsets); + if (type == 2) time = test_atomic(L, N, M, K, R, offsets); + if (type == 3) time = test_atomic(L, N, M, K, R, offsets); + if (type == 4) time = test_atomic(L, N, M, K, R, offsets); + if (type == 5) + time = test_atomic >(L, N, M, K, R, offsets); - double time2 = 1; - if(type==1) - time2 = test_no_atomic(L,N,M,K,R,offsets); - if(type==2) - time2 = test_no_atomic(L,N,M,K,R,offsets); - if(type==3) - time2 = test_no_atomic(L,N,M,K,R,offsets); - if(type==4) - time2 = test_no_atomic(L,N,M,K,R,offsets); - if(type==5) - time2 = test_no_atomic >(L,N,M,K,R,offsets); + double time2 = 1; + if (type == 1) time2 = test_no_atomic(L, N, M, K, R, offsets); + if (type == 2) time2 = test_no_atomic(L, N, M, K, R, offsets); + if (type == 3) time2 = test_no_atomic(L, N, M, K, R, offsets); + if (type == 4) time2 = test_no_atomic(L, N, M, K, R, offsets); + if (type == 5) + time2 = test_no_atomic >(L, N, M, K, R, offsets); - int size = 0; - if(type==1) size = sizeof(int); - if(type==2) size = sizeof(long); - if(type==3) size = sizeof(float); - if(type==4) size = sizeof(double); - if(type==5) size = sizeof(Kokkos::complex); + int size = 0; + if (type == 1) size = sizeof(int); + if (type == 2) size = sizeof(long); + if (type == 3) size = sizeof(float); + if (type == 4) size = sizeof(double); + if (type == 5) size = sizeof(Kokkos::complex); - printf("%i\n",size); - printf("Time: %s %i %i %i %i %i %i (t_atomic: %e t_nonatomic: %e ratio: %lf )( GUpdates/s: %lf GB/s: %lf )\n", - (type==1)?"int": ( - (type==2)?"long": ( - (type==3)?"float": ( - (type==4)?"double":"complex"))), - L,N,M,D,K,R,time,time2,time/time2, - 1.e-9*L*R*M/time, 1.0*L*R*M*2*size/time/1024/1024/1024); -} + printf("%i\n", size); + printf( + "Time: %s %i %i %i %i %i %i (t_atomic: %e t_nonatomic: %e ratio: %lf " + ")( GUpdates/s: %lf GB/s: %lf )\n", + (type == 1) + ? "int" + : ((type == 2) + ? "long" + : ((type == 3) ? "float" + : ((type == 4) ? "double" : "complex"))), + L, N, M, D, K, R, time, time2, time / time2, 1.e-9 * L * R * M / time, + 1.0 * L * R * M * 2 * size / time / 1024 / 1024 / 1024); + } Kokkos::finalize(); } - diff --git a/lib/kokkos/benchmarks/bytes_and_flops/bench.hpp b/lib/kokkos/benchmarks/bytes_and_flops/bench.hpp index 59b4d50c44..62d7ef4a4c 100644 --- a/lib/kokkos/benchmarks/bytes_and_flops/bench.hpp +++ b/lib/kokkos/benchmarks/bytes_and_flops/bench.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,59 +42,52 @@ //@HEADER */ -#include -#include +#include +#include -template +template struct Run { -static void run(int N, int K, int R, int F, int T, int S); + static void run(int N, int K, int R, int F, int T, int S); }; -template +template struct RunStride { -static void run_1(int N, int K, int R, int F, int T, int S); -static void run_2(int N, int K, int R, int F, int T, int S); -static void run_3(int N, int K, int R, int F, int T, int S); -static void run_4(int N, int K, int R, int F, int T, int S); -static void run_5(int N, int K, int R, int F, int T, int S); -static void run_6(int N, int K, int R, int F, int T, int S); -static void run_7(int N, int K, int R, int F, int T, int S); -static void run_8(int N, int K, int R, int F, int T, int S); -static void run(int N, int K, int R, int U, int F, int T, int S); + static void run_1(int N, int K, int R, int F, int T, int S); + static void run_2(int N, int K, int R, int F, int T, int S); + static void run_3(int N, int K, int R, int F, int T, int S); + static void run_4(int N, int K, int R, int F, int T, int S); + static void run_5(int N, int K, int R, int F, int T, int S); + static void run_6(int N, int K, int R, int F, int T, int S); + static void run_7(int N, int K, int R, int F, int T, int S); + static void run_8(int N, int K, int R, int F, int T, int S); + static void run(int N, int K, int R, int U, int F, int T, int S); }; #define STRIDE 1 -#include +#include #undef STRIDE #define STRIDE 2 -#include +#include #undef STRIDE #define STRIDE 4 -#include +#include #undef STRIDE #define STRIDE 8 -#include +#include #undef STRIDE #define STRIDE 16 -#include +#include #undef STRIDE #define STRIDE 32 -#include +#include #undef STRIDE -template +template void run_stride_unroll(int N, int K, int R, int D, int U, int F, int T, int S) { - if(D == 1) - RunStride::run(N,K,R,U,F,T,S); - if(D == 2) - RunStride::run(N,K,R,U,F,T,S); - if(D == 4) - RunStride::run(N,K,R,U,F,T,S); - if(D == 8) - RunStride::run(N,K,R,U,F,T,S); - if(D == 16) - RunStride::run(N,K,R,U,F,T,S); - if(D == 32) - RunStride::run(N,K,R,U,F,T,S); + if (D == 1) RunStride::run(N, K, R, U, F, T, S); + if (D == 2) RunStride::run(N, K, R, U, F, T, S); + if (D == 4) RunStride::run(N, K, R, U, F, T, S); + if (D == 8) RunStride::run(N, K, R, U, F, T, S); + if (D == 16) RunStride::run(N, K, R, U, F, T, S); + if (D == 32) RunStride::run(N, K, R, U, F, T, S); } - diff --git a/lib/kokkos/benchmarks/bytes_and_flops/bench_stride.hpp b/lib/kokkos/benchmarks/bytes_and_flops/bench_stride.hpp index 6509c654e7..64817fe9dc 100644 --- a/lib/kokkos/benchmarks/bytes_and_flops/bench_stride.hpp +++ b/lib/kokkos/benchmarks/bytes_and_flops/bench_stride.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,84 +42,82 @@ //@HEADER */ - #define UNROLL 1 -#include +#include #undef UNROLL #define UNROLL 2 -#include +#include #undef UNROLL #define UNROLL 3 -#include +#include #undef UNROLL #define UNROLL 4 -#include +#include #undef UNROLL #define UNROLL 5 -#include +#include #undef UNROLL #define UNROLL 6 -#include +#include #undef UNROLL #define UNROLL 7 -#include +#include #undef UNROLL #define UNROLL 8 -#include +#include #undef UNROLL -template -struct RunStride { -static void run_1(int N, int K, int R, int F, int T, int S) { - Run::run(N,K,R,F,T,S); -} -static void run_2(int N, int K, int R, int F, int T, int S) { - Run::run(N,K,R,F,T,S); -} -static void run_3(int N, int K, int R, int F, int T, int S) { - Run::run(N,K,R,F,T,S); -} -static void run_4(int N, int K, int R, int F, int T, int S) { - Run::run(N,K,R,F,T,S); -} -static void run_5(int N, int K, int R, int F, int T, int S) { - Run::run(N,K,R,F,T,S); -} -static void run_6(int N, int K, int R, int F, int T, int S) { - Run::run(N,K,R,F,T,S); -} -static void run_7(int N, int K, int R, int F, int T, int S) { - Run::run(N,K,R,F,T,S); -} -static void run_8(int N, int K, int R, int F, int T, int S) { - Run::run(N,K,R,F,T,S); -} - -static void run(int N, int K, int R, int U, int F, int T, int S) { - if(U==1) { - run_1(N,K,R,F,T,S); +template +struct RunStride { + static void run_1(int N, int K, int R, int F, int T, int S) { + Run::run(N, K, R, F, T, S); } - if(U==2) { - run_2(N,K,R,F,T,S); + static void run_2(int N, int K, int R, int F, int T, int S) { + Run::run(N, K, R, F, T, S); } - if(U==3) { - run_3(N,K,R,F,T,S); + static void run_3(int N, int K, int R, int F, int T, int S) { + Run::run(N, K, R, F, T, S); } - if(U==4) { - run_4(N,K,R,F,T,S); + static void run_4(int N, int K, int R, int F, int T, int S) { + Run::run(N, K, R, F, T, S); } - if(U==5) { - run_5(N,K,R,F,T,S); + static void run_5(int N, int K, int R, int F, int T, int S) { + Run::run(N, K, R, F, T, S); } - if(U==6) { - run_6(N,K,R,F,T,S); + static void run_6(int N, int K, int R, int F, int T, int S) { + Run::run(N, K, R, F, T, S); } - if(U==7) { - run_7(N,K,R,F,T,S); + static void run_7(int N, int K, int R, int F, int T, int S) { + Run::run(N, K, R, F, T, S); + } + static void run_8(int N, int K, int R, int F, int T, int S) { + Run::run(N, K, R, F, T, S); } - if(U==8) { - run_8(N,K,R,F,T,S); - } -} -}; + static void run(int N, int K, int R, int U, int F, int T, int S) { + if (U == 1) { + run_1(N, K, R, F, T, S); + } + if (U == 2) { + run_2(N, K, R, F, T, S); + } + if (U == 3) { + run_3(N, K, R, F, T, S); + } + if (U == 4) { + run_4(N, K, R, F, T, S); + } + if (U == 5) { + run_5(N, K, R, F, T, S); + } + if (U == 6) { + run_6(N, K, R, F, T, S); + } + if (U == 7) { + run_7(N, K, R, F, T, S); + } + if (U == 8) { + run_8(N, K, R, F, T, S); + } + } +}; diff --git a/lib/kokkos/benchmarks/bytes_and_flops/bench_unroll_stride.hpp b/lib/kokkos/benchmarks/bytes_and_flops/bench_unroll_stride.hpp index c6651da1e7..00ce635a48 100644 --- a/lib/kokkos/benchmarks/bytes_and_flops/bench_unroll_stride.hpp +++ b/lib/kokkos/benchmarks/bytes_and_flops/bench_unroll_stride.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,108 +42,110 @@ //@HEADER */ -template -struct Run { -static void run(int N, int K, int R, int F, int T, int S) { - Kokkos::View A("A",N,K); - Kokkos::View B("B",N,K); - Kokkos::View C("C",N,K); +template +struct Run { + static void run(int N, int K, int R, int F, int T, int S) { + Kokkos::View A("A", N, K); + Kokkos::View B("B", N, K); + Kokkos::View C("C", N, K); - Kokkos::deep_copy(A,Scalar(1.5)); - Kokkos::deep_copy(B,Scalar(2.5)); - Kokkos::deep_copy(C,Scalar(3.5)); + Kokkos::deep_copy(A, Scalar(1.5)); + Kokkos::deep_copy(B, Scalar(2.5)); + Kokkos::deep_copy(C, Scalar(3.5)); - Kokkos::Timer timer; - Kokkos::parallel_for("BenchmarkKernel",Kokkos::TeamPolicy<>(N,T).set_scratch_size(0,Kokkos::PerTeam(S)), - KOKKOS_LAMBDA ( const Kokkos::TeamPolicy<>::member_type& team) { - const int n = team.league_rank(); - for(int r=0; r1) - Scalar a2 = a1*1.3; -#endif -#if(UNROLL>2) - Scalar a3 = a2*1.1; -#endif -#if(UNROLL>3) - Scalar a4 = a3*1.1; -#endif -#if(UNROLL>4) - Scalar a5 = a4*1.3; -#endif -#if(UNROLL>5) - Scalar a6 = a5*1.1; -#endif -#if(UNROLL>6) - Scalar a7 = a6*1.1; -#endif -#if(UNROLL>7) - Scalar a8 = a7*1.1; + Kokkos::Timer timer; + Kokkos::parallel_for( + "BenchmarkKernel", + Kokkos::TeamPolicy<>(N, T).set_scratch_size(0, Kokkos::PerTeam(S)), + KOKKOS_LAMBDA(const Kokkos::TeamPolicy<>::member_type& team) { + const int n = team.league_rank(); + for (int r = 0; r < R; r++) { + Kokkos::parallel_for( + Kokkos::TeamThreadRange(team, 0, K), [&](const int& i) { + Scalar a1 = A(n, i, 0); + const Scalar b = B(n, i, 0); +#if (UNROLL > 1) + Scalar a2 = a1 * 1.3; +#endif +#if (UNROLL > 2) + Scalar a3 = a2 * 1.1; +#endif +#if (UNROLL > 3) + Scalar a4 = a3 * 1.1; +#endif +#if (UNROLL > 4) + Scalar a5 = a4 * 1.3; +#endif +#if (UNROLL > 5) + Scalar a6 = a5 * 1.1; +#endif +#if (UNROLL > 6) + Scalar a7 = a6 * 1.1; +#endif +#if (UNROLL > 7) + Scalar a8 = a7 * 1.1; #endif - - for(int f = 0; f1) - a2 += b*a2; + for (int f = 0; f < F; f++) { + a1 += b * a1; +#if (UNROLL > 1) + a2 += b * a2; #endif -#if(UNROLL>2) - a3 += b*a3; +#if (UNROLL > 2) + a3 += b * a3; #endif -#if(UNROLL>3) - a4 += b*a4; +#if (UNROLL > 3) + a4 += b * a4; #endif -#if(UNROLL>4) - a5 += b*a5; +#if (UNROLL > 4) + a5 += b * a5; #endif -#if(UNROLL>5) - a6 += b*a6; +#if (UNROLL > 5) + a6 += b * a6; #endif -#if(UNROLL>6) - a7 += b*a7; +#if (UNROLL > 6) + a7 += b * a7; #endif -#if(UNROLL>7) - a8 += b*a8; +#if (UNROLL > 7) + a8 += b * a8; #endif - - - } -#if(UNROLL==1) - C(n,i,0) = a1; + } +#if (UNROLL == 1) + C(n, i, 0) = a1; #endif -#if(UNROLL==2) - C(n,i,0) = a1+a2; +#if (UNROLL == 2) + C(n, i, 0) = a1 + a2; #endif -#if(UNROLL==3) - C(n,i,0) = a1+a2+a3; +#if (UNROLL == 3) + C(n, i, 0) = a1 + a2 + a3; #endif -#if(UNROLL==4) - C(n,i,0) = a1+a2+a3+a4; +#if (UNROLL == 4) + C(n, i, 0) = a1 + a2 + a3 + a4; #endif -#if(UNROLL==5) - C(n,i,0) = a1+a2+a3+a4+a5; +#if (UNROLL == 5) + C(n, i, 0) = a1 + a2 + a3 + a4 + a5; #endif -#if(UNROLL==6) - C(n,i,0) = a1+a2+a3+a4+a5+a6; +#if (UNROLL == 6) + C(n, i, 0) = a1 + a2 + a3 + a4 + a5 + a6; #endif -#if(UNROLL==7) - C(n,i,0) = a1+a2+a3+a4+a5+a6+a7; +#if (UNROLL == 7) + C(n, i, 0) = a1 + a2 + a3 + a4 + a5 + a6 + a7; #endif -#if(UNROLL==8) - C(n,i,0) = a1+a2+a3+a4+a5+a6+a7+a8; +#if (UNROLL == 8) + C(n, i, 0) = a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8; #endif + }); + } + }); + Kokkos::fence(); + double seconds = timer.seconds(); - }); - } - }); - Kokkos::fence(); - double seconds = timer.seconds(); - - double bytes = 1.0*N*K*R*3*sizeof(Scalar); - double flops = 1.0*N*K*R*(F*2*UNROLL + 2*(UNROLL-1)); - printf("NKRUFTS: %i %i %i %i %i %i %i Time: %lfs Bandwidth: %lfGiB/s GFlop/s: %lf\n",N,K,R,UNROLL,F,T,S,seconds,1.0*bytes/seconds/1024/1024/1024,1.e-9*flops/seconds); -} + double bytes = 1.0 * N * K * R * 3 * sizeof(Scalar); + double flops = 1.0 * N * K * R * (F * 2 * UNROLL + 2 * (UNROLL - 1)); + printf( + "NKRUFTS: %i %i %i %i %i %i %i Time: %lfs Bandwidth: %lfGiB/s GFlop/s: " + "%lf\n", + N, K, R, UNROLL, F, T, S, seconds, + 1.0 * bytes / seconds / 1024 / 1024 / 1024, 1.e-9 * flops / seconds); + } }; - diff --git a/lib/kokkos/benchmarks/bytes_and_flops/main.cpp b/lib/kokkos/benchmarks/bytes_and_flops/main.cpp index 4f46b38717..c21a16200e 100644 --- a/lib/kokkos/benchmarks/bytes_and_flops/main.cpp +++ b/lib/kokkos/benchmarks/bytes_and_flops/main.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,25 +42,27 @@ //@HEADER */ -#include -#include -#include -#include +#include +#include +#include +#include int main(int argc, char* argv[]) { Kokkos::initialize(); - - if(argc<10) { + if (argc < 10) { printf("Arguments: N K R D U F T S\n"); printf(" P: Precision (1==float, 2==double)\n"); printf(" N,K: dimensions of the 2D array to allocate\n"); printf(" R: how often to loop through the K dimension with each team\n"); printf(" D: distance between loaded elements (stride)\n"); printf(" U: how many independent flops to do per load\n"); - printf(" F: how many times to repeat the U unrolled operations before reading next element\n"); + printf( + " F: how many times to repeat the U unrolled operations before " + "reading next element\n"); printf(" T: team size\n"); - printf(" S: shared memory per team (used to control occupancy on GPUs)\n"); + printf( + " S: shared memory per team (used to control occupancy on GPUs)\n"); printf("Example Input GPU:\n"); printf(" Bandwidth Bound : 2 100000 1024 1 1 1 1 256 6000\n"); printf(" Cache Bound : 2 100000 1024 64 1 1 1 512 20000\n"); @@ -70,7 +73,6 @@ int main(int argc, char* argv[]) { return 0; } - int P = atoi(argv[1]); int N = atoi(argv[2]); int K = atoi(argv[3]); @@ -81,17 +83,25 @@ int main(int argc, char* argv[]) { int T = atoi(argv[8]); int S = atoi(argv[9]); - if(U>8) {printf("U must be 1-8\n"); return 0;} - if( (D!=1) && (D!=2) && (D!=4) && (D!=8) && (D!=16) && (D!=32)) {printf("D must be one of 1,2,4,8,16,32\n"); return 0;} - if( (P!=1) && (P!=2) ) {printf("P must be one of 1,2\n"); return 0;} + if (U > 8) { + printf("U must be 1-8\n"); + return 0; + } + if ((D != 1) && (D != 2) && (D != 4) && (D != 8) && (D != 16) && (D != 32)) { + printf("D must be one of 1,2,4,8,16,32\n"); + return 0; + } + if ((P != 1) && (P != 2)) { + printf("P must be one of 1,2\n"); + return 0; + } - if(P==1) { - run_stride_unroll(N,K,R,D,U,F,T,S); + if (P == 1) { + run_stride_unroll(N, K, R, D, U, F, T, S); } - if(P==2) { - run_stride_unroll(N,K,R,D,U,F,T,S); + if (P == 2) { + run_stride_unroll(N, K, R, D, U, F, T, S); } Kokkos::finalize(); } - diff --git a/lib/kokkos/benchmarks/gather/gather.hpp b/lib/kokkos/benchmarks/gather/gather.hpp index bbbd65850f..239614184b 100644 --- a/lib/kokkos/benchmarks/gather/gather.hpp +++ b/lib/kokkos/benchmarks/gather/gather.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,52 +42,44 @@ //@HEADER */ -template +template struct RunGather { static void run(int N, int K, int D, int R, int F); }; #define UNROLL 1 -#include +#include #undef UNROLL #define UNROLL 2 -#include +#include #undef UNROLL #define UNROLL 3 -#include +#include #undef UNROLL #define UNROLL 4 -#include +#include #undef UNROLL #define UNROLL 5 -#include +#include #undef UNROLL #define UNROLL 6 -#include +#include #undef UNROLL #define UNROLL 7 -#include +#include #undef UNROLL #define UNROLL 8 -#include +#include #undef UNROLL -template +template void run_gather_test(int N, int K, int D, int R, int U, int F) { - if(U == 1) - RunGather::run(N,K,D,R,F); - if(U == 2) - RunGather::run(N,K,D,R,F); - if(U == 3) - RunGather::run(N,K,D,R,F); - if(U == 4) - RunGather::run(N,K,D,R,F); - if(U == 5) - RunGather::run(N,K,D,R,F); - if(U == 6) - RunGather::run(N,K,D,R,F); - if(U == 7) - RunGather::run(N,K,D,R,F); - if(U == 8) - RunGather::run(N,K,D,R,F); + if (U == 1) RunGather::run(N, K, D, R, F); + if (U == 2) RunGather::run(N, K, D, R, F); + if (U == 3) RunGather::run(N, K, D, R, F); + if (U == 4) RunGather::run(N, K, D, R, F); + if (U == 5) RunGather::run(N, K, D, R, F); + if (U == 6) RunGather::run(N, K, D, R, F); + if (U == 7) RunGather::run(N, K, D, R, F); + if (U == 8) RunGather::run(N, K, D, R, F); } diff --git a/lib/kokkos/benchmarks/gather/gather_unroll.hpp b/lib/kokkos/benchmarks/gather/gather_unroll.hpp index 1d9c99adf9..4dc046f99c 100644 --- a/lib/kokkos/benchmarks/gather/gather_unroll.hpp +++ b/lib/kokkos/benchmarks/gather/gather_unroll.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,129 +42,132 @@ //@HEADER */ -#include -#include +#include +#include -template -struct RunGather { -static void run(int N, int K, int D, int R, int F) { - Kokkos::View connectivity("Connectivity",N,K); - Kokkos::View A_in("Input",N); - Kokkos::View B_in("Input",N); - Kokkos::View C("Output",N); +template +struct RunGather { + static void run(int N, int K, int D, int R, int F) { + Kokkos::View connectivity("Connectivity", N, K); + Kokkos::View A_in("Input", N); + Kokkos::View B_in("Input", N); + Kokkos::View C("Output", N); - Kokkos::Random_XorShift64_Pool<> rand_pool(12313); + Kokkos::Random_XorShift64_Pool<> rand_pool(12313); - Kokkos::deep_copy(A_in,1.5); - Kokkos::deep_copy(B_in,2.0); + Kokkos::deep_copy(A_in, 1.5); + Kokkos::deep_copy(B_in, 2.0); - Kokkos::View > A(A_in); - Kokkos::View > B(B_in); - - Kokkos::parallel_for("InitKernel",N, - KOKKOS_LAMBDA (const int& i) { - auto rand_gen = rand_pool.get_state(); - for( int jj=0; jj > A( + A_in); + Kokkos::View > B( + B_in); + Kokkos::parallel_for( + "InitKernel", N, KOKKOS_LAMBDA(const int& i) { + auto rand_gen = rand_pool.get_state(); + for (int jj = 0; jj < K; jj++) { + connectivity(i, jj) = (rand_gen.rand(D) + i - D / 2 + N) % N; + } + rand_pool.free_state(rand_gen); + }); + Kokkos::fence(); - Kokkos::Timer timer; - for(int r = 0; r1) - Scalar a2 = a1*Scalar(1.3); + Kokkos::Timer timer; + for (int r = 0; r < R; r++) { + Kokkos::parallel_for( + "BenchmarkKernel", N, KOKKOS_LAMBDA(const int& i) { + Scalar c = Scalar(0.0); + for (int jj = 0; jj < K; jj++) { + const int j = connectivity(i, jj); + Scalar a1 = A(j); + const Scalar b = B(j); +#if (UNROLL > 1) + Scalar a2 = a1 * Scalar(1.3); #endif -#if(UNROLL>2) - Scalar a3 = a2*Scalar(1.1); +#if (UNROLL > 2) + Scalar a3 = a2 * Scalar(1.1); #endif -#if(UNROLL>3) - Scalar a4 = a3*Scalar(1.1); +#if (UNROLL > 3) + Scalar a4 = a3 * Scalar(1.1); #endif -#if(UNROLL>4) - Scalar a5 = a4*Scalar(1.3); +#if (UNROLL > 4) + Scalar a5 = a4 * Scalar(1.3); #endif -#if(UNROLL>5) - Scalar a6 = a5*Scalar(1.1); +#if (UNROLL > 5) + Scalar a6 = a5 * Scalar(1.1); #endif -#if(UNROLL>6) - Scalar a7 = a6*Scalar(1.1); +#if (UNROLL > 6) + Scalar a7 = a6 * Scalar(1.1); #endif -#if(UNROLL>7) - Scalar a8 = a7*Scalar(1.1); +#if (UNROLL > 7) + Scalar a8 = a7 * Scalar(1.1); #endif - - for(int f = 0; f1) - a2 += b*a2; + for (int f = 0; f < F; f++) { + a1 += b * a1; +#if (UNROLL > 1) + a2 += b * a2; #endif -#if(UNROLL>2) - a3 += b*a3; +#if (UNROLL > 2) + a3 += b * a3; #endif -#if(UNROLL>3) - a4 += b*a4; +#if (UNROLL > 3) + a4 += b * a4; #endif -#if(UNROLL>4) - a5 += b*a5; +#if (UNROLL > 4) + a5 += b * a5; #endif -#if(UNROLL>5) - a6 += b*a6; +#if (UNROLL > 5) + a6 += b * a6; #endif -#if(UNROLL>6) - a7 += b*a7; +#if (UNROLL > 6) + a7 += b * a7; #endif -#if(UNROLL>7) - a8 += b*a8; +#if (UNROLL > 7) + a8 += b * a8; #endif - - - } -#if(UNROLL==1) - c += a1; + } +#if (UNROLL == 1) + c += a1; #endif -#if(UNROLL==2) - c += a1+a2; +#if (UNROLL == 2) + c += a1 + a2; #endif -#if(UNROLL==3) - c += a1+a2+a3; +#if (UNROLL == 3) + c += a1 + a2 + a3; #endif -#if(UNROLL==4) - c += a1+a2+a3+a4; +#if (UNROLL == 4) + c += a1 + a2 + a3 + a4; #endif -#if(UNROLL==5) - c += a1+a2+a3+a4+a5; +#if (UNROLL == 5) + c += a1 + a2 + a3 + a4 + a5; #endif -#if(UNROLL==6) - c += a1+a2+a3+a4+a5+a6; +#if (UNROLL == 6) + c += a1 + a2 + a3 + a4 + a5 + a6; #endif -#if(UNROLL==7) - c += a1+a2+a3+a4+a5+a6+a7; +#if (UNROLL == 7) + c += a1 + a2 + a3 + a4 + a5 + a6 + a7; #endif -#if(UNROLL==8) - c += a1+a2+a3+a4+a5+a6+a7+a8; +#if (UNROLL == 8) + c += a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8; #endif + } + C(i) = c; + }); + Kokkos::fence(); + } + double seconds = timer.seconds(); - } - C(i) = c ; - }); - Kokkos::fence(); + double bytes = 1.0 * N * K * R * (2 * sizeof(Scalar) + sizeof(int)) + + 1.0 * N * R * sizeof(Scalar); + double flops = 1.0 * N * K * R * (F * 2 * UNROLL + 2 * (UNROLL - 1)); + double gather_ops = 1.0 * N * K * R * 2; + printf( + "SNKDRUF: %i %i %i %i %i %i %i Time: %lfs Bandwidth: %lfGiB/s GFlop/s: " + "%lf GGather/s: %lf\n", + sizeof(Scalar) / 4, N, K, D, R, UNROLL, F, seconds, + 1.0 * bytes / seconds / 1024 / 1024 / 1024, 1.e-9 * flops / seconds, + 1.e-9 * gather_ops / seconds); } - double seconds = timer.seconds(); - - double bytes = 1.0*N*K*R*(2*sizeof(Scalar)+sizeof(int)) + 1.0*N*R*sizeof(Scalar); - double flops = 1.0*N*K*R*(F*2*UNROLL + 2*(UNROLL-1)); - double gather_ops = 1.0*N*K*R*2; - printf("SNKDRUF: %i %i %i %i %i %i %i Time: %lfs Bandwidth: %lfGiB/s GFlop/s: %lf GGather/s: %lf\n",sizeof(Scalar)/4,N,K,D,R,UNROLL,F,seconds,1.0*bytes/seconds/1024/1024/1024,1.e-9*flops/seconds,1.e-9*gather_ops/seconds); -} }; diff --git a/lib/kokkos/benchmarks/gather/main.cpp b/lib/kokkos/benchmarks/gather/main.cpp index ca5238e7fd..6a2db3e024 100644 --- a/lib/kokkos/benchmarks/gather/main.cpp +++ b/lib/kokkos/benchmarks/gather/main.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,23 +42,26 @@ //@HEADER */ -#include -#include -#include -#include +#include +#include +#include +#include int main(int argc, char* argv[]) { - Kokkos::initialize(argc,argv); + Kokkos::initialize(argc, argv); - if(argc<8) { + if (argc < 8) { printf("Arguments: S N K D\n"); - printf(" S: Scalar Type Size (1==float, 2==double, 4=complex)\n"); + printf( + " S: Scalar Type Size (1==float, 2==double, 4=complex)\n"); printf(" N: Number of entities\n"); printf(" K: Number of things to gather per entity\n"); printf(" D: Max distance of gathered things of an entity\n"); printf(" R: how often to loop through the K dimension with each team\n"); printf(" U: how many independent flops to do per load\n"); - printf(" F: how many times to repeat the U unrolled operations before reading next element\n"); + printf( + " F: how many times to repeat the U unrolled operations before " + "reading next element\n"); printf("Example Input GPU:\n"); printf(" Bandwidth Bound : 2 10000000 1 1 10 1 1\n"); printf(" Cache Bound : 2 10000000 64 1 10 1 1\n"); @@ -68,7 +72,6 @@ int main(int argc, char* argv[]) { return 0; } - int S = atoi(argv[1]); int N = atoi(argv[2]); int K = atoi(argv[3]); @@ -77,17 +80,22 @@ int main(int argc, char* argv[]) { int U = atoi(argv[6]); int F = atoi(argv[7]); - if( (S!=1) && (S!=2) && (S!=4)) {printf("S must be one of 1,2,4\n"); return 0;} - if( N(N,K,D,R,U,F); + if ((S != 1) && (S != 2) && (S != 4)) { + printf("S must be one of 1,2,4\n"); + return 0; + } + if (N < D) { + printf("N must be larger or equal to D\n"); + return 0; + } + if (S == 1) { + run_gather_test(N, K, D, R, U, F); } - if(S==2) { - run_gather_test(N,K,D,R,U,F); + if (S == 2) { + run_gather_test(N, K, D, R, U, F); } - if(S==4) { - run_gather_test >(N,K,D,R,U,F); + if (S == 4) { + run_gather_test >(N, K, D, R, U, F); } Kokkos::finalize(); } - diff --git a/lib/kokkos/benchmarks/gups/gups-kokkos.cc b/lib/kokkos/benchmarks/gups/gups-kokkos.cc index 4602adda79..9ac59be4a6 100644 --- a/lib/kokkos/benchmarks/gups/gups-kokkos.cc +++ b/lib/kokkos/benchmarks/gups/gups-kokkos.cc @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/lib/kokkos/benchmarks/policy_performance/main.cpp b/lib/kokkos/benchmarks/policy_performance/main.cpp index 2f5395734a..332e5574da 100644 --- a/lib/kokkos/benchmarks/policy_performance/main.cpp +++ b/lib/kokkos/benchmarks/policy_performance/main.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,67 +45,86 @@ #include #include "policy_perf_test.hpp" -int main(int argc, char* argv[] ) { - Kokkos::initialize(argc,argv); +int main(int argc, char* argv[]) { + Kokkos::initialize(argc, argv); - if(argc<10) { + if (argc < 10) { printf(" Ten arguments are needed to run this program:\n"); - printf(" (1)team_range, (2)thread_range, (3)vector_range, (4)outer_repeat, (5)thread_repeat, (6)vector_repeat, (7)team_size, (8)vector_size, (9)schedule, (10)test_type\n"); + printf( + " (1)team_range, (2)thread_range, (3)vector_range, (4)outer_repeat, " + "(5)thread_repeat, (6)vector_repeat, (7)team_size, (8)vector_size, " + "(9)schedule, (10)test_type\n"); printf(" team_range: number of teams (league_size)\n"); printf(" thread_range: range for nested TeamThreadRange parallel_*\n"); printf(" vector_range: range for nested ThreadVectorRange parallel_*\n"); printf(" outer_repeat: number of repeats for outer parallel_* call\n"); - printf(" thread_repeat: number of repeats for TeamThreadRange parallel_* call\n"); - printf(" vector_repeat: number of repeats for ThreadVectorRange parallel_* call\n"); + printf( + " thread_repeat: number of repeats for TeamThreadRange parallel_* " + "call\n"); + printf( + " vector_repeat: number of repeats for ThreadVectorRange parallel_* " + "call\n"); printf(" team_size: number of team members (team_size)\n"); printf(" vector_size: desired vectorization (if possible)\n"); printf(" schedule: 1 == Static 2 == Dynamic\n"); - printf(" test_type: 3-digit code XYZ for testing (nested) parallel_*\n"); - printf(" code key: XYZ X in {1,2,3,4,5}, Y in {0,1,2}, Z in {0,1,2}\n"); + printf( + " test_type: 3-digit code XYZ for testing (nested) parallel_*\n"); + printf( + " code key: XYZ X in {1,2,3,4,5}, Y in {0,1,2}, Z in " + "{0,1,2}\n"); printf(" TeamPolicy:\n"); - printf(" X: 0 = none (never used, makes no sense); 1 = parallel_for; 2 = parallel_reduce\n"); - printf(" Y: 0 = none; 1 = parallel_for; 2 = parallel_reduce\n"); - printf(" Z: 0 = none; 1 = parallel_for; 2 = parallel_reduce\n"); + printf( + " X: 0 = none (never used, makes no sense); 1 = " + "parallel_for; 2 = parallel_reduce\n"); + printf( + " Y: 0 = none; 1 = parallel_for; 2 = " + "parallel_reduce\n"); + printf( + " Z: 0 = none; 1 = parallel_for; 2 = " + "parallel_reduce\n"); printf(" RangePolicy:\n"); - printf(" X: 3 = parallel_for; 4 = parallel_reduce; 5 = parallel_scan\n"); + printf( + " X: 3 = parallel_for; 4 = parallel_reduce; 5 = " + "parallel_scan\n"); printf(" Y: 0 = none\n"); printf(" Z: 0 = none\n"); printf(" Example Input:\n"); - printf(" 100000 32 32 100 100 100 8 1 1 100\n"); + printf(" 100000 32 32 100 100 100 8 1 1 100\n"); Kokkos::finalize(); return 0; } - int team_range = atoi(argv[1]); + int team_range = atoi(argv[1]); int thread_range = atoi(argv[2]); int vector_range = atoi(argv[3]); - int outer_repeat = atoi(argv[4]); + int outer_repeat = atoi(argv[4]); int thread_repeat = atoi(argv[5]); int vector_repeat = atoi(argv[6]); - int team_size = atoi(argv[7]); + int team_size = atoi(argv[7]); int vector_size = atoi(argv[8]); - int schedule = atoi(argv[9]); - int test_type = atoi(argv[10]); + int schedule = atoi(argv[9]); + int test_type = atoi(argv[10]); - int disable_verbose_output = 0; - if ( argc > 11 ) { + int disable_verbose_output = 0; + if (argc > 11) { disable_verbose_output = atoi(argv[11]); } - if ( schedule != 1 && schedule != 2 ) { + if (schedule != 1 && schedule != 2) { printf("schedule: %d\n", schedule); printf("Options for schedule are: 1 == Static 2 == Dynamic\n"); Kokkos::finalize(); return -1; } - if ( test_type != 100 && test_type != 110 && test_type != 111 && test_type != 112 && test_type != 120 && test_type != 121 && test_type != 122 - && test_type != 200 && test_type != 210 && test_type != 211 && test_type != 212 && test_type != 220 && test_type != 221 && test_type != 222 - && test_type != 300 && test_type != 400 && test_type != 500 - ) - { + if (test_type != 100 && test_type != 110 && test_type != 111 && + test_type != 112 && test_type != 120 && test_type != 121 && + test_type != 122 && test_type != 200 && test_type != 210 && + test_type != 211 && test_type != 212 && test_type != 220 && + test_type != 221 && test_type != 222 && test_type != 300 && + test_type != 400 && test_type != 500) { printf("Incorrect test_type option\n"); Kokkos::finalize(); return -2; @@ -112,56 +132,85 @@ int main(int argc, char* argv[] ) { double result = 0.0; - Kokkos::parallel_reduce( "parallel_reduce warmup", Kokkos::TeamPolicy<>(10,1), - KOKKOS_LAMBDA(const Kokkos::TeamPolicy<>::member_type team, double& lval) { - lval += 1; - }, result); + Kokkos::parallel_reduce( + "parallel_reduce warmup", Kokkos::TeamPolicy<>(10, 1), + KOKKOS_LAMBDA(const Kokkos::TeamPolicy<>::member_type team, + double& lval) { lval += 1; }, + result); - typedef Kokkos::View view_type_1d; - typedef Kokkos::View view_type_2d; + typedef Kokkos::View view_type_1d; + typedef Kokkos::View view_type_2d; typedef Kokkos::View view_type_3d; // Allocate view without initializing - // Call a 'warmup' test with 1 repeat - this will initialize the corresponding view appropriately for test and should obey first-touch etc - // Second call to test is the one we actually care about and time - view_type_1d v_1( Kokkos::ViewAllocateWithoutInitializing("v_1"), team_range*team_size); - view_type_2d v_2( Kokkos::ViewAllocateWithoutInitializing("v_2"), team_range*team_size, thread_range); - view_type_3d v_3( Kokkos::ViewAllocateWithoutInitializing("v_3"), team_range*team_size, thread_range, vector_range); + // Call a 'warmup' test with 1 repeat - this will initialize the corresponding + // view appropriately for test and should obey first-touch etc Second call to + // test is the one we actually care about and time + view_type_1d v_1(Kokkos::ViewAllocateWithoutInitializing("v_1"), + team_range * team_size); + view_type_2d v_2(Kokkos::ViewAllocateWithoutInitializing("v_2"), + team_range * team_size, thread_range); + view_type_3d v_3(Kokkos::ViewAllocateWithoutInitializing("v_3"), + team_range * team_size, thread_range, vector_range); double result_computed = 0.0; - double result_expect = 0.0; - double time = 0.0; + double result_expect = 0.0; + double time = 0.0; - if(schedule==1) { - if ( test_type != 500 ) { + if (schedule == 1) { + if (test_type != 500) { // warmup - no repeat of loops - test_policy,int>(team_range,thread_range,vector_range,1,1,1,team_size,vector_size,test_type,v_1,v_2,v_3,result_computed,result_expect,time); - test_policy,int>(team_range,thread_range,vector_range,outer_repeat,thread_repeat,vector_repeat,team_size,vector_size,test_type,v_1,v_2,v_3,result_computed,result_expect,time); - } - else { + test_policy, int>( + team_range, thread_range, vector_range, 1, 1, 1, team_size, + vector_size, test_type, v_1, v_2, v_3, result_computed, result_expect, + time); + test_policy, int>( + team_range, thread_range, vector_range, outer_repeat, thread_repeat, + vector_repeat, team_size, vector_size, test_type, v_1, v_2, v_3, + result_computed, result_expect, time); + } else { // parallel_scan: initialize 1d view for parallel_scan - test_policy,int>(team_range,thread_range,vector_range,1,1,1,team_size,vector_size,100,v_1,v_2,v_3,result_computed,result_expect,time); - test_policy,int>(team_range,thread_range,vector_range,outer_repeat,thread_repeat,vector_repeat,team_size,vector_size,test_type,v_1,v_2,v_3,result_computed,result_expect,time); + test_policy, int>( + team_range, thread_range, vector_range, 1, 1, 1, team_size, + vector_size, 100, v_1, v_2, v_3, result_computed, result_expect, + time); + test_policy, int>( + team_range, thread_range, vector_range, outer_repeat, thread_repeat, + vector_repeat, team_size, vector_size, test_type, v_1, v_2, v_3, + result_computed, result_expect, time); } } - if(schedule==2) { - if ( test_type != 500 ) { + if (schedule == 2) { + if (test_type != 500) { // warmup - no repeat of loops - test_policy,int>(team_range,thread_range,vector_range,1,1,1,team_size,vector_size,test_type,v_1,v_2,v_3,result_computed,result_expect,time); - test_policy,int>(team_range,thread_range,vector_range,outer_repeat,thread_repeat,vector_repeat,team_size,vector_size,test_type,v_1,v_2,v_3,result_computed,result_expect,time); - } - else { + test_policy, int>( + team_range, thread_range, vector_range, 1, 1, 1, team_size, + vector_size, test_type, v_1, v_2, v_3, result_computed, result_expect, + time); + test_policy, int>( + team_range, thread_range, vector_range, outer_repeat, thread_repeat, + vector_repeat, team_size, vector_size, test_type, v_1, v_2, v_3, + result_computed, result_expect, time); + } else { // parallel_scan: initialize 1d view for parallel_scan - test_policy,int>(team_range,thread_range,vector_range,1,1,1,team_size,vector_size,100,v_1,v_2,v_3,result_computed,result_expect,time); - test_policy,int>(team_range,thread_range,vector_range,outer_repeat,thread_repeat,vector_repeat,team_size,vector_size,test_type,v_1,v_2,v_3,result_computed,result_expect,time); + test_policy, int>( + team_range, thread_range, vector_range, 1, 1, 1, team_size, + vector_size, 100, v_1, v_2, v_3, result_computed, result_expect, + time); + test_policy, int>( + team_range, thread_range, vector_range, outer_repeat, thread_repeat, + vector_repeat, team_size, vector_size, test_type, v_1, v_2, v_3, + result_computed, result_expect, time); } } - if ( disable_verbose_output == 0 ) { - printf("%7i %4i %2i %9i %4i %4i %4i %2i %1i %3i %e %e %lf\n",team_range,thread_range,vector_range,outer_repeat,thread_repeat,vector_repeat,team_size,vector_size,schedule,test_type,result_computed,result_expect,time); - } - else { - printf("%lf\n",time); + if (disable_verbose_output == 0) { + printf("%7i %4i %2i %9i %4i %4i %4i %2i %1i %3i %e %e %lf\n", team_range, + thread_range, vector_range, outer_repeat, thread_repeat, + vector_repeat, team_size, vector_size, schedule, test_type, + result_computed, result_expect, time); + } else { + printf("%lf\n", time); } Kokkos::finalize(); diff --git a/lib/kokkos/benchmarks/policy_performance/policy_perf_test.hpp b/lib/kokkos/benchmarks/policy_performance/policy_perf_test.hpp index 1ab437928d..7a1500891f 100644 --- a/lib/kokkos/benchmarks/policy_performance/policy_perf_test.hpp +++ b/lib/kokkos/benchmarks/policy_performance/policy_perf_test.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -43,297 +44,375 @@ #include -template < class ViewType > +template struct ParallelScanFunctor { using value_type = double; ViewType v; - ParallelScanFunctor( const ViewType & v_ ) - : v(v_) - {} + ParallelScanFunctor(const ViewType& v_) : v(v_) {} KOKKOS_INLINE_FUNCTION - void operator()( const int idx, value_type& val, const bool& final ) const - { - // inclusive scan - val += v(idx); - if ( final ) { - v(idx) = val; - } + void operator()(const int idx, value_type& val, const bool& final) const { + // inclusive scan + val += v(idx); + if (final) { + v(idx) = val; } + } }; -template +template void test_policy(int team_range, int thread_range, int vector_range, - int outer_repeat, int thread_repeat, int inner_repeat, - int team_size, int vector_size, int test_type, - ViewType1 &v1, ViewType2 &v2, ViewType3 &v3, - double &result, double &result_expect, double &time) { - - typedef Kokkos::TeamPolicy t_policy; + int outer_repeat, int thread_repeat, int inner_repeat, + int team_size, int vector_size, int test_type, ViewType1& v1, + ViewType2& v2, ViewType3& v3, double& result, + double& result_expect, double& time) { + typedef Kokkos::TeamPolicy t_policy; typedef typename t_policy::member_type t_team; Kokkos::Timer timer; - for(int orep = 0; orep(v1) + Kokkos::parallel_scan("500 outer scan", team_size * team_range, + ParallelScanFunctor(v1) #if 0 // This does not compile with pre Cuda 8.0 - see Github Issue #913 for explanation KOKKOS_LAMBDA (const int idx, double& val, const bool& final) { @@ -345,11 +424,12 @@ void test_policy(int team_range, int thread_range, int vector_range, } #endif ); - // result = v1( team_size*team_range - 1 ); // won't work with Cuda - need to copy result back to host to print - // result_expect = 0.5*(team_size*team_range)*(team_size*team_range-1); + // result = v1( team_size*team_range - 1 ); // won't work with Cuda - need + // to copy result back to host to print result_expect = + // 0.5*(team_size*team_range)*(team_size*team_range-1); } - } // end outer for loop + } // end outer for loop time = timer.seconds(); -} //end test_policy +} // end test_policy diff --git a/lib/kokkos/benchmarks/policy_performance/script_sample_usage.sh b/lib/kokkos/benchmarks/policy_performance/script_sample_usage.sh index 1c2db56648..f4bfb87f8f 100755 --- a/lib/kokkos/benchmarks/policy_performance/script_sample_usage.sh +++ b/lib/kokkos/benchmarks/policy_performance/script_sample_usage.sh @@ -2,7 +2,7 @@ # Sample script for benchmarking policy performance -# Suggested environment variables to export prior to executing script: +# Suggested enviroment variables to export prior to executing script: # KNL: # OMP_NUM_THREADS=256 KMP_AFFINITY=compact # Power: diff --git a/lib/kokkos/benchmarks/stream/stream-kokkos.cc b/lib/kokkos/benchmarks/stream/stream-kokkos.cc index 370995432e..6ce789dd82 100644 --- a/lib/kokkos/benchmarks/stream/stream-kokkos.cc +++ b/lib/kokkos/benchmarks/stream/stream-kokkos.cc @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/lib/kokkos/bin/hpcbind b/lib/kokkos/bin/hpcbind index 6af091a7d8..b185a92821 100755 --- a/lib/kokkos/bin/hpcbind +++ b/lib/kokkos/bin/hpcbind @@ -383,7 +383,7 @@ fi # Check unknown arguments ################################################################################ if [[ ${#UNKNOWN_ARGS[*]} > 0 ]]; then - echo "HPCBIND Unknown options: ${UNKNOWN_ARGS[*]}" > >(tee -a ${HPCBIND_LOG}) + echo "HPCBIND Uknown options: ${UNKNOWN_ARGS[*]}" > >(tee -a ${HPCBIND_LOG}) exit 1 fi diff --git a/lib/kokkos/bin/nvcc_wrapper b/lib/kokkos/bin/nvcc_wrapper index 94bc72854e..8a23d0d620 100755 --- a/lib/kokkos/bin/nvcc_wrapper +++ b/lib/kokkos/bin/nvcc_wrapper @@ -85,11 +85,11 @@ first_xcompiler_arg=1 temp_dir=${TMPDIR:-/tmp} -# Check if we have an optimization argument already -optimization_applied=0 +# optimization flag added as a command-line argument +optimization_flag="" -# Check if we have -std=c++X or --std=c++X already -stdcxx_applied=0 +# std standard flag added as a command-line argument +std_flag="" # Run nvcc a second time to generate dependencies if needed depfile_separate=0 @@ -99,6 +99,10 @@ depfile_target_arg="" # Option to remove duplicate libraries and object files remove_duplicate_link_files=0 +function warn_std_flag() { + echo "nvcc_wrapper - *warning* you have set multiple standard flags (-std=c++1* or --std=c++1*), only the last is used because nvcc can only accept a single std setting" +} + #echo "Arguments: $# $@" while [ $# -gt 0 ] @@ -130,12 +134,16 @@ do ;; # Ensure we only have one optimization flag because NVCC doesn't allow muliple -O*) - if [ $optimization_applied -eq 1 ]; then - echo "nvcc_wrapper - *warning* you have set multiple optimization flags (-O*), only the first is used because nvcc can only accept a single optimization setting." + if [ -n "$optimization_flag" ]; then + echo "nvcc_wrapper - *warning* you have set multiple optimization flags (-O*), only the last is used because nvcc can only accept a single optimization setting." + shared_args=${shared_args/ $optimization_flag/} + fi + if [ "$1" = "-O" ]; then + optimization_flag="-O2" else - shared_args="$shared_args $1" - optimization_applied=1 + optimization_flag=$1 fi + shared_args="$shared_args $optimization_flag" ;; #Handle shared args (valid for both nvcc and the host compiler) -D*) @@ -171,7 +179,7 @@ do shift ;; #Handle known nvcc args - --dryrun|--verbose|--keep|--keep-dir*|-G|--relocatable-device-code*|-lineinfo|-expt-extended-lambda|--resource-usage|-Xptxas*) + --dryrun|--verbose|--keep|--keep-dir*|-G|--relocatable-device-code*|-lineinfo|-expt-extended-lambda|--resource-usage|-Xptxas*|--fmad*) cuda_args="$cuda_args $1" ;; #Handle more known nvcc args @@ -179,21 +187,43 @@ do cuda_args="$cuda_args $1" ;; #Handle known nvcc args that have an argument - -rdc|-maxrregcount|--default-stream) + -rdc|-maxrregcount|--default-stream|-Xnvlink|--fmad) cuda_args="$cuda_args $1 $2" shift ;; -rdc=*|-maxrregcount*|--maxrregcount*) cuda_args="$cuda_args $1" ;; - #Handle c++11 - --std=c++11|-std=c++11|--std=c++14|-std=c++14|--std=c++1y|-std=c++1y|--std=c++17|-std=c++17|--std=c++1z|-std=c++1z) - if [ $stdcxx_applied -eq 1 ]; then - echo "nvcc_wrapper - *warning* you have set multiple optimization flags (-std=c++1* or --std=c++1*), only the first is used because nvcc can only accept a single std setting" - else - shared_args="$shared_args $1" - stdcxx_applied=1 + #Handle unsupported standard flags + --std=c++1y|-std=c++1y|--std=c++1z|-std=c++1z|--std=gnu++1y|-std=gnu++1y|--std=gnu++1z|-std=gnu++1z|--std=c++2a|-std=c++2a|--std=c++17|-std=c++17) + fallback_std_flag="-std=c++14" + # this is hopefully just occurring in a downstream project during CMake feature tests + # we really have no choice here but to accept the flag and change to an accepted C++ standard + echo "nvcc_wrapper does not accept standard flags $1 since partial standard flags and standards after C++14 are not supported. nvcc_wrapper will use $fallback_std_flag instead. It is undefined behavior to use this flag. This should only be occurring during CMake configuration." + if [ -n "$std_flag" ]; then + warn_std_flag + shared_args=${shared_args/ $std_flag/} + fi + std_flag=$fallback_std_flag + shared_args="$shared_args $std_flag" + ;; + -std=gnu*) + corrected_std_flag=${1/gnu/c} + echo "nvcc_wrapper has been given GNU extension standard flag $1 - reverting flag to $corrected_std_flag" + if [ -n "$std_flag" ]; then + warn_std_flag + shared_args=${shared_args/ $std_flag/} + fi + std_flag=$corrected_std_flag + shared_args="$shared_args $std_flag" + ;; + --std=c++11|-std=c++11|--std=c++14|-std=c++14) + if [ -n "$std_flag" ]; then + warn_std_flag + shared_args=${shared_args/ $std_flag/} fi + std_flag=$1 + shared_args="$shared_args $std_flag" ;; #strip of -std=c++98 due to nvcc warnings and Tribits will place both -std=c++11 and -std=c++98 @@ -308,16 +338,6 @@ do shift done -#Check if nvcc exists -if [ $host_only -ne 1 ]; then - var=$(which nvcc ) - if [ $? -gt 0 ]; then - echo "Could not find nvcc in PATH" - exit $? - fi -fi - - # Only print host compiler version if [ $get_host_version -eq 1 ]; then $host_compiler --version @@ -372,6 +392,9 @@ if [ $first_xcompiler_arg -eq 0 ]; then nvcc_command="$nvcc_command -Xcompiler $xcompiler_args" fi +#Replace all commas in xcompiler_args with a space for the host only command +xcompiler_args=${xcompiler_args//,/" "} + #Compose host only command host_command="$host_compiler $shared_args $host_only_args $compile_arg $output_arg $xcompiler_args $host_linker_args $shared_versioned_libraries_host" diff --git a/lib/kokkos/cm_generate_makefile.bash b/lib/kokkos/cm_generate_makefile.bash new file mode 100755 index 0000000000..fd7cfe2d32 --- /dev/null +++ b/lib/kokkos/cm_generate_makefile.bash @@ -0,0 +1,339 @@ +#!/bin/bash + +update_kokkos_devices() { + SEARCH_TEXT="*$1*" + if [[ $KOKKOS_DEVICES == $SEARCH_TEXT ]]; then + echo kokkos devices already includes $SEARCH_TEXT + else + if [ "$KOKKOS_DEVICES" = "" ]; then + KOKKOS_DEVICES="$1" + echo reseting kokkos devices to $KOKKOS_DEVICES + else + KOKKOS_DEVICES="${KOKKOS_DEVICES},$1" + echo appending to kokkos devices $KOKKOS_DEVICES + fi + fi +} + +get_kokkos_device_list() { + KOKKOS_DEVICE_CMD= + PARSE_DEVICES_LST=$(echo $KOKKOS_DEVICES | tr "," "\n") + for DEVICE_ in $PARSE_DEVICES_LST + do + UC_DEVICE=$(echo $DEVICE_ | tr "[:lower:]" "[:upper:]") + KOKKOS_DEVICE_CMD="-DKokkos_ENABLE_${UC_DEVICE}=ON ${KOKKOS_DEVICE_CMD}" + done +} + +get_kokkos_arch_list() { + KOKKOS_ARCH_CMD= + PARSE_ARCH_LST=$(echo $KOKKOS_ARCH | tr "," "\n") + for ARCH_ in $PARSE_ARCH_LST + do + UC_ARCH=$(echo $ARCH_ | tr "[:lower:]" "[:upper:]") + KOKKOS_ARCH_CMD="-DKokkos_ARCH_${UC_ARCH}=ON ${KOKKOS_ARCH_CMD}" + done +} + +get_kokkos_cuda_option_list() { + echo parsing KOKKOS_CUDA_OPTIONS=$KOKKOS_CUDA_OPTIONS + KOKKOS_CUDA_OPTION_CMD= + PARSE_CUDA_LST=$(echo $KOKKOS_CUDA_OPTIONS | tr "," "\n") + for CUDA_ in $PARSE_CUDA_LST + do + CUDA_OPT_NAME= + if [ "${CUDA_}" == "enable_lambda" ]; then + CUDA_OPT_NAME=CUDA_LAMBDA + elif [ "${CUDA_}" == "rdc" ]; then + CUDA_OPT_NAME=CUDA_RELOCATABLE_DEVICE_CODE + elif [ "${CUDA_}" == "force_uvm" ]; then + CUDA_OPT_NAME=CUDA_UVM + elif [ "${CUDA_}" == "use_ldg" ]; then + CUDA_OPT_NAME=CUDA_LDG_INTRINSIC + else + echo "${CUDA_} is not a valid cuda options..." + fi + if [ "${CUDA_OPT_NAME}" != "" ]; then + KOKKOS_CUDA_OPTION_CMD="-DKokkos_ENABLE_${CUDA_OPT_NAME}=ON ${KOKKOS_CUDA_OPTION_CMD}" + fi + done +} + +get_kokkos_option_list() { + echo parsing KOKKOS_OPTIONS=$KOKKOS_OPTIONS + KOKKOS_OPTION_CMD= + PARSE_OPTIONS_LST=$(echo $KOKKOS_OPTIONS | tr "," "\n") + for OPT_ in $PARSE_OPTIONS_LST + do + UC_OPT_=$(echo $OPT_ | tr "[:lower:]" "[:upper:]") + if [[ "$UC_OPT_" == *DISABLE* ]]; then + FLIP_OPT_=${UC_OPT_/DISABLE/ENABLE} + KOKKOS_OPTION_CMD="-DKokkos_${FLIP_OPT_}=OFF ${KOKKOS_OPTION_CMD}" + elif [[ "$UC_OPT_" == *ENABLE* ]]; then + KOKKOS_OPTION_CMD="-DKokkos_${UC_OPT_}=ON ${KOKKOS_OPTION_CMD}" + else + KOKKOS_OPTION_CMD="-DKokkos_ENABLE_${UC_OPT_}=ON ${KOKKOS_OPTION_CMD}" + fi + done +} + +display_help_text() { + + echo "Kokkos configure options:" + echo "" + echo "--kokkos-path=/Path/To/Kokkos: Path to the Kokkos root directory." + echo "--prefix=/Install/Path: Path to install the Kokkos library." + echo "" + echo "--with-cuda[=/Path/To/Cuda]: Enable Cuda and set path to Cuda Toolkit." + echo "--with-openmp: Enable OpenMP backend." + echo "--with-pthread: Enable Pthreads backend." + echo "--with-serial: Enable Serial backend." + echo "--with-devices: Explicitly add a set of backends." + echo "" + echo "--arch=[OPT]: Set target architectures. Options are:" + echo " [AMD]" + echo " AMDAVX = AMD CPU" + echo " EPYC = AMD EPYC Zen-Core CPU" + echo " [ARM]" + echo " ARMv80 = ARMv8.0 Compatible CPU" + echo " ARMv81 = ARMv8.1 Compatible CPU" + echo " ARMv8-ThunderX = ARMv8 Cavium ThunderX CPU" + echo " ARMv8-TX2 = ARMv8 Cavium ThunderX2 CPU" + echo " [IBM]" + echo " BGQ = IBM Blue Gene Q" + echo " Power7 = IBM POWER7 and POWER7+ CPUs" + echo " Power8 = IBM POWER8 CPUs" + echo " Power9 = IBM POWER9 CPUs" + echo " [Intel]" + echo " WSM = Intel Westmere CPUs" + echo " SNB = Intel Sandy/Ivy Bridge CPUs" + echo " HSW = Intel Haswell CPUs" + echo " BDW = Intel Broadwell Xeon E-class CPUs" + echo " SKX = Intel Sky Lake Xeon E-class HPC CPUs (AVX512)" + echo " [Intel Xeon Phi]" + echo " KNC = Intel Knights Corner Xeon Phi" + echo " KNL = Intel Knights Landing Xeon Phi" + echo " [NVIDIA]" + echo " Kepler30 = NVIDIA Kepler generation CC 3.0" + echo " Kepler32 = NVIDIA Kepler generation CC 3.2" + echo " Kepler35 = NVIDIA Kepler generation CC 3.5" + echo " Kepler37 = NVIDIA Kepler generation CC 3.7" + echo " Maxwell50 = NVIDIA Maxwell generation CC 5.0" + echo " Maxwell52 = NVIDIA Maxwell generation CC 5.2" + echo " Maxwell53 = NVIDIA Maxwell generation CC 5.3" + echo " Pascal60 = NVIDIA Pascal generation CC 6.0" + echo " Pascal61 = NVIDIA Pascal generation CC 6.1" + echo " Volta70 = NVIDIA Volta generation CC 7.0" + echo " Volta72 = NVIDIA Volta generation CC 7.2" + echo "" + echo "--compiler=/Path/To/Compiler Set the compiler." + echo "--debug,-dbg: Enable Debugging." + echo "--cxxflags=[FLAGS] Overwrite CXXFLAGS for library build and test" + echo " build. This will still set certain required" + echo " flags via KOKKOS_CXXFLAGS (such as -fopenmp," + echo " --std=c++11, etc.)." + echo "--cxxstandard=[FLAGS] Overwrite KOKKOS_CXX_STANDARD for library build and test" + echo " c++11 (default), c++14, c++17, c++1y, c++1z, c++2a" + echo "--ldflags=[FLAGS] Overwrite LDFLAGS for library build and test" + echo " build. This will still set certain required" + echo " flags via KOKKOS_LDFLAGS (such as -fopenmp," + echo " -lpthread, etc.)." + echo "--with-gtest=/Path/To/Gtest: Set path to gtest. (Used in unit and performance" + echo " tests.)" + echo "--with-hwloc=/Path/To/Hwloc: Set path to hwloc library." + echo "--with-memkind=/Path/To/MemKind: Set path to memkind library." + echo "--with-options=[OPT]: Additional options to Kokkos:" + echo " compiler_warnings" + echo " aggressive_vectorization = add ivdep on loops" + echo " disable_profiling = do not compile with profiling hooks" + echo " " + echo "--with-cuda-options=[OPT]: Additional options to CUDA:" + echo " force_uvm, use_ldg, enable_lambda, rdc" + echo "--with-hpx-options=[OPT]: Additional options to HPX:" + echo " enable_async_dispatch" + echo "--gcc-toolchain=/Path/To/GccRoot: Set the gcc toolchain to use with clang (e.g. /usr)" + echo "--make-j=[NUM]: DEPRECATED: call make with appropriate" + echo " -j flag" + +} + +while [[ $# > 0 ]] +do + key="$1" + + case $key in + --kokkos-path*) + KOKKOS_PATH="${key#*=}" + ;; + --hpx-path*) + HPX_PATH="${key#*=}" + ;; + --prefix*) + PREFIX="${key#*=}" + ;; + --with-cuda) + update_kokkos_devices Cuda + CUDA_PATH_NVCC=$(command -v nvcc) + CUDA_PATH=${CUDA_PATH_NVCC%/bin/nvcc} + ;; + # Catch this before '--with-cuda*' + --with-cuda-options*) + KOKKOS_CUDA_OPTIONS="${key#*=}" + ;; + --with-cuda*) + update_kokkos_devices Cuda + CUDA_PATH="${key#*=}" + ;; + --with-openmp) + update_kokkos_devices OpenMP + ;; + --with-pthread) + update_kokkos_devices Pthread + ;; + --with-serial) + update_kokkos_devices Serial + ;; + --with-hpx-options*) + KOKKOS_HPX_OPT="${key#*=}" + ;; + --with-hpx*) + update_kokkos_devices HPX + if [ -z "$HPX_PATH" ]; then + HPX_PATH="${key#*=}" + fi + ;; + --with-devices*) + DEVICES="${key#*=}" + PARSE_DEVICES=$(echo $DEVICES | tr "," "\n") + for DEVICE_ in $PARSE_DEVICES + do + update_kokkos_devices $DEVICE_ + done + ;; + --with-gtest*) + GTEST_PATH="${key#*=}" + ;; + --with-hwloc*) + HWLOC_PATH="${key#*=}" + ;; + --with-memkind*) + MEMKIND_PATH="${key#*=}" + ;; + --arch*) + KOKKOS_ARCH="${key#*=}" + ;; + --cxxflags*) + KOKKOS_CXXFLAGS="${key#*=}" + KOKKOS_CXXFLAGS=${KOKKOS_CXXFLAGS//,/ } + ;; + --cxxstandard*) + KOKKOS_CXX_STANDARD="${key#*=}" + ;; + --ldflags*) + KOKKOS_LDFLAGS="${key#*=}" + ;; + --debug|-dbg) + KOKKOS_DEBUG=yes + ;; + --make-j*) + echo "Warning: ${key} is deprecated" + echo "Call make with appropriate -j flag" + ;; + --compiler*) + COMPILER="${key#*=}" + CNUM=$(command -v ${COMPILER} 2>&1 >/dev/null | grep "no ${COMPILER}" | wc -l) + if [ ${CNUM} -gt 0 ]; then + echo "Invalid compiler by --compiler command: '${COMPILER}'" + exit + fi + if [[ ! -n ${COMPILER} ]]; then + echo "Empty compiler specified by --compiler command." + exit + fi + CNUM=$(command -v ${COMPILER} | grep ${COMPILER} | wc -l) + if [ ${CNUM} -eq 0 ]; then + echo "Invalid compiler by --compiler command: '${COMPILER}'" + exit + fi + # ... valid compiler, ensure absolute path set + WCOMPATH=$(command -v $COMPILER) + COMPDIR=$(dirname $WCOMPATH) + COMPNAME=$(basename $WCOMPATH) + COMPILER=${COMPDIR}/${COMPNAME} + ;; + --with-options*) + KOKKOS_OPTIONS="${key#*=}" + ;; + --gcc-toolchain*) + KOKKOS_GCC_TOOLCHAIN="${key#*=}" + ;; + --help) + display_help_text + exit 0 + ;; + *) + echo "warning: ignoring unknown option $key" + ;; + esac + + shift +done + + +if [ "$COMPILER" == "" ]; then + COMPILER_CMD= +else + COMPILER_CMD=-DCMAKE_CXX_COMPILER=$COMPILER +fi + +if [ "$KOKKOS_DEBUG" == "" ]; then + KOKKOS_DEBUG_CMD=-DCMAKE_BUILD_TYPE=RELEASE +else + KOKKOS_DEBUG_CMD=-DCMAKE_BUILD_TYPE=DEBUG +fi + +if [ ! -e ${KOKKOS_PATH}/CMakeLists.txt ]; then + if [ "${KOKKOS_PATH}" == "" ]; then + CM_SCRIPT=$0 + KOKKOS_PATH=`dirname $CM_SCRIPT` + if [ ! -e ${KOKKOS_PATH}/CMakeLists.txt ]; then + echo "${KOKKOS_PATH} repository appears to not be complete. please verify and try again" + exit 0 + fi + else + echo "KOKKOS_PATH does not appear to be set properly. please specify in location of CMakeLists.txt" + display_help_text + exit 0 + fi +fi + +get_kokkos_device_list +get_kokkos_option_list +get_kokkos_arch_list +get_kokkos_cuda_option_list + +## if HPX is enabled, we need to enforce cxx standard = 14 +if [[ ${KOKKOS_DEVICE_CMD} == *Kokkos_ENABLE_HPX* ]]; then + if [ "${KOKKOS_CXX_STANDARD}" == "" ] || [ ${#KOKKOS_CXX_STANDARD} -lt 14 ]; then + echo CXX Standard must be 14 or higher for HPX to work. + KOKKOS_CXX_STANDARD=14 + fi +fi + +if [ "$KOKKOS_CXX_STANDARD" == "" ]; then + STANDARD_CMD= +else + STANDARD_CMD=-DKokkos_CXX_STANDARD=${KOKKOS_CXX_STANDARD} +fi + +if [[ ${COMPILER} == *clang* ]]; then + gcc_path=$(which g++ | awk --field-separator='/bin/g++' '{printf $1}' ) + KOKKOS_CXXFLAGS="${KOKKOS_CXXFLAGS} --gcc-toolchain=${gcc_path}" + + if [ ! "${CUDA_PATH}" == "" ]; then + KOKKOS_CXXFLAGS="${KOKKOS_CXXFLAGS} --cuda-path=${CUDA_PATH}" + fi +fi + +echo cmake $COMPILER_CMD -DCMAKE_CXX_FLAGS="${KOKKOS_CXXFLAGS}" -DCMAKE_EXE_LINKER_FLAGS="${KOKKOS_LDFLAGS}" -DCMAKE_INSTALL_PREFIX=${PREFIX} ${KOKKOS_DEVICE_CMD} ${KOKKOS_ARCH_CMD} -DKokkos_ENABLE_TESTS=ON ${KOKKOS_OPTION_CMD} ${KOKKOS_CUDA_OPTION_CMD} -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_CXX_EXTENSIONS=OFF ${STANDARD_CMD} ${KOKKOS_DEBUG_CMD} ${KOKKOS_PATH} +cmake $COMPILER_CMD -DCMAKE_CXX_FLAGS="${KOKKOS_CXXFLAGS//\"}" -DCMAKE_EXE_LINKER_FLAGS="${KOKKOS_LDFLAGS//\"}" -DCMAKE_INSTALL_PREFIX=${PREFIX} ${KOKKOS_DEVICE_CMD} ${KOKKOS_ARCH_CMD} -DKokkos_ENABLE_TESTS=ON ${KOKKOS_OPTION_CMD} ${KOKKOS_CUDA_OPTION_CMD} -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_CXX_EXTENSIONS=OFF ${STANDARD_CMD} ${KOKKOS_DEBUG_CMD} ${KOKKOS_PATH} diff --git a/lib/kokkos/cmake/KokkosConfig.cmake.in b/lib/kokkos/cmake/KokkosConfig.cmake.in index fc099a494c..6f4607687e 100644 --- a/lib/kokkos/cmake/KokkosConfig.cmake.in +++ b/lib/kokkos/cmake/KokkosConfig.cmake.in @@ -1,18 +1,14 @@ -# - Config file for the Kokkos package -# It defines the following variables -# Kokkos_INCLUDE_DIRS - include directories for Kokkos -# Kokkos_LIBRARIES - libraries to link against - # Compute paths -GET_FILENAME_COMPONENT(Kokkos_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) -SET(Kokkos_INCLUDE_DIRS "@CONF_INCLUDE_DIRS@") +@PACKAGE_INIT@ -# Our library dependencies (contains definitions for IMPORTED targets) -IF(NOT TARGET kokkos AND NOT Kokkos_BINARY_DIR) - INCLUDE("${Kokkos_CMAKE_DIR}/KokkosTargets.cmake") -ENDIF() +#Find dependencies +INCLUDE(CMakeFindDependencyMacro) -# These are IMPORTED targets created by KokkosTargets.cmake -SET(Kokkos_LIBRARY_DIRS @INSTALL_LIB_DIR@) -SET(Kokkos_LIBRARIES @Kokkos_LIBRARIES_NAMES@) -SET(Kokkos_TPL_LIBRARIES @KOKKOS_LIBS@) +#This needs to go above the KokkosTargets in case +#the Kokkos targets depend in some way on the TPL imports +@KOKKOS_TPL_EXPORTS@ + +GET_FILENAME_COMPONENT(Kokkos_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +INCLUDE("${Kokkos_CMAKE_DIR}/KokkosTargets.cmake") +INCLUDE("${Kokkos_CMAKE_DIR}/KokkosConfigCommon.cmake") +UNSET(Kokkos_CMAKE_DIR) diff --git a/lib/kokkos/cmake/KokkosConfigCommon.cmake.in b/lib/kokkos/cmake/KokkosConfigCommon.cmake.in new file mode 100644 index 0000000000..da9c61976c --- /dev/null +++ b/lib/kokkos/cmake/KokkosConfigCommon.cmake.in @@ -0,0 +1,87 @@ +SET(Kokkos_DEVICES @KOKKOS_ENABLED_DEVICES@) +SET(Kokkos_OPTIONS @KOKKOS_ENABLED_OPTIONS@) +SET(Kokkos_TPLS @KOKKOS_ENABLED_TPLS@) +SET(Kokkos_ARCH @KOKKOS_ENABLED_ARCH_LIST@) + +# These are needed by KokkosKernels +FOREACH(DEV ${Kokkos_DEVICES}) + SET(Kokkos_ENABLE_${DEV} ON) +ENDFOREACH() + +IF(NOT Kokkos_FIND_QUIETLY) + MESSAGE(STATUS "Enabled Kokkos devices: ${Kokkos_DEVICES}") +ENDIF() + +IF (Kokkos_ENABLE_CUDA AND ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14.0") + #If we are building CUDA, we have tricked CMake because we declare a CXX project + #If the default C++ standard for a given compiler matches the requested + #standard, then CMake just omits the -std flag in later versions of CMake + #This breaks CUDA compilation (CUDA compiler can have a different default + #-std then the underlying host compiler by itself). Setting this variable + #forces CMake to always add the -std flag even if it thinks it doesn't need it + SET(CMAKE_CXX_STANDARD_DEFAULT 98 CACHE INTERNAL "" FORCE) +ENDIF() + +SET(KOKKOS_USE_CXX_EXTENSIONS @KOKKOS_USE_CXX_EXTENSIONS@) +IF (NOT DEFINED CMAKE_CXX_EXTENSIONS OR CMAKE_CXX_EXTENSIONS) + IF (NOT KOKKOS_USE_CXX_EXTENSIONS) + MESSAGE(WARNING "The installed Kokkos configuration does not support CXX extensions. Forcing -DCMAKE_CXX_EXTENSIONS=Off") + SET(CMAKE_CXX_EXTENSIONS OFF CACHE BOOL "" FORCE) + ENDIF() +ENDIF() + +include(FindPackageHandleStandardArgs) + +# This function makes sure that Kokkos was built with the requested backends +# and target architectures and generates a fatal error if it was not. +# +# kokkos_check( +# [DEVICES ...] # Set of backends (e.g. "OpenMP" and/or "Cuda") +# [ARCH ...] # Target architectures (e.g. "Power9" and/or "Volta70") +# [OPTIONS ...] # Optional settings (e.g. "PROFILING") +# [TPLS ...] # Third party libraries +# [RETURN_VALUE ] # Set a variable that indicates the result of the +# # check instead of a fatal error +# ) +function(kokkos_check) + set(ALLOWED_ARGS DEVICES ARCH OPTIONS TPLS) + cmake_parse_arguments(KOKKOS_CHECK "" "RETURN_VALUE" "${ALLOWED_ARGS}" ${ARGN}) + foreach(_arg ${KOKKOS_CHECK_UNPARSED_ARGUMENTS}) + message(SEND_ERROR "Argument '${_arg}' passed to kokkos_check() was not recognized") + endforeach() + # Get the list of keywords that were actually passed to the function. + set(REQUESTED_ARGS) + foreach(arg ${ALLOWED_ARGS}) + if(KOKKOS_CHECK_${arg}) + list(APPEND REQUESTED_ARGS ${arg}) + endif() + endforeach() + set(KOKKOS_CHECK_SUCCESS TRUE) + foreach(arg ${REQUESTED_ARGS}) + # Define variables named after the required arguments that are provided by + # the Kokkos install. + foreach(requested ${KOKKOS_CHECK_${arg}}) + foreach(provided ${Kokkos_${arg}}) + STRING(TOUPPER ${requested} REQUESTED_UC) + STRING(TOUPPER ${provided} PROVIDED_UC) + if(PROVIDED_UC STREQUAL REQUESTED_UC) + string(REPLACE ";" " " ${requested} "${KOKKOS_CHECK_${arg}}") + endif() + endforeach() + endforeach() + # Somewhat divert the CMake function below from its original purpose and + # use it to check that there are variables defined for all required + # arguments. Success or failure messages will be displayed but we are + # responsible for signaling failure and skip the build system generation. + find_package_handle_standard_args("Kokkos_${arg}" DEFAULT_MSG + ${KOKKOS_CHECK_${arg}}) + if(NOT Kokkos_${arg}_FOUND) + set(KOKKOS_CHECK_SUCCESS FALSE) + endif() + endforeach() + if(NOT KOKKOS_CHECK_SUCCESS AND NOT KOKKOS_CHECK_RETURN_VALUE) + message(FATAL_ERROR "Kokkos does NOT provide all backends and/or architectures requested") + else() + set(${KOKKOS_CHECK_RETURN_VALUE} ${KOKKOS_CHECK_SUCCESS} PARENT_SCOPE) + endif() +endfunction() diff --git a/lib/kokkos/cmake/KokkosCore_config.h.in b/lib/kokkos/cmake/KokkosCore_config.h.in new file mode 100644 index 0000000000..084afba8a8 --- /dev/null +++ b/lib/kokkos/cmake/KokkosCore_config.h.in @@ -0,0 +1,89 @@ + +#if !defined(KOKKOS_MACROS_HPP) || defined(KOKKOS_CORE_CONFIG_H) +#error "Do not include KokkosCore_config.h directly; include Kokkos_Macros.hpp instead." +#else +#define KOKKOS_CORE_CONFIG_H +#endif + +/* Execution Spaces */ +#cmakedefine KOKKOS_ENABLE_SERIAL +#cmakedefine KOKKOS_ENABLE_OPENMP +#cmakedefine KOKKOS_ENABLE_THREADS +#cmakedefine KOKKOS_ENABLE_CUDA +#cmakedefine KOKKOS_ENABLE_HPX +#cmakedefine KOKKOS_ENABLE_MEMKIND +#cmakedefine KOKKOS_ENABLE_LIBRT + +#ifndef __CUDA_ARCH__ +#cmakedefine KOKKOS_ENABLE_TM +#cmakedefine KOKKOS_USE_ISA_X86_64 +#cmakedefine KOKKOS_USE_ISA_KNC +#cmakedefine KOKKOS_USE_ISA_POWERPCLE +#cmakedefine KOKKOS_USE_ISA_POWERPCBE +#endif + +/* General Settings */ +#cmakedefine KOKKOS_ENABLE_CXX11 +#cmakedefine KOKKOS_ENABLE_CXX14 +#cmakedefine KOKKOS_ENABLE_CXX17 +#cmakedefine KOKKOS_ENABLE_CXX20 + +#cmakedefine KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE +#cmakedefine KOKKOS_ENABLE_CUDA_UVM +#cmakedefine KOKKOS_ENABLE_CUDA_LAMBDA +#cmakedefine KOKKOS_ENABLE_CUDA_CONSTEXPR +#cmakedefine KOKKOS_ENABLE_CUDA_LDG_INTRINSIC +#cmakedefine KOKKOS_ENABLE_HPX_ASYNC_DISPATCH +#cmakedefine KOKKOS_ENABLE_DEBUG +#cmakedefine KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK +#cmakedefine KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK +#cmakedefine KOKKOS_ENABLE_COMPILER_WARNINGS +#cmakedefine KOKKOS_ENABLE_PROFILING +#cmakedefine KOKKOS_ENABLE_PROFILING_LOAD_PRINT +#cmakedefine KOKKOS_ENABLE_DEPRECATED_CODE +#cmakedefine KOKKOS_ENABLE_ETI +#cmakedefine KOKKOS_ENABLE_LARGE_MEM_TESTS +#cmakedefine KOKKOS_ENABLE_DUALVIEW_MODIFY_CHECK +#cmakedefine KOKKOS_ENABLE_COMPLEX_ALIGN +#cmakedefine KOKKOS_OPT_RANGE_AGGRESSIVE_VECTORIZATION + +/* TPL Settings */ +#cmakedefine KOKKOS_ENABLE_HWLOC +#cmakedefine KOKKOS_USE_LIBRT +#cmakedefine KOKKOS_ENABLE_HWBSPACE + +#cmakedefine KOKKOS_IMPL_CUDA_CLANG_WORKAROUND + +#cmakedefine KOKKOS_COMPILER_CUDA_VERSION @KOKKOS_COMPILER_CUDA_VERSION@ + +#cmakedefine KOKKOS_ARCH_SSE42 +#cmakedefine KOKKOS_ARCH_ARMV80 +#cmakedefine KOKKOS_ARCH_ARMV8_THUNDERX +#cmakedefine KOKKOS_ARCH_ARMV81 +#cmakedefine KOKKOS_ARCH_ARMV8_THUNDERX2 +#cmakedefine KOKKOS_ARCH_AMD_AVX2 +#cmakedefine KOKKOS_ARCH_AVX +#cmakedefine KOKKOS_ARCH_AVX2 +#cmakedefine KOKKOS_ARCH_AVX512XEON +#cmakedefine KOKKOS_ARCH_KNC +#cmakedefine KOKKOS_ARCH_AVX512MIC +#cmakedefine KOKKOS_ARCH_POWER7 +#cmakedefine KOKKOS_ARCH_POWER8 +#cmakedefine KOKKOS_ARCH_POWER9 +#cmakedefine KOKKOS_ARCH_KEPLER +#cmakedefine KOKKOS_ARCH_KEPLER30 +#cmakedefine KOKKOS_ARCH_KEPLER32 +#cmakedefine KOKKOS_ARCH_KEPLER35 +#cmakedefine KOKKOS_ARCH_KEPLER37 +#cmakedefine KOKKOS_ARCH_MAXWELL +#cmakedefine KOKKOS_ARCH_MAXWELL50 +#cmakedefine KOKKOS_ARCH_MAXWELL52 +#cmakedefine KOKKOS_ARCH_MAXWELL53 +#cmakedefine KOKKOS_ARCH_PASCAL +#cmakedefine KOKKOS_ARCH_PASCAL60 +#cmakedefine KOKKOS_ARCH_PASCAL61 +#cmakedefine KOKKOS_ARCH_VOLTA +#cmakedefine KOKKOS_ARCH_VOLTA70 +#cmakedefine KOKKOS_ARCH_VOLTA72 +#cmakedefine KOKKOS_ARCH_TURING75 +#cmakedefine KOKKOS_ARCH_AMD_EPYC diff --git a/lib/kokkos/cmake/Makefile.generate_cmake_settings b/lib/kokkos/cmake/Makefile.generate_cmake_settings deleted file mode 100644 index da076b23db..0000000000 --- a/lib/kokkos/cmake/Makefile.generate_cmake_settings +++ /dev/null @@ -1,8 +0,0 @@ -ifndef KOKKOS_PATH - MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) - KOKKOS_PATH = $(subst Makefile,,$(MAKEFILE_PATH)).. -endif - -include $(KOKKOS_PATH)/Makefile.kokkos -include $(KOKKOS_PATH)/core/src/Makefile.generate_header_lists -include $(KOKKOS_PATH)/core/src/Makefile.generate_build_files diff --git a/lib/kokkos/cmake/Modules/FindHWLOC.cmake b/lib/kokkos/cmake/Modules/FindHWLOC.cmake deleted file mode 100644 index 60df8084d8..0000000000 --- a/lib/kokkos/cmake/Modules/FindHWLOC.cmake +++ /dev/null @@ -1,20 +0,0 @@ -#.rst: -# FindHWLOC -# ---------- -# -# Try to find HWLOC, based on KOKKOS_HWLOC_DIR -# -# The following variables are defined: -# -# HWLOC_FOUND - System has HWLOC -# HWLOC_INCLUDE_DIR - HWLOC include directory -# HWLOC_LIBRARIES - Libraries needed to use HWLOC - -find_path(HWLOC_INCLUDE_DIR hwloc.h PATHS "${KOKKOS_HWLOC_DIR}/include") -find_library(HWLOC_LIBRARIES hwloc PATHS "${KOKKOS_HWLOC_DIR}/lib") - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(HWLOC DEFAULT_MSG - HWLOC_INCLUDE_DIR HWLOC_LIBRARIES) - -mark_as_advanced(HWLOC_INCLUDE_DIR HWLOC_LIBRARIES) diff --git a/lib/kokkos/cmake/Modules/FindMemkind.cmake b/lib/kokkos/cmake/Modules/FindMemkind.cmake deleted file mode 100644 index 245fb44c19..0000000000 --- a/lib/kokkos/cmake/Modules/FindMemkind.cmake +++ /dev/null @@ -1,20 +0,0 @@ -#.rst: -# FindMemkind -# ---------- -# -# Try to find Memkind. -# -# The following variables are defined: -# -# MEMKIND_FOUND - System has Memkind -# MEMKIND_INCLUDE_DIR - Memkind include directory -# MEMKIND_LIBRARIES - Libraries needed to use Memkind - -find_path(MEMKIND_INCLUDE_DIR memkind.h) -find_library(MEMKIND_LIBRARIES memkind) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Memkind DEFAULT_MSG - MEMKIND_INCLUDE_DIR MEMKIND_LIBRARIES) - -mark_as_advanced(MEMKIND_INCLUDE_DIR MEMKIND_LIBRARIES) diff --git a/lib/kokkos/cmake/Modules/FindQthreads.cmake b/lib/kokkos/cmake/Modules/FindQthreads.cmake deleted file mode 100644 index a254b0e996..0000000000 --- a/lib/kokkos/cmake/Modules/FindQthreads.cmake +++ /dev/null @@ -1,20 +0,0 @@ -#.rst: -# FindQthreads -# ---------- -# -# Try to find Qthreads. -# -# The following variables are defined: -# -# QTHREADS_FOUND - System has Qthreads -# QTHREADS_INCLUDE_DIR - Qthreads include directory -# QTHREADS_LIBRARIES - Libraries needed to use Qthreads - -find_path(QTHREADS_INCLUDE_DIR qthread.h) -find_library(QTHREADS_LIBRARIES qthread) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Qthreads DEFAULT_MSG - QTHREADS_INCLUDE_DIR QTHREADS_LIBRARIES) - -mark_as_advanced(QTHREADS_INCLUDE_DIR QTHREADS_LIBRARIES) diff --git a/lib/kokkos/cmake/Modules/FindTPLCUDA.cmake b/lib/kokkos/cmake/Modules/FindTPLCUDA.cmake new file mode 100644 index 0000000000..36aefcdb44 --- /dev/null +++ b/lib/kokkos/cmake/Modules/FindTPLCUDA.cmake @@ -0,0 +1,13 @@ + +IF (KOKKOS_CXX_COMPILER_ID STREQUAL Clang) + KOKKOS_FIND_IMPORTED(CUDA INTERFACE + LIBRARIES cudart cuda + LIBRARY_PATHS ENV LD_LIBRARY_PATH ENV CUDA_PATH + ALLOW_SYSTEM_PATH_FALLBACK + ) +ELSE() + KOKKOS_CREATE_IMPORTED_TPL(CUDA INTERFACE + LINK_LIBRARIES cuda + ) +ENDIF() + diff --git a/lib/kokkos/cmake/Modules/FindTPLHPX.cmake b/lib/kokkos/cmake/Modules/FindTPLHPX.cmake new file mode 100644 index 0000000000..c8b3bc4c9b --- /dev/null +++ b/lib/kokkos/cmake/Modules/FindTPLHPX.cmake @@ -0,0 +1,15 @@ + +FIND_PACKAGE(HPX REQUIRED) +#as of right now, HPX doesn't export correctly +#so let's convert it to an interface target +KOKKOS_CREATE_IMPORTED_TPL(HPX INTERFACE + LINK_LIBRARIES ${HPX_LIBRARIES} + INCLUDES ${HPX_INCLUDE_DIRS} +) +#this is a bit funky since this is a CMake target +#but HPX doesn't export itself correctly +KOKKOS_EXPORT_CMAKE_TPL(HPX) + +#I would prefer all of this gets replaced with +#KOKKOS_IMPORT_CMAKE_TPL(HPX) + diff --git a/lib/kokkos/cmake/Modules/FindTPLHWLOC.cmake b/lib/kokkos/cmake/Modules/FindTPLHWLOC.cmake new file mode 100644 index 0000000000..cf763b7e5b --- /dev/null +++ b/lib/kokkos/cmake/Modules/FindTPLHWLOC.cmake @@ -0,0 +1 @@ +KOKKOS_FIND_IMPORTED(HWLOC HEADER hwloc.h LIBRARY hwloc) diff --git a/lib/kokkos/cmake/Modules/FindTPLLIBDL.cmake b/lib/kokkos/cmake/Modules/FindTPLLIBDL.cmake new file mode 100644 index 0000000000..5fc6a69303 --- /dev/null +++ b/lib/kokkos/cmake/Modules/FindTPLLIBDL.cmake @@ -0,0 +1 @@ +KOKKOS_FIND_IMPORTED(LIBDL HEADER dlfcn.h LIBRARY dl) diff --git a/lib/kokkos/cmake/Modules/FindTPLLIBNUMA.cmake b/lib/kokkos/cmake/Modules/FindTPLLIBNUMA.cmake new file mode 100644 index 0000000000..811db5851b --- /dev/null +++ b/lib/kokkos/cmake/Modules/FindTPLLIBNUMA.cmake @@ -0,0 +1 @@ +KOKKOS_FIND_IMPORTED(LIBNUMA HEADER numa.h LIBRARY numa) diff --git a/lib/kokkos/cmake/Modules/FindTPLLIBRT.cmake b/lib/kokkos/cmake/Modules/FindTPLLIBRT.cmake new file mode 100644 index 0000000000..e75da56b5b --- /dev/null +++ b/lib/kokkos/cmake/Modules/FindTPLLIBRT.cmake @@ -0,0 +1 @@ +KOKKOS_FIND_IMPORTED(LIBRT HEADER time.h LIBRARY rt) diff --git a/lib/kokkos/cmake/Modules/FindTPLMEMKIND.cmake b/lib/kokkos/cmake/Modules/FindTPLMEMKIND.cmake new file mode 100644 index 0000000000..20aaff2295 --- /dev/null +++ b/lib/kokkos/cmake/Modules/FindTPLMEMKIND.cmake @@ -0,0 +1 @@ +KOKKOS_FIND_IMPORTED(MEMKIND HEADER memkind.h LIBRARY memkind) diff --git a/lib/kokkos/cmake/Modules/FindTPLPTHREAD.cmake b/lib/kokkos/cmake/Modules/FindTPLPTHREAD.cmake new file mode 100644 index 0000000000..b4b8c34122 --- /dev/null +++ b/lib/kokkos/cmake/Modules/FindTPLPTHREAD.cmake @@ -0,0 +1,17 @@ + +TRY_COMPILE(KOKKOS_HAS_PTHREAD_ARG + ${KOKKOS_TOP_BUILD_DIR}/tpl_tests + ${KOKKOS_SOURCE_DIR}/cmake/compile_tests/pthread.cpp + LINK_LIBRARIES -pthread + COMPILE_DEFINITIONS -pthread) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(PTHREAD DEFAULT_MSG KOKKOS_HAS_PTHREAD_ARG) + +KOKKOS_CREATE_IMPORTED_TPL(PTHREAD + INTERFACE #this is not a real library with a real location + COMPILE_OPTIONS -pthread + LINK_OPTIONS -pthread) + + + diff --git a/lib/kokkos/cmake/README.md b/lib/kokkos/cmake/README.md new file mode 100644 index 0000000000..2ac8731586 --- /dev/null +++ b/lib/kokkos/cmake/README.md @@ -0,0 +1,331 @@ +![Kokkos](https://avatars2.githubusercontent.com/u/10199860?s=200&v=4) + +# Developing Kokkos + +This document contains a build system overview for developers with information on adding new CMake options that could influence +* Header configuration macros +* Optional features +* Third-partly libraries +* Compiler and linker flags +For build system details for users, refer to the [build instructions](../BUILD.md). + +## Build System + +Kokkos uses CMake to configure, build, and install. +Rather than being a completely straightforward use of modern CMake, +Kokkos has several extra complications, primarily due to: +* Kokkos must support linking to an installed version or in-tree builds as a subdirectory of a larger project. +* Kokkos must configure a special compiler `nvcc_wrapper` that allows `nvcc` to accept all C++ flags (which `nvcc` currently does not). +* Kokkos must work as a part of TriBITS, a CMake library providing a particular build idiom for Trilinos. +* Kokkos has many pre-existing users. We need to be careful about breaking previous versions or generating meaningful error messags if we do break backwards compatibility. + +If you are looking at the build system code wondering why certain decisions were made: we have had to balance many competing requirements and certain technical debt. Everything in the build system was done for a reason, trying to adhere as closely as possible to modern CMake best practices while meeting all pre-existing. customer requirements. + +### Modern CMake Philosophy + +Modern CMake relies on understanding the principle of *building* and *using* a code project. +What preprocessor, compiler, and linker flags do I need to *build* my project? +What flags does a downstream project that links to me need to *use* my project? +In CMake terms, flags that are only needed for building are `PRIVATE`. +Only Kokkos needs these flags, not a package that depends on Kokkos. +Flags that must be used in a downstream project are `PUBLIC`. +Kokkos must tell other projects to use them. + +In Kokkos, almost everything is a public flag since Kokkos is driven by headers and Kokkos is in charge of optimizing your code to achieve performance portability! +Include paths, C++ standard flags, architecture-specific optimizations, or OpenMP and CUDA flags are all examples of flags that Kokkos configures and adds to your project. + +Modern CMake now automatically propagates flags through the `target_link_libraries` command. +Suppose you have a library `stencil` that needs to build with Kokkos. +Consider the following CMake code: + +```` +find_package(Kokkos) +add_library(stencil stencil.cpp) +target_link_libraries(stencil Kokkos::kokkos) +```` + +This locates the Kokkos package, adds your library, and tells CMake to link Kokkos to your library. +All public build flags get added automatically through the `target_link_libraries` command. +There is nothing to do. You can be happily oblivious to how Kokkos was configured. +Everything should just work. + +As a Kokkos developer who wants to add new public compiler flags, how do you ensure that CMake does this properly? Modern CMake works through targets and properties. +Each target has a set of standard properties: +* `INTERFACE_COMPILE_OPTIONS` contains all the compiler options that Kokkos should add to downstream projects +* `INTERFACE_INCLUDE_DIRECTORIES` contains all the directories downstream projects must include from Kokkos +* `INTERFACE_COMPILE_DEFINITIONS` contains the list of preprocessor `-D` flags +* `INTERFACE_LINK_LIBRARIES` contains all the libraries downstream projects need to link +* `INTERFACE_COMPILE_FEATURES` essentially adds compiler flags, but with extra complications. Features names are specific to CMake. More later. + +CMake makes it easy to append to these properties using: +* `target_compile_options(kokkos PUBLIC -fmyflag)` +* `target_include_directories(kokkos PUBLIC mySpecialFolder)` +* `target_compile_definitions(kokkos PUBLIC -DmySpecialFlag=0)` +* `target_link_libraries(kokkos PUBLIC mySpecialLibrary)` +* `target_compile_features(kokkos PUBLIC mySpecialFeature)` +Note that all of these use `PUBLIC`! Almost every Kokkos flag is not private to Kokkos, but must also be used by downstream projects. + + +### Compiler Features and Compiler Options +Compiler options are flags like `-fopenmp` that do not need to be "resolved." +The flag is either on or off. +Compiler features are more fine-grained and require conflicting requests to be resolved. +Suppose I have +```` +add_library(A a.cpp) +target_compile_features(A PUBLIC cxx_std_11) +```` +then another target +```` +add_library(B b.cpp) +target_compile_features(B PUBLIC cxx_std_14) +target_link_libraries(A B) +```` +I have requested two diferent features. +CMake understands the requests and knows that `cxx_std_11` is a subset of `cxx_std_14`. +CMake then picks C++14 for library `B`. +CMake would not have been able to do feature resolution if we had directly done: +```` +target_compile_options(A PUBLIC -std=c++11) +```` + +### Adding Kokkos Options +After configuring for the first time, +CMake creates a cache of configure variables in `CMakeCache.txt`. +Reconfiguring in the folder "restarts" from those variables. +All flags passed as `-DKokkos_SOME_OPTION=X` to `cmake` become variables in the cache. +All Kokkos options begin with camel case `Kokkos_` followed by an upper case option name. + +CMake best practice is to avoid cache variables, if possible. +In essence, you want the minimal amount of state cached between configurations. +And never, ever have behavior influenced by multiple cache variables. +If you want to change the Kokkos configuration, have a single unique variable that needs to be changed. +Never require two cache variables to be changed. + +Kokkos provides a function `KOKKOS_OPTION` for defining valid cache-level variables, +proofreading them, and defining local project variables. +The most common variables are called `Kokkos_ENABLE_X`, +for which a helper function `KOKKOS_ENABLE_OPTION` is provided, e.g. +```` +KOKKOS_ENABLE_OPTION(TESTS OFF "Whether to build tests") +```` +The function checks if `-DKokkos_ENABLE_TESTS` was given, +whether it was given with the wrong case, e.g. `-DKokkos_Enable_Tests`, +and then defines a regular (non-cache) variable `KOKKOS_ENABLE_TESTS` to `ON` or `OFF` +depending on the given default and whether the option was specified. + +### Defining Kokkos Config Macros + +Sometimes you may want to add `#define Kokkos_X` macros to the config header. +This is straightforward with CMake. +Suppose you want to define an optional macro `KOKKOS_SUPER_SCIENCE`. +Simply go into `KokkosCore_config.h.in` and add +```` +#cmakedefine KOKKOS_SUPER_SCIENCE +```` +I can either add +```` +KOKKOS_OPTION(SUPER_SCIENCE ON "Whether to do some super science") +```` +to directly set the variable as a command-line `-D` option. +Alternatively, based on other logic, I could add to a `CMakeLists.txt` +```` +SET(KOKKOS_SUPER_SCIENCE ON) +```` +If not set as a command-line option (cache variable), you must make sure the variable is visible in the top-level scope. +If set in a function, you would need: +```` +SET(KOKKOS_SUPER_SCIENCE ON PARENT_SCOPE) +```` + +### Third-Party Libraries +In much the same way that compiler flags transitively propagate to dependent projects, +modern CMake allows us to propagate dependent libraries. +If Kokkos depends on, e.g. `hwloc` the downstream project will also need to link `hwloc`. +There are three stages in adding a new third-party library (TPL): +* Finding: find the desired library on the system and verify the installation is correct +* Importing: create a CMake target, if necessary, that is compatible with `target_link_libraries`. This is mostly relevant for TPLs not installed with CMake. +* Exporting: make the desired library visible to downstream projects + +TPLs are somewhat complicated by whether the library was installed with CMake or some other build system. +If CMake, our lives are greatly simplified. We simply use `find_package` to locate the installed CMake project then call `target_link_libraries(kokkoscore PUBLIC/PRIVATE TPL)`. For libaries not installed with CMake, the process is a bit more complex. +It is up to the Kokkos developers to "convert" the library into a CMake target as if it had been installed as a valid modern CMake target with properties. +There are helper functions for simplifying the process of importing TPLs in Kokkos, but we walk through the process in detail to clearly illustrate the steps involved. + +#### TPL Search Order + +There are several options for where CMake could try to find a TPL. +If there are multiple installations of the same TPL on the system, +the search order is critical for making sure the correct TPL is found. +There are 3 possibilities that could be used: + +1. Default system paths like /usr +1. User-provided paths through options `_ROOT` and `Kokkos__DIR` +1. Additional paths not in the CMake default list or provided by the user that Kokkos decides to add. For example, Kokkos may query `nvcc` or `LD_LIBRARY_PATH` for where to find CUDA libraries. + +The following is the search order that Kokkos follows. Note: This differs from the default search order used by CMake `find_library` and `find_header`. CMake prefers default system paths over user-provided paths. +For Kokkos (and package managers in general), it is better to prefer user-provided paths since this usually indicates a specific version we want. + +1. `_ROOT` +1. `Kokkos__DIR` +1. Paths added by Kokkos CMake logic +1. Default system paths (if allowed) + +Default system paths are allowed in two cases. First, none of the other options are given so the only place to look is system paths. Second, if explicitly given permission, configure will look in system paths. +The rationale for this logic is that if you specify a custom location, you usually *only* want to look in that location. +If you do not find the TPL where you expect it, you should error out rather than grab another random match. + + +#### Finding TPLs + +If finding a TPL that is not a modern CMake project, refer to the `FindHWLOC.cmake` file in `cmake/Modules` for an example. +You will ususally need to verify expected headers with `find_path` +```` +find_path(TPL_INCLUDE_DIR mytpl.h PATHS "${KOKKOS_MYTPL_DIR}/include") +```` +This insures that the library header is in the expected include directory and defines the variable `TPL_INCLUDE_DIR` with a valid path if successful. +Similarly, you can verify a library +```` +find_library(TPL_LIBRARY mytpl PATHS "${KOKKOS_MYTPL_DIR/lib") +```` +that then defines the variable `TPL_LIBRARY` with a valid path if successful. +CMake provides a utility for checking if the `find_path` and `find_library` calls were successful that emulates the behavior of `find_package` for a CMake target. +```` +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(MYTPL DEFAULT_MSG + MYTPL_INCLUDE_DIR MYTPL_LIBRARY) +```` +If the find failed, CMake will print standard error messages explaining the failure. + +#### Importing TPLs + +The installed TPL must be adapted into a CMake target. +CMake allows libraries to be added that are built externally as follows: +```` +add_library(Kokkos::mytpl UNKNOWN IMPORTED) +```` +Importantly, we use a `Kokkos::` namespace to avoid name conflicts and identify this specifically as the version imported by Kokkos. +Because we are importing a non-CMake target, we must populate all the target properties that would have been automatically populated for a CMake target. +```` +set_target_properties(Kokkos::mytpl PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${MYTPL_INCLUDE_DIR}" + IMPORTED_LOCATION "${MYTPL_LIBRARY}" +) +```` + +#### Exporting TPLs + +Kokkos may now depend on the target `Kokkos::mytpl` as a `PUBLIC` library (remember building and using). +This means that downstream projects must also know about `Kokkos::myptl` - so Kokkos must export them. +In the `KokkosConfig.cmake.in` file, we need to add code like the following: +```` +set(MYTPL_LIBRARY @MYTPL_LIBRARY@) +set(MYTPL_INCLUDE_DIR @MYTPL_INCLUDE_DIR@) +add_library(Kokkos::mytpl UNKNOWN IMPORTED) +set_target_properties(Kokkos::mytpl PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${MYTPL_INCLUDE_DIR}" + IMPORTED_LOCATION "${MYTPL_LIBRARY}" +) +```` +If this looks familiar, that's because it is exactly the same code as above for importing the TPL. +Exporting a TPL really just means importing the TPL when Kokkos is loaded by an external project. +We will describe helper functions that simplify this process. + +#### Interface TPLs + +If a TPL is just a library and set of headers, we can make a simple `IMPORTED` target. +However, a TPL is actually completely flexible and need not be limited to just headers and libraries. +TPLs can configure compiler flags, linker flags, or multiple different libraries. +For this, we use a special type of CMake target: `INTERFACE` libraries. +These libraries don't build anything. +They simply populate properties that will configure flags for dependent targets. +We consider the example: +```` +add_library(PTHREAD INTERFACE) +target_compile_options(PTHREAD PUBLIC -pthread) +```` +Kokkos uses the compiler flag `-pthread` to define compiler macros for re-entrant functions rather than treating it simply as a library with header `pthread.h` and library `-lpthread`. +Any property can be configured, e.g. +```` +target_link_libraries(MYTPL ...) +```` +In contrast to imported TPLs which require direct modification of `KokkosConfig.cmake.in`, +we can use CMake's built-in export functions: +```` +INSTALL( + TARGETS MYTPL + EXPORT KokkosTargets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) +```` +These interface targets will be automatically populated in the config file. + +#### Linking the TPL +After finishing the import process, it still remains to link the imported target as needed. +For example, +```` +target_link_libraries(kokkoscore PUBLIC Kokkos::HWLOC) +```` +The complexity of which includes, options, and libraries the TPL requires +should be encapsulated in the CMake target. + +#### TPL Helper Functions +##### KOKKOS_IMPORT_TPL +This function can be invoked as, e.g. +```` +KOKKOS_IMPORT_TPL(HWLOC) +```` +This function checks if the TPL was enabled by a `-DKokkos_ENABLE_HWLOC=On` flag. +If so, it calls `find_package(TPLHWLOC)`. +This invokes the file `FindTPLHWLOC.cmake` which should be contained in the `cmake/Modules` folder. +If successful, another function `KOKKOS_EXPORT_CMAKE_TPL` gets invoked. +This automatically adds all the necessary import commands to `KokkosConfig.cmake`. + +##### KOKKOS_FIND_IMPORTED +Inside a `FindTPLX.cmake` file, the simplest way to import a library is to call, e.g. +```` +KOKKOS_FIND_IMPORTED(HWLOC LIBRARY hwloc HEADER hwloc.h) +```` +This finds the location of the library and header and creates an imported target `Kokkos::HWLOC` +that can be linked against. +The library/header find can be guided with `-DHWLOC_ROOT=` or `-DKokkos_HWLOC_DIR=` during CMake configure. +These both specify the install prefix. + +##### KOKKOS_LINK_TPL +This function checks if the TPL has been enabled. +If so, it links a given library against the imported (or interface) TPL target. + +##### KOKKOS_CREATE_IMPORTED_TPL +This helper function is best understood by reading the actual code. +This function takes arguments specifying the properties and creates the actual TPL target. +The most important thing to understand for this function is whether you call this function with the optional `INTERFACE` keyword. +This tells the project to either create the target as an imported target or interface target, as discussed above. + +##### KOKKOS_EXPORT_CMAKE_TPL +Even if the TPL just loads a valid CMake target, we still must "export" it into the config file. +When Kokkos is loaded by a downstream project, this TPL must be loaded. +Calling this function simply appends text recording the location where the TPL was found +and adding a `find_dependency(...)` call that will reload the CMake target. + +### The Great TriBITS Compromise + +TriBITS was a masterpiece of CMake version 2 before the modern CMake idioms of building and using. +TriBITS greatly limited verbosity of CMake files, handled complicated dependency trees between packages, and handled automatically setting up include and linker paths for dependent libraries. + +Kokkos is now used by numerous projects that don't (and won't) depend on TriBITS for their build systems. +Kokkos has to work outside of TriBITS and provide a standard CMake 3+ build system. +At the same time, Kokkos is used by numerous projects that depend on TriBITS and don't (and won't) switch to a standard CMake 3+ build system. + +Instead of calling functions `TRIBITS_X(...)`, the CMake calls wrapper functions `KOKKOS_X(...)`. +If TriBITS is available (as in Trilinos), `KOKKOS_X` will just be a thin wrapper around `TRIBITS_X`. +If TriBITS is not available, Kokkos maps `KOKKOS_X` calls to native CMake that complies with CMake 3 idioms. +For the time being, this seems the most sensible way to handle the competing requirements of a standalone modern CMake and TriBITS build system. + +##### [LICENSE](https://github.com/kokkos/kokkos/blob/devel/LICENSE) + +[![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) + +Under the terms of Contract DE-NA0003525 with NTESS, +the U.S. Government retains certain rights in this software. diff --git a/lib/kokkos/cmake/compile_tests/clang_omp.cpp b/lib/kokkos/cmake/compile_tests/clang_omp.cpp new file mode 100644 index 0000000000..ce3bbfb262 --- /dev/null +++ b/lib/kokkos/cmake/compile_tests/clang_omp.cpp @@ -0,0 +1,9 @@ +#include + +int main(int argc, char** argv) { + int thr = omp_get_num_threads(); + if (thr > 0) + return thr; + else + return 0; +} diff --git a/lib/kokkos/cmake/compile_tests/pthread.cpp b/lib/kokkos/cmake/compile_tests/pthread.cpp new file mode 100644 index 0000000000..3b13f7ba35 --- /dev/null +++ b/lib/kokkos/cmake/compile_tests/pthread.cpp @@ -0,0 +1,10 @@ +#include + +void* kokkos_test(void* args) { return args; } + +int main(void) { + pthread_t thread; + pthread_create(&thread, NULL, kokkos_test, NULL); + pthread_join(thread, NULL); + return 0; +} diff --git a/lib/kokkos/cmake/cray.cmake b/lib/kokkos/cmake/cray.cmake new file mode 100644 index 0000000000..08912f5130 --- /dev/null +++ b/lib/kokkos/cmake/cray.cmake @@ -0,0 +1,9 @@ + + +function(kokkos_set_cray_flags full_standard int_standard) + STRING(TOLOWER ${full_standard} FULL_LC_STANDARD) + STRING(TOLOWER ${int_standard} INT_LC_STANDARD) + SET(KOKKOS_CXX_STANDARD_FLAG "-hstd=c++${FULL_LC_STANDARD}", PARENT_SCOPE) + SET(KOKKOS_CXX_INTERMDIATE_STANDARD_FLAG "-hstd=c++${INT_LC_STANDARD}" PARENT_SCOPE) +endfunction() + diff --git a/lib/kokkos/cmake/deps/CUDA.cmake b/lib/kokkos/cmake/deps/CUDA.cmake index 801c20067b..4876bca259 100644 --- a/lib/kokkos/cmake/deps/CUDA.cmake +++ b/lib/kokkos/cmake/deps/CUDA.cmake @@ -73,7 +73,7 @@ IF(NOT _CUDA_FAILURE) GLOBAL_SET(TPL_CUDA_LIBRARY_DIRS) GLOBAL_SET(TPL_CUDA_INCLUDE_DIRS ${CUDA_TOOLKIT_INCLUDE}) GLOBAL_SET(TPL_CUDA_LIBRARIES ${CUDA_CUDART_LIBRARY} ${CUDA_cublas_LIBRARY} ${CUDA_cufft_LIBRARY}) - TIBITS_CREATE_IMPORTED_TPL_LIBRARY(CUSPARSE) + KOKKOS_CREATE_IMPORTED_TPL_LIBRARY(CUSPARSE) ELSE() SET(TPL_ENABLE_CUDA OFF) ENDIF() diff --git a/lib/kokkos/cmake/deps/CUSPARSE.cmake b/lib/kokkos/cmake/deps/CUSPARSE.cmake index 6f26d857c0..b2420d1168 100644 --- a/lib/kokkos/cmake/deps/CUSPARSE.cmake +++ b/lib/kokkos/cmake/deps/CUSPARSE.cmake @@ -59,6 +59,6 @@ # GLOBAL_SET(TPL_CUSPARSE_LIBRARY_DIRS) # GLOBAL_SET(TPL_CUSPARSE_INCLUDE_DIRS ${TPL_CUDA_INCLUDE_DIRS}) # GLOBAL_SET(TPL_CUSPARSE_LIBRARIES ${CUDA_cusparse_LIBRARY}) -# TIBITS_CREATE_IMPORTED_TPL_LIBRARY(CUSPARSE) +# KOKKOS_CREATE_IMPORTED_TPL_LIBRARY(CUSPARSE) #ENDIF() diff --git a/lib/kokkos/cmake/deps/HWLOC.cmake b/lib/kokkos/cmake/deps/HWLOC.cmake index 275abd3a5d..ed89c8c1e5 100644 --- a/lib/kokkos/cmake/deps/HWLOC.cmake +++ b/lib/kokkos/cmake/deps/HWLOC.cmake @@ -64,7 +64,7 @@ # Version: 1.3 # -TRIBITS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES( HWLOC +KOKKOS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES( HWLOC REQUIRED_HEADERS hwloc.h REQUIRED_LIBS_NAMES "hwloc" ) diff --git a/lib/kokkos/cmake/deps/Pthread.cmake b/lib/kokkos/cmake/deps/Pthread.cmake index 46d0a939ca..5f835fc300 100644 --- a/lib/kokkos/cmake/deps/Pthread.cmake +++ b/lib/kokkos/cmake/deps/Pthread.cmake @@ -74,9 +74,9 @@ IF(USE_THREADS) SET(TPL_Pthread_INCLUDE_DIRS "") SET(TPL_Pthread_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}") SET(TPL_Pthread_LIBRARY_DIRS "") - TIBITS_CREATE_IMPORTED_TPL_LIBRARY(Pthread) + KOKKOS_CREATE_IMPORTED_TPL_LIBRARY(Pthread) ELSE() - TRIBITS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES( Pthread + KOKKOS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES( Pthread REQUIRED_HEADERS pthread.h REQUIRED_LIBS_NAMES pthread ) diff --git a/lib/kokkos/cmake/deps/QTHREADS.cmake b/lib/kokkos/cmake/deps/QTHREADS.cmake deleted file mode 100644 index c312f2590b..0000000000 --- a/lib/kokkos/cmake/deps/QTHREADS.cmake +++ /dev/null @@ -1,69 +0,0 @@ -# @HEADER -# ************************************************************************ -# -# Trilinos: An Object-Oriented Solver Framework -# Copyright (2001) Sandia Corporation -# -# -# Copyright (2001) Sandia Corporation. Under the terms of Contract -# DE-AC04-94AL85000, there is a non-exclusive license for use of this -# work by or on behalf of the U.S. Government. Export of this program -# may require a license from the United States Government. -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the Corporation nor the names of the -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY -# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# NOTICE: The United States Government is granted for itself and others -# acting on its behalf a paid-up, nonexclusive, irrevocable worldwide -# license in this data to reproduce, prepare derivative works, and -# perform publicly and display publicly. Beginning five (5) years from -# July 25, 2001, the United States Government is granted for itself and -# others acting on its behalf a paid-up, nonexclusive, irrevocable -# worldwide license in this data to reproduce, prepare derivative works, -# distribute copies to the public, perform publicly and display -# publicly, and to permit others to do so. -# -# NEITHER THE UNITED STATES GOVERNMENT, NOR THE UNITED STATES DEPARTMENT -# OF ENERGY, NOR SANDIA CORPORATION, NOR ANY OF THEIR EMPLOYEES, MAKES -# ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL LIABILITY OR -# RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR USEFULNESS OF ANY -# INFORMATION, APPARATUS, PRODUCT, OR PROCESS DISCLOSED, OR REPRESENTS -# THAT ITS USE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS. -# -# ************************************************************************ -# @HEADER - - -#----------------------------------------------------------------------------- -# Hardware locality detection and control library. -# -# Acquisition information: -# Date checked: July 2014 -# Checked by: H. Carter Edwards -# Source: https://code.google.com/p/qthreads -# - -TRIBITS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES( QTHREADS - REQUIRED_HEADERS qthread.h - REQUIRED_LIBS_NAMES "qthread" - ) diff --git a/lib/kokkos/cmake/fake_tribits.cmake b/lib/kokkos/cmake/fake_tribits.cmake new file mode 100644 index 0000000000..26948d2cfb --- /dev/null +++ b/lib/kokkos/cmake/fake_tribits.cmake @@ -0,0 +1,338 @@ +#These are tribits wrappers used by all projects in the Kokkos ecosystem + +INCLUDE(CMakeParseArguments) +INCLUDE(CTest) + +cmake_policy(SET CMP0054 NEW) + +FUNCTION(ASSERT_DEFINED VARS) + FOREACH(VAR ${VARS}) + IF(NOT DEFINED ${VAR}) + MESSAGE(SEND_ERROR "Error, the variable ${VAR} is not defined!") + ENDIF() + ENDFOREACH() +ENDFUNCTION() + +MACRO(KOKKOS_ADD_OPTION_AND_DEFINE USER_OPTION_NAME MACRO_DEFINE_NAME DOCSTRING DEFAULT_VALUE ) +SET( ${USER_OPTION_NAME} "${DEFAULT_VALUE}" CACHE BOOL "${DOCSTRING}" ) +IF(NOT ${MACRO_DEFINE_NAME} STREQUAL "") + IF(${USER_OPTION_NAME}) + GLOBAL_SET(${MACRO_DEFINE_NAME} ON) + ELSE() + GLOBAL_SET(${MACRO_DEFINE_NAME} OFF) + ENDIF() +ENDIF() +ENDMACRO() + +MACRO(GLOBAL_RESET VARNAME) + SET(${VARNAME} "" CACHE INTERNAL "" FORCE) +ENDMACRO() + +MACRO(GLOBAL_OVERWRITE VARNAME VALUE TYPE) + SET(${VARNAME} ${VALUE} CACHE ${TYPE} "" FORCE) +ENDMACRO() + +IF (NOT KOKKOS_HAS_TRILINOS) +MACRO(APPEND_GLOB VAR) + FILE(GLOB LOCAL_TMP_VAR ${ARGN}) + LIST(APPEND ${VAR} ${LOCAL_TMP_VAR}) +ENDMACRO() + +MACRO(GLOBAL_SET VARNAME) + SET(${VARNAME} ${ARGN} CACHE INTERNAL "" FORCE) +ENDMACRO() + +FUNCTION(VERIFY_EMPTY CONTEXT) +if(${ARGN}) +MESSAGE(FATAL_ERROR "Kokkos does not support all of Tribits. Unhandled arguments in ${CONTEXT}:\n${ARGN}") +endif() +ENDFUNCTION() + +MACRO(PREPEND_GLOBAL_SET VARNAME) + ASSERT_DEFINED(${VARNAME}) + GLOBAL_SET(${VARNAME} ${ARGN} ${${VARNAME}}) +ENDMACRO() + +MACRO(PREPEND_TARGET_SET VARNAME TARGET_NAME TYPE) + IF(TYPE STREQUAL "REQUIRED") + SET(REQUIRED TRUE) + ELSE() + SET(REQUIRED FALSE) + ENDIF() + IF(TARGET ${TARGET_NAME}) + PREPEND_GLOBAL_SET(${VARNAME} ${TARGET_NAME}) + ELSE() + IF(REQUIRED) + MESSAGE(FATAL_ERROR "Missing dependency ${TARGET_NAME}") + ENDIF() + ENDIF() +ENDMACRO() +endif() + + +FUNCTION(KOKKOS_CONFIGURE_FILE PACKAGE_NAME_CONFIG_FILE) + if (KOKKOS_HAS_TRILINOS) + TRIBITS_CONFIGURE_FILE(${PACKAGE_NAME_CONFIG_FILE}) + else() + # Configure the file + CONFIGURE_FILE( + ${PACKAGE_SOURCE_DIR}/cmake/${PACKAGE_NAME_CONFIG_FILE}.in + ${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME_CONFIG_FILE} + ) + endif() +ENDFUNCTION() + +MACRO(ADD_INTERFACE_LIBRARY LIB_NAME) + FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp "") + ADD_LIBRARY(${LIB_NAME} STATIC ${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp) + SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES INTERFACE TRUE) +ENDMACRO() + +IF(NOT TARGET check) + ADD_CUSTOM_TARGET(check COMMAND ${CMAKE_CTEST_COMMAND} -VV -C ${CMAKE_CFG_INTDIR}) +ENDIF() + +FUNCTION(KOKKOS_ADD_TEST) + if (KOKKOS_HAS_TRILINOS) + CMAKE_PARSE_ARGUMENTS(TEST + "" + "EXE;NAME" + "" + ${ARGN}) + IF(TEST_EXE) + SET(EXE_ROOT ${TEST_EXE}) + ELSE() + SET(EXE_ROOT ${TEST_NAME}) + ENDIF() + + TRIBITS_ADD_TEST( + ${EXE_ROOT} + NAME ${TEST_NAME} + ${ARGN} + COMM serial mpi + NUM_MPI_PROCS 1 + ${TEST_UNPARSED_ARGUMENTS} + ) + else() + CMAKE_PARSE_ARGUMENTS(TEST + "WILL_FAIL" + "FAIL_REGULAR_EXPRESSION;PASS_REGULAR_EXPRESSION;EXE;NAME" + "CATEGORIES;CMD_ARGS" + ${ARGN}) + IF(TEST_EXE) + SET(EXE ${TEST_EXE}) + ELSE() + SET(EXE ${TEST_NAME}) + ENDIF() + IF(WIN32) + ADD_TEST(NAME ${TEST_NAME} WORKING_DIRECTORY ${LIBRARY_OUTPUT_PATH} COMMAND ${EXE}${CMAKE_EXECUTABLE_SUFFIX} ${TEST_CMD_ARGS}) + ELSE() + ADD_TEST(NAME ${TEST_NAME} COMMAND ${EXE} ${TEST_CMD_ARGS}) + ENDIF() + IF(TEST_WILL_FAIL) + SET_TESTS_PROPERTIES(${TEST_NAME} PROPERTIES WILL_FAIL ${TEST_WILL_FAIL}) + ENDIF() + IF(TEST_FAIL_REGULAR_EXPRESSION) + SET_TESTS_PROPERTIES(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION ${TEST_FAIL_REGULAR_EXPRESSION}) + ENDIF() + IF(TEST_PASS_REGULAR_EXPRESSION) + SET_TESTS_PROPERTIES(${TEST_NAME} PROPERTIES PASS_REGULAR_EXPRESSION ${TEST_PASS_REGULAR_EXPRESSION}) + ENDIF() + VERIFY_EMPTY(KOKKOS_ADD_TEST ${TEST_UNPARSED_ARGUMENTS}) + endif() +ENDFUNCTION() + +FUNCTION(KOKKOS_ADD_ADVANCED_TEST) + if (KOKKOS_HAS_TRILINOS) + TRIBITS_ADD_ADVANCED_TEST(${ARGN}) + else() + # TODO Write this + endif() +ENDFUNCTION() + +MACRO(KOKKOS_CREATE_IMPORTED_TPL_LIBRARY TPL_NAME) + ADD_INTERFACE_LIBRARY(TPL_LIB_${TPL_NAME}) + TARGET_LINK_LIBRARIES(TPL_LIB_${TPL_NAME} LINK_PUBLIC ${TPL_${TPL_NAME}_LIBRARIES}) + TARGET_INCLUDE_DIRECTORIES(TPL_LIB_${TPL_NAME} INTERFACE ${TPL_${TPL_NAME}_INCLUDE_DIRS}) +ENDMACRO() + +FUNCTION(KOKKOS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES TPL_NAME) + if (KOKKOS_HAS_TRILINOS) + TRIBITS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES(${TPL_NAME} ${ARGN}) + else() + CMAKE_PARSE_ARGUMENTS(PARSE + "" + "" + "REQUIRED_HEADERS;REQUIRED_LIBS_NAMES" + ${ARGN}) + + SET(_${TPL_NAME}_ENABLE_SUCCESS TRUE) + IF (PARSE_REQUIRED_LIBS_NAMES) + FIND_LIBRARY(TPL_${TPL_NAME}_LIBRARIES NAMES ${PARSE_REQUIRED_LIBS_NAMES}) + IF(NOT TPL_${TPL_NAME}_LIBRARIES) + SET(_${TPL_NAME}_ENABLE_SUCCESS FALSE) + ENDIF() + ENDIF() + IF (PARSE_REQUIRED_HEADERS) + FIND_PATH(TPL_${TPL_NAME}_INCLUDE_DIRS NAMES ${PARSE_REQUIRED_HEADERS}) + IF(NOT TPL_${TPL_NAME}_INCLUDE_DIRS) + SET(_${TPL_NAME}_ENABLE_SUCCESS FALSE) + ENDIF() + ENDIF() + IF (_${TPL_NAME}_ENABLE_SUCCESS) + KOKKOS_CREATE_IMPORTED_TPL_LIBRARY(${TPL_NAME}) + ENDIF() + VERIFY_EMPTY(KOKKOS_CREATE_IMPORTED_TPL_LIBRARY ${PARSE_UNPARSED_ARGUMENTS}) + endif() +ENDFUNCTION() + +MACRO(KOKKOS_TARGET_COMPILE_OPTIONS TARGET) +if(KOKKOS_HAS_TRILINOS) + TARGET_COMPILE_OPTIONS(${TARGET} ${ARGN}) +else() + TARGET_COMPILE_OPTIONS(${TARGET} ${ARGN}) +endif() +ENDMACRO() + + +MACRO(KOKKOS_EXCLUDE_AUTOTOOLS_FILES) + if (KOKKOS_HAS_TRILINOS) + TRIBITS_EXCLUDE_AUTOTOOLS_FILES() + else() + #do nothing + endif() +ENDMACRO() + +FUNCTION(KOKKOS_LIB_TYPE LIB RET) +GET_TARGET_PROPERTY(PROP ${LIB} TYPE) +IF (${PROP} STREQUAL "INTERFACE_LIBRARY") + SET(${RET} "INTERFACE" PARENT_SCOPE) +ELSE() + SET(${RET} "PUBLIC" PARENT_SCOPE) +ENDIF() +ENDFUNCTION() + +FUNCTION(KOKKOS_TARGET_INCLUDE_DIRECTORIES TARGET) +IF(KOKKOS_HAS_TRILINOS) + KOKKOS_LIB_TYPE(${TARGET} INCTYPE) + #don't trust tribits to do this correctly - but need to add package name + TARGET_INCLUDE_DIRECTORIES(${TARGET} ${INCTYPE} ${ARGN}) +ELSEIF(TARGET ${TARGET}) + #the target actually exists - this means we are doing separate libs + #or this a test library + KOKKOS_LIB_TYPE(${TARGET} INCTYPE) + TARGET_INCLUDE_DIRECTORIES(${TARGET} ${INCTYPE} ${ARGN}) +ELSE() + GET_PROPERTY(LIBS GLOBAL PROPERTY KOKKOS_LIBRARIES_NAMES) + IF (${TARGET} IN_LIST LIBS) + SET_PROPERTY(GLOBAL APPEND PROPERTY KOKKOS_LIBRARY_INCLUDES ${ARGN}) + ELSE() + MESSAGE(FATAL_ERROR "Trying to set include directories on unknown target ${TARGET}") + ENDIF() +ENDIF() +ENDFUNCTION() + +FUNCTION(KOKKOS_LINK_INTERNAL_LIBRARY TARGET DEPLIB) +IF(KOKKOS_HAS_TRILINOS) + #do nothing +ELSE() + SET(options INTERFACE) + SET(oneValueArgs) + SET(multiValueArgs) + CMAKE_PARSE_ARGUMENTS(PARSE + "INTERFACE" + "" + "" + ${ARGN}) + SET(LINK_TYPE) + IF(PARSE_INTERFACE) + SET(LINK_TYPE INTERFACE) + ELSE() + SET(LINK_TYPE PUBLIC) + ENDIF() + TARGET_LINK_LIBRARIES(${TARGET} ${LINK_TYPE} ${DEPLIB}) + VERIFY_EMPTY(KOKKOS_LINK_INTERNAL_LIBRARY ${PARSE_UNPARSED_ARGUMENTS}) +ENDIF() +ENDFUNCTION() + +FUNCTION(KOKKOS_ADD_TEST_LIBRARY NAME) +IF (KOKKOS_HAS_TRILINOS) + TRIBITS_ADD_LIBRARY(${NAME} ${ARGN} TESTONLY + ADDED_LIB_TARGET_NAME_OUT ${NAME} + ) +ELSE() + SET(oneValueArgs) + SET(multiValueArgs HEADERS SOURCES) + + CMAKE_PARSE_ARGUMENTS(PARSE + "STATIC;SHARED" + "" + "HEADERS;SOURCES" + ${ARGN}) + + IF(PARSE_HEADERS) + LIST(REMOVE_DUPLICATES PARSE_HEADERS) + ENDIF() + IF(PARSE_SOURCES) + LIST(REMOVE_DUPLICATES PARSE_SOURCES) + ENDIF() + ADD_LIBRARY(${NAME} ${PARSE_SOURCES}) + target_link_libraries( + ${NAME} + PUBLIC kokkos + ) +ENDIF() +ENDFUNCTION() + + +FUNCTION(KOKKOS_TARGET_COMPILE_DEFINITIONS) + IF (KOKKOS_HAS_TRILINOS) + TARGET_COMPILE_DEFINITIONS(${TARGET} ${ARGN}) + ELSE() + TARGET_COMPILE_DEFINITIONS(${TARGET} ${ARGN}) + ENDIF() +ENDFUNCTION() + +FUNCTION(KOKKOS_INCLUDE_DIRECTORIES) +IF(KOKKOS_HAS_TRILINOS) + TRIBITS_INCLUDE_DIRECTORIES(${ARGN}) +ELSE() + CMAKE_PARSE_ARGUMENTS( + INC + "REQUIRED_DURING_INSTALLATION_TESTING" + "" + "" + ${ARGN} + ) + INCLUDE_DIRECTORIES(${INC_UNPARSED_ARGUMENTS}) +ENDIF() +ENDFUNCTION() + + +MACRO(KOKKOS_ADD_COMPILE_OPTIONS) +ADD_COMPILE_OPTIONS(${ARGN}) +ENDMACRO() + +MACRO(PRINTALL match) +get_cmake_property(_variableNames VARIABLES) +list (SORT _variableNames) +foreach (_variableName ${_variableNames}) + if("${_variableName}" MATCHES "${match}") + message(STATUS "${_variableName}=${${_variableName}}") + endif() +endforeach() +ENDMACRO() + +MACRO(SET_GLOBAL_REPLACE SUBSTR VARNAME) + STRING(REPLACE ${SUBSTR} ${${VARNAME}} TEMP) + GLOBAL_SET(${VARNAME} ${TEMP}) +ENDMACRO() + +FUNCTION(GLOBAL_APPEND VARNAME) + #We make this a function since we are setting variables + #and want to use scope to avoid overwriting local variables + SET(TEMP ${${VARNAME}}) + LIST(APPEND TEMP ${ARGN}) + GLOBAL_SET(${VARNAME} ${TEMP}) +ENDFUNCTION() + diff --git a/lib/kokkos/cmake/gnu.cmake b/lib/kokkos/cmake/gnu.cmake new file mode 100644 index 0000000000..aa11fe87b1 --- /dev/null +++ b/lib/kokkos/cmake/gnu.cmake @@ -0,0 +1,23 @@ + +FUNCTION(kokkos_set_gnu_flags full_standard int_standard) + STRING(TOLOWER ${full_standard} FULL_LC_STANDARD) + STRING(TOLOWER ${int_standard} INT_LC_STANDARD) + # The following three blocks of code were copied from + # /Modules/Compiler/Intel-CXX.cmake from CMake 3.7.2 and then modified. + IF(CMAKE_CXX_SIMULATE_ID STREQUAL MSVC) + SET(_std -Qstd) + SET(_ext c++) + ELSE() + SET(_std -std) + SET(_ext gnu++) + ENDIF() + + IF (CMAKE_CXX_EXTENSIONS) + SET(KOKKOS_CXX_STANDARD_FLAG "-std=gnu++${FULL_LC_STANDARD}" PARENT_SCOPE) + SET(KOKKOS_CXX_INTERMEDIATE_STANDARD_FLAG "-std=gnu++${INT_LC_STANDARD}" PARENT_SCOPE) + ELSE() + SET(KOKKOS_CXX_STANDARD_FLAG "-std=c++${FULL_LC_STANDARD}" PARENT_SCOPE) + SET(KOKKOS_CXX_INTERMEDIATE_STANDARD_FLAG "-std=c++${INT_LC_STANDARD}" PARENT_SCOPE) + ENDIF() +ENDFUNCTION() + diff --git a/lib/kokkos/cmake/intel.cmake b/lib/kokkos/cmake/intel.cmake new file mode 100644 index 0000000000..f36f01d8ca --- /dev/null +++ b/lib/kokkos/cmake/intel.cmake @@ -0,0 +1,30 @@ + +FUNCTION(kokkos_set_intel_flags full_standard int_standard) + STRING(TOLOWER ${full_standard} FULL_LC_STANDARD) + STRING(TOLOWER ${int_standard} INT_LC_STANDARD) + # The following three blocks of code were copied from + # /Modules/Compiler/Intel-CXX.cmake from CMake 3.7.2 and then modified. + IF(CMAKE_CXX_SIMULATE_ID STREQUAL MSVC) + SET(_std -Qstd) + SET(_ext c++) + ELSE() + SET(_std -std) + SET(_ext gnu++) + ENDIF() + + IF(NOT KOKKOS_CXX_STANDARD STREQUAL 11 AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0.2) + #There is no gnu++14 value supported; figure out what to do. + SET(KOKKOS_CXX_STANDARD_FLAG "${_std}=c++${FULL_LC_STANDARD}" PARENT_SCOPE) + SET(KOKKOS_CXX_INTERMEDIATE_STANDARD_FLAG "${_std}=c++${INT_LC_STANDARD}" PARENT_SCOPE) + ELSEIF(KOKKOS_CXX_STANDARD STREQUAL 11 AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.0) + IF (CMAKE_CXX_EXTENSIONS) + SET(KOKKOS_CXX_STANDARD_FLAG "${_std}=${_ext}c++11" PARENT_SCOPE) + ELSE() + SET(KOKKOS_CXX_STANDARD_FLAG "${_std}=c++11" PARENT_SCOPE) + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR "Intel compiler version too low - need 13.0 for C++11 and 15.0 for C++14") + ENDIF() + +ENDFUNCTION() + diff --git a/lib/kokkos/cmake/kokkos_arch.cmake b/lib/kokkos/cmake/kokkos_arch.cmake new file mode 100644 index 0000000000..c33247c955 --- /dev/null +++ b/lib/kokkos/cmake/kokkos_arch.cmake @@ -0,0 +1,438 @@ + +FUNCTION(KOKKOS_ARCH_OPTION SUFFIX DEV_TYPE DESCRIPTION) + #all optimizations off by default + KOKKOS_OPTION(ARCH_${SUFFIX} OFF BOOL "Optimize for ${DESCRIPTION} (${DEV_TYPE})") + IF (KOKKOS_ARCH_${SUFFIX}) + LIST(APPEND KOKKOS_ENABLED_ARCH_LIST ${SUFFIX}) + SET(KOKKOS_ENABLED_ARCH_LIST ${KOKKOS_ENABLED_ARCH_LIST} PARENT_SCOPE) + ENDIF() + SET(KOKKOS_ARCH_${SUFFIX} ${KOKKOS_ARCH_${SUFFIX}} PARENT_SCOPE) +ENDFUNCTION() + +FUNCTION(ARCH_FLAGS) + SET(COMPILERS NVIDIA PGI XL DEFAULT Cray Intel Clang AppleClang GNU) + CMAKE_PARSE_ARGUMENTS( + PARSE + "LINK_ONLY;COMPILE_ONLY" + "" + "${COMPILERS}" + ${ARGN}) + + SET(COMPILER ${KOKKOS_CXX_COMPILER_ID}) + + SET(FLAGS) + SET(NEW_COMPILE_OPTIONS) + SET(NEW_XCOMPILER_OPTIONS) + SET(NEW_LINK_OPTIONS) + LIST(APPEND NEW_XCOMPILER_OPTIONS ${KOKKOS_XCOMPILER_OPTIONS}) + LIST(APPEND NEW_COMPILE_OPTIONS ${KOKKOS_COMPILE_OPTIONS}) + LIST(APPEND NEW_LINK_OPTIONS ${KOKKOS_LINK_OPTIONS}) + FOREACH(COMP ${COMPILERS}) + IF (COMPILER STREQUAL "${COMP}") + IF (PARSE_${COMPILER}) + IF (NOT "${PARSE_${COMPILER}}" STREQUAL "NO-VALUE-SPECIFIED") + SET(FLAGS ${PARSE_${COMPILER}}) + ENDIF() + ELSEIF(PARSE_DEFAULT) + SET(FLAGS ${PARSE_DEFAULT}) + ENDIF() + ENDIF() + ENDFOREACH() + + IF (NOT LINK_ONLY) + # The funky logic here is for future handling of argument deduplication + # If we naively pass multiple -Xcompiler flags to target_compile_options + # -Xcompiler will get deduplicated and break the build + IF ("-Xcompiler" IN_LIST FLAGS) + LIST(REMOVE_ITEM FLAGS "-Xcompiler") + GLOBAL_APPEND(KOKKOS_XCOMPILER_OPTIONS ${FLAGS}) + ELSE() + GLOBAL_APPEND(KOKKOS_COMPILE_OPTIONS ${FLAGS}) + ENDIF() + ENDIF() + + IF (NOT COMPILE_ONLY) + GLOBAL_APPEND(KOKKOS_LINK_OPTIONS ${FLAGS}) + ENDIF() +ENDFUNCTION() + +# Make sure devices and compiler ID are done +KOKKOS_CFG_DEPENDS(ARCH COMPILER_ID) +KOKKOS_CFG_DEPENDS(ARCH DEVICES) +KOKKOS_CFG_DEPENDS(ARCH OPTIONS) + + +#------------------------------------------------------------------------------- +# List of possible host architectures. +#------------------------------------------------------------------------------- +SET(KOKKOS_ARCH_LIST) + + +KOKKOS_DEPRECATED_LIST(ARCH ARCH) +KOKKOS_ARCH_OPTION(AMDAVX HOST "AMD chip") +KOKKOS_ARCH_OPTION(ARMV80 HOST "ARMv8.0 Compatible CPU") +KOKKOS_ARCH_OPTION(ARMV81 HOST "ARMv8.1 Compatible CPU") +KOKKOS_ARCH_OPTION(ARMV8_THUNDERX HOST "ARMv8 Cavium ThunderX CPU") +KOKKOS_ARCH_OPTION(ARMV8_THUNDERX2 HOST "ARMv8 Cavium ThunderX2 CPU") +KOKKOS_ARCH_OPTION(WSM HOST "Intel Westmere CPU") +KOKKOS_ARCH_OPTION(SNB HOST "Intel Sandy/Ivy Bridge CPUs") +KOKKOS_ARCH_OPTION(HSW HOST "Intel Haswell CPUs") +KOKKOS_ARCH_OPTION(BDW HOST "Intel Broadwell Xeon E-class CPUs") +KOKKOS_ARCH_OPTION(SKX HOST "Intel Sky Lake Xeon E-class HPC CPUs (AVX512)") +KOKKOS_ARCH_OPTION(KNC HOST "Intel Knights Corner Xeon Phi") +KOKKOS_ARCH_OPTION(KNL HOST "Intel Knights Landing Xeon Phi") +KOKKOS_ARCH_OPTION(BGQ HOST "IBM Blue Gene Q") +KOKKOS_ARCH_OPTION(POWER7 HOST "IBM POWER7 CPUs") +KOKKOS_ARCH_OPTION(POWER8 HOST "IBM POWER8 CPUs") +KOKKOS_ARCH_OPTION(POWER9 HOST "IBM POWER9 CPUs") +KOKKOS_ARCH_OPTION(KEPLER30 GPU "NVIDIA Kepler generation CC 3.0") +KOKKOS_ARCH_OPTION(KEPLER32 GPU "NVIDIA Kepler generation CC 3.2") +KOKKOS_ARCH_OPTION(KEPLER35 GPU "NVIDIA Kepler generation CC 3.5") +KOKKOS_ARCH_OPTION(KEPLER37 GPU "NVIDIA Kepler generation CC 3.7") +KOKKOS_ARCH_OPTION(MAXWELL50 GPU "NVIDIA Maxwell generation CC 5.0") +KOKKOS_ARCH_OPTION(MAXWELL52 GPU "NVIDIA Maxwell generation CC 5.2") +KOKKOS_ARCH_OPTION(MAXWELL53 GPU "NVIDIA Maxwell generation CC 5.3") +KOKKOS_ARCH_OPTION(PASCAL60 GPU "NVIDIA Pascal generation CC 6.0") +KOKKOS_ARCH_OPTION(PASCAL61 GPU "NVIDIA Pascal generation CC 6.1") +KOKKOS_ARCH_OPTION(VOLTA70 GPU "NVIDIA Volta generation CC 7.0") +KOKKOS_ARCH_OPTION(VOLTA72 GPU "NVIDIA Volta generation CC 7.2") +KOKKOS_ARCH_OPTION(TURING75 GPU "NVIDIA Turing generation CC 7.5") +KOKKOS_ARCH_OPTION(EPYC HOST "AMD Epyc architecture") + + +IF (KOKKOS_ENABLE_CUDA) + #Regardless of version, make sure we define the general architecture name + IF (KOKKOS_ARCH_KEPLER30 OR KOKKOS_ARCH_KEPLER32 OR KOKKOS_ARCH_KEPLER35 OR KOKKOS_ARCH_KEPLER37) + SET(KOKKOS_ARCH_KEPLER ON) + ENDIF() + + #Regardless of version, make sure we define the general architecture name + IF (KOKKOS_ARCH_MAXWELL50 OR KOKKOS_ARCH_MAXWELL52 OR KOKKOS_ARCH_MAXWELL53) + SET(KOKKOS_ARCH_MAXWELL ON) + ENDIF() + + #Regardless of version, make sure we define the general architecture name + IF (KOKKOS_ARCH_PASCAL60 OR KOKKOS_ARCH_PASCAL61) + SET(KOKKOS_ARCH_PASCAL ON) + ENDIF() + + #Regardless of version, make sure we define the general architecture name + IF (KOKKOS_ARCH_VOLTA70 OR KOKKOS_ARCH_VOLTA72) + SET(KOKKOS_ARCH_VOLTA ON) + ENDIF() +ENDIF() + + + +IF(KOKKOS_ENABLE_COMPILER_WARNINGS) + SET(COMMON_WARNINGS + "-Wall" "-Wshadow" "-pedantic" + "-Wsign-compare" "-Wtype-limits" "-Wuninitialized") + + SET(GNU_WARNINGS "-Wempty-body" "-Wclobbered" "-Wignored-qualifiers" + ${COMMON_WARNINGS}) + + ARCH_FLAGS( + PGI NO-VALUE-SPECIFIED + GNU ${GNU_WARNINGS} + DEFAULT ${COMMON_WARNINGS} + ) +ENDIF() + + +#------------------------------- KOKKOS_CUDA_OPTIONS --------------------------- +GLOBAL_RESET(KOKKOS_CUDA_OPTIONS) +# Construct the Makefile options +IF (KOKKOS_ENABLE_CUDA_LAMBDA) + IF(KOKKOS_CXX_COMPILER_ID STREQUAL NVIDIA) + GLOBAL_APPEND(KOKKOS_CUDA_OPTIONS "-expt-extended-lambda") + ENDIF() +ENDIF() + +IF (KOKKOS_ENABLE_CUDA_CONSTEXPR) + IF(KOKKOS_CXX_COMPILER_ID STREQUAL NVIDIA) + GLOBAL_APPEND(KOKKOS_CUDA_OPTIONS "-expt-relaxed-constexpr") + ENDIF() +ENDIF() + +IF (KOKKOS_CXX_COMPILER_ID STREQUAL Clang) + SET(CUDA_ARCH_FLAG "--cuda-gpu-arch") + GLOBAL_APPEND(KOKKOS_CUDA_OPTIONS -x cuda) + IF (KOKKOS_ENABLE_CUDA) + SET(KOKKOS_IMPL_CUDA_CLANG_WORKAROUND ON CACHE BOOL "enable CUDA Clang workarounds" FORCE) + ENDIF() +ELSEIF(KOKKOS_CXX_COMPILER_ID STREQUAL NVIDIA) + SET(CUDA_ARCH_FLAG "-arch") +ENDIF() + +IF (KOKKOS_CXX_COMPILER_ID STREQUAL NVIDIA) + STRING(TOUPPER "${CMAKE_BUILD_TYPE}" _UPPERCASE_CMAKE_BUILD_TYPE) + IF (KOKKOS_ENABLE_DEBUG OR _UPPERCASE_CMAKE_BUILD_TYPE STREQUAL "DEBUG") + GLOBAL_APPEND(KOKKOS_CUDA_OPTIONS -lineinfo) + ENDIF() + UNSET(_UPPERCASE_CMAKE_BUILD_TYPE) + IF (KOKKOS_CXX_COMPILER_VERSION VERSION_GREATER 9.0 OR KOKKOS_CXX_COMPILER_VERSION VERSION_EQUAL 9.0) + GLOBAL_APPEND(KOKKOS_CUDAFE_OPTIONS --diag_suppress=esa_on_defaulted_function_ignored) + ENDIF() +ENDIF() + +IF(KOKKOS_ENABLE_OPENMP) + IF (KOKKOS_CXX_COMPILER_ID STREQUAL AppleClang) + MESSAGE(FATAL_ERROR "Apple Clang does not support OpenMP. Use native Clang instead") + ENDIF() + ARCH_FLAGS( + Clang -fopenmp=libomp + PGI -mp + NVIDIA -Xcompiler -fopenmp + Cray NO-VALUE-SPECIFIED + XL -qsmp=omp + DEFAULT -fopenmp + ) +ENDIF() + +IF (KOKKOS_ARCH_ARMV80) + ARCH_FLAGS( + Cray NO-VALUE-SPECIFIED + PGI NO-VALUE-SPECIFIED + DEFAULT -march=armv8-a + ) +ENDIF() + +IF (KOKKOS_ARCH_ARMV81) + ARCH_FLAGS( + Cray NO-VALUE-SPECIFIED + PGI NO-VALUE-SPECIFIED + DEFAULT -march=armv8.1-a + ) +ENDIF() + +IF (KOKKOS_ARCH_ARMV8_THUNDERX) + SET(KOKKOS_ARCH_ARMV80 ON) #Not a cache variable + ARCH_FLAGS( + Cray NO-VALUE-SPECIFIED + PGI NO-VALUE-SPECIFIED + DEFAULT -march=armv8-a -mtune=thunderx + ) +ENDIF() + +IF (KOKKOS_ARCH_ARMV8_THUNDERX2) + SET(KOKKOS_ARCH_ARMV81 ON) #Not a cache variable + ARCH_FLAGS( + Cray NO-VALUE-SPECIFIED + PGI NO-VALUE-SPECIFIED + DEFAULT -mcpu=thunderx2t99 -mtune=thunderx2t99 + ) +ENDIF() + +IF (KOKKOS_ARCH_EPYC) + ARCH_FLAGS( + Intel -mavx2 + DEFAULT -march=znver1 -mtune=znver1 + ) + SET(KOKKOS_ARCH_AMD_EPYC ON) + SET(KOKKOS_ARCH_AMD_AVX2 ON) +ENDIF() + +IF (KOKKOS_ARCH_WSM) + ARCH_FLAGS( + Intel -xSSE4.2 + PGI -tp=nehalem + Cray NO-VALUE-SPECIFIED + DEFAULT -msse4.2 + ) + SET(KOKKOS_ARCH_SSE42 ON) +ENDIF() + +IF (KOKKOS_ARCH_SNB OR KOKKOS_ARCH_AMDAVX) + SET(KOKKOS_ARCH_AVX ON) + ARCH_FLAGS( + Intel -mavx + PGI -tp=sandybridge + Cray NO-VALUE-SPECIFIED + DEFAULT -mavx + ) +ENDIF() + +IF (KOKKOS_ARCH_HSW) + SET(KOKKOS_ARCH_AVX2 ON) + ARCH_FLAGS( + Intel -xCORE-AVX2 + PGI -tp=haswell + Cray NO-VALUE-SPECIFIED + DEFAULT -march=core-avx2 -mtune=core-avx2 + ) +ENDIF() + +IF (KOKKOS_ARCH_BDW) + SET(KOKKOS_ARCH_AVX2 ON) + ARCH_FLAGS( + Intel -xCORE-AVX2 + PGI -tp=haswell + Cray NO-VALUE-SPECIFIED + DEFAULT -march=core-avx2 -mtune=core-avx2 -mrtm + ) +ENDIF() + +IF (KOKKOS_ARCH_EPYC) + SET(KOKKOS_ARCH_AMD_AVX2 ON) + ARCH_FLAGS( + Intel -mvax2 + DEFAULT -march=znver1 -mtune=znver1 + ) +ENDIF() + +IF (KOKKOS_ARCH_KNL) + #avx512-mic + SET(KOKKOS_ARCH_AVX512MIC ON) #not a cache variable + ARCH_FLAGS( + Intel -xMIC-AVX512 + PGI NO-VALUE-SPECIFIED + Cray NO-VALUE-SPECIFIED + DEFAULT -march=knl -mtune=knl + ) +ENDIF() + +IF (KOKKOS_ARCH_KNC) + SET(KOKKOS_USE_ISA_KNC ON) + ARCH_FLAGS( + DEFAULT -mmic + ) +ENDIF() + +IF (KOKKOS_ARCH_SKX) + #avx512-xeon + SET(KOKKOS_ARCH_AVX512XEON ON) + ARCH_FLAGS( + Intel -xCORE-AVX512 + PGI NO-VALUE-SPECIFIED + Cray NO-VALUE-SPECIFIED + DEFAULT -march=skylake-avx512 -mtune=skylake-avx512 -mrtm + ) +ENDIF() + +IF (KOKKOS_ARCH_WSM OR KOKKOS_ARCH_SNB OR KOKKOS_ARCH_HSW OR KOKKOS_ARCH_BDW OR KOKKOS_ARCH_KNL OR KOKKOS_ARCH_SKX OR KOKKOS_ARCH_EPYC) + SET(KOKKOS_USE_ISA_X86_64 ON) +ENDIF() + +IF (KOKKOS_ARCH_BDW OR KOKKOS_ARCH_SKX) + SET(KOKKOS_ENABLE_TM ON) #not a cache variable +ENDIF() + +IF (KOKKOS_ARCH_POWER7) + ARCH_FLAGS( + PGI NO-VALUE-SPECIFIED + DEFAULT -mcpu=power7 -mtune=power7 + ) + SET(KOKKOS_USE_ISA_POWERPCBE ON) +ENDIF() + +IF (KOKKOS_ARCH_POWER8) + ARCH_FLAGS( + PGI NO-VALUE-SPECIFIED + NVIDIA NO-VALUE-SPECIFIED + DEFAULT -mcpu=power8 -mtune=power8 + ) +ENDIF() + +IF (KOKKOS_ARCH_POWER9) + ARCH_FLAGS( + PGI NO-VALUE-SPECIFIED + NVIDIA NO-VALUE-SPECIFIED + DEFAULT -mcpu=power9 -mtune=power9 + ) +ENDIF() + +IF (KOKKOS_ARCH_POWER8 OR KOKKOS_ARCH_POWER9) + SET(KOKKOS_USE_ISA_POWERPCLE ON) +ENDIF() + +IF (Kokkos_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE) + ARCH_FLAGS( + Clang -fcuda-rdc + NVIDIA --relocatable-device-code=true + ) +ENDIF() + + +SET(CUDA_ARCH_ALREADY_SPECIFIED "") +FUNCTION(CHECK_CUDA_ARCH ARCH FLAG) +IF(KOKKOS_ARCH_${ARCH}) + IF(CUDA_ARCH_ALREADY_SPECIFIED) + MESSAGE(FATAL_ERROR "Multiple GPU architectures given! Already have ${CUDA_ARCH_ALREADY_SPECIFIED}, but trying to add ${ARCH}. If you are re-running CMake, try clearing the cache and running again.") + ENDIF() + SET(CUDA_ARCH_ALREADY_SPECIFIED ${ARCH} PARENT_SCOPE) + IF (NOT KOKKOS_ENABLE_CUDA) + MESSAGE(WARNING "Given CUDA arch ${ARCH}, but Kokkos_ENABLE_CUDA is OFF. Option will be ignored.") + UNSET(KOKKOS_ARCH_${ARCH} PARENT_SCOPE) + ELSE() + GLOBAL_APPEND(KOKKOS_CUDA_OPTIONS "${CUDA_ARCH_FLAG}=${FLAG}") + IF(KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE) + GLOBAL_APPEND(KOKKOS_LINK_OPTIONS "${CUDA_ARCH_FLAG}=${FLAG}") + ENDIF() + ENDIF() +ENDIF() +ENDFUNCTION() + + +CHECK_CUDA_ARCH(KEPLER30 sm_30) +CHECK_CUDA_ARCH(KEPLER32 sm_32) +CHECK_CUDA_ARCH(KEPLER35 sm_35) +CHECK_CUDA_ARCH(KEPLER37 sm_37) +CHECK_CUDA_ARCH(MAXWELL50 sm_50) +CHECK_CUDA_ARCH(MAXWELL52 sm_52) +CHECK_CUDA_ARCH(MAXWELL53 sm_53) +CHECK_CUDA_ARCH(PASCAL60 sm_60) +CHECK_CUDA_ARCH(PASCAL61 sm_61) +CHECK_CUDA_ARCH(VOLTA70 sm_70) +CHECK_CUDA_ARCH(VOLTA72 sm_72) +CHECK_CUDA_ARCH(TURING75 sm_75) + +#CMake verbose is kind of pointless +#Let's just always print things +MESSAGE(STATUS "Execution Spaces:") +IF(KOKKOS_ENABLE_CUDA) + MESSAGE(STATUS " Device Parallel: CUDA") +ELSE() + MESSAGE(STATUS " Device Parallel: NONE") +ENDIF() + +FOREACH (_BACKEND OPENMP PTHREAD HPX) + IF(KOKKOS_ENABLE_${_BACKEND}) + IF(_HOST_PARALLEL) + MESSAGE(FATAL_ERROR "Multiple host parallel execution spaces are not allowed! " + "Trying to enable execution space ${_BACKEND}, " + "but execution space ${_HOST_PARALLEL} is already enabled. " + "Remove the CMakeCache.txt file and re-configure.") + ENDIF() + SET(_HOST_PARALLEL ${_BACKEND}) + ENDIF() +ENDFOREACH() + +IF(NOT _HOST_PARALLEL AND NOT KOKKOS_ENABLE_SERIAL) + MESSAGE(FATAL_ERROR "At least one host execution space must be enabled, " + "but no host parallel execution space was requested " + "and Kokkos_ENABLE_SERIAL=OFF.") +ENDIF() + +IF(NOT _HOST_PARALLEL) + SET(_HOST_PARALLEL "NONE") +ENDIF() +MESSAGE(STATUS " Host Parallel: ${_HOST_PARALLEL}") +UNSET(_HOST_PARALLEL) + +IF(KOKKOS_ENABLE_PTHREAD) + SET(KOKKOS_ENABLE_THREADS ON) +ENDIF() + +IF(KOKKOS_ENABLE_SERIAL) + MESSAGE(STATUS " Host Serial: SERIAL") +ELSE() + MESSAGE(STATUS " Host Serial: NONE") +ENDIF() + +MESSAGE(STATUS "") +MESSAGE(STATUS "Architectures:") +FOREACH(Arch ${KOKKOS_ENABLED_ARCH_LIST}) + MESSAGE(STATUS " ${Arch}") +ENDFOREACH() + diff --git a/lib/kokkos/cmake/kokkos_build.cmake b/lib/kokkos/cmake/kokkos_build.cmake deleted file mode 100644 index f9b995baae..0000000000 --- a/lib/kokkos/cmake/kokkos_build.cmake +++ /dev/null @@ -1,261 +0,0 @@ -############################ Detect if submodule ############################### -# -# With thanks to StackOverflow: -# http://stackoverflow.com/questions/25199677/how-to-detect-if-current-scope-has-a-parent-in-cmake -# -get_directory_property(HAS_PARENT PARENT_DIRECTORY) -if(HAS_PARENT) - message(STATUS "Submodule build") - SET(KOKKOS_HEADER_DIR "include/kokkos") -else() - message(STATUS "Standalone build") - SET(KOKKOS_HEADER_DIR "include") -endif() - -################################ Handle the actual build ####################### - -SET(INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries") -SET(INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables") -SET(INSTALL_INCLUDE_DIR ${KOKKOS_HEADER_DIR} CACHE PATH - "Installation directory for header files") -IF(WIN32 AND NOT CYGWIN) - SET(DEF_INSTALL_CMAKE_DIR CMake) -ELSE() - SET(DEF_INSTALL_CMAKE_DIR lib/CMake/Kokkos) -ENDIF() - -SET(INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH - "Installation directory for CMake files") - -# Make relative paths absolute (needed later on) -FOREACH(p LIB BIN INCLUDE CMAKE) - SET(var INSTALL_${p}_DIR) - IF(NOT IS_ABSOLUTE "${${var}}") - SET(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}") - ENDIF() -ENDFOREACH() - -# set up include-directories -SET (Kokkos_INCLUDE_DIRS - ${Kokkos_SOURCE_DIR}/core/src - ${Kokkos_SOURCE_DIR}/containers/src - ${Kokkos_SOURCE_DIR}/algorithms/src - ${Kokkos_BINARY_DIR} # to find KokkosCore_config.h - ${KOKKOS_INCLUDE_DIRS} -) - -# pass include dirs back to parent scope -if(HAS_PARENT) -SET(Kokkos_INCLUDE_DIRS_RET ${Kokkos_INCLUDE_DIRS} PARENT_SCOPE) -else() -SET(Kokkos_INCLUDE_DIRS_RET ${Kokkos_INCLUDE_DIRS}) -endif() - -INCLUDE_DIRECTORIES(${Kokkos_INCLUDE_DIRS}) - -IF(KOKKOS_SEPARATE_LIBS) - # Sources come from makefile-generated kokkos_generated_settings.cmake file - # Separate libs need to separate the sources - set_kokkos_srcs(KOKKOS_SRC ${KOKKOS_SRC}) - - # kokkoscore - ADD_LIBRARY( - kokkoscore - ${KOKKOS_CORE_SRCS} - ) - - target_compile_options( - kokkoscore - PUBLIC $<$:${KOKKOS_CXX_FLAGS}> - ) - - target_include_directories( - kokkoscore - PUBLIC - ${KOKKOS_TPL_INCLUDE_DIRS} - ) - - foreach(lib IN LISTS KOKKOS_TPL_LIBRARY_NAMES) - if (("${lib}" STREQUAL "cuda") AND (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")) - set(LIB_cuda "-lcuda") - elseif ("${lib}" STREQUAL "hpx") - find_package(HPX REQUIRED) - if(${HPX_FOUND}) - target_link_libraries(kokkoscore PUBLIC ${HPX_LIBRARIES}) - target_link_libraries(kokkoscontainers PUBLIC ${HPX_LIBRARIES}) - target_link_libraries(kokkosalgorithms PUBLIC ${HPX_LIBRARIES}) - target_include_directories(kokkoscore PUBLIC ${HPX_INCLUDE_DIRS}) - target_include_directories(kokkoscontainers PUBLIC ${HPX_INCLUDE_DIRS}) - target_include_directories(kokkosalgorithms PUBLIC ${HPX_INCLUDE_DIRS}) - else() - message(ERROR "HPX not found. Check the value of HPX_DIR (= ${HPX_DIR}) or CMAKE_PREFIX_PATH (= ${CMAKE_PREFIX_PATH}).") - endif() - else() - find_library(LIB_${lib} ${lib} PATHS ${KOKKOS_TPL_LIBRARY_DIRS}) - endif() - target_link_libraries(kokkoscore PUBLIC ${LIB_${lib}}) - endforeach() - - target_link_libraries(kokkoscore PUBLIC "${KOKKOS_LINK_FLAGS}") - - # Install the kokkoscore library - INSTALL (TARGETS kokkoscore - EXPORT KokkosTargets - ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib - LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib - RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin - ) - - # kokkoscontainers - if (DEFINED KOKKOS_CONTAINERS_SRCS) - ADD_LIBRARY( - kokkoscontainers - ${KOKKOS_CONTAINERS_SRCS} - ) - endif() - - TARGET_LINK_LIBRARIES( - kokkoscontainers - kokkoscore - ) - - # Install the kokkocontainers library - INSTALL (TARGETS kokkoscontainers - EXPORT KokkosTargets - ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib - LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib - RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) - - # kokkosalgorithms - Build as interface library since no source files. - ADD_LIBRARY( - kokkosalgorithms - INTERFACE - ) - - target_include_directories( - kokkosalgorithms - INTERFACE ${Kokkos_SOURCE_DIR}/algorithms/src - ) - - TARGET_LINK_LIBRARIES( - kokkosalgorithms - INTERFACE kokkoscore - ) - - # Install the kokkoalgorithms library - INSTALL (TARGETS kokkosalgorithms - ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib - LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib - RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) - - SET (Kokkos_LIBRARIES_NAMES kokkoscore kokkoscontainers kokkosalgorithms) - -ELSE() - # kokkos - ADD_LIBRARY( - kokkos - ${KOKKOS_CORE_SRCS} - ${KOKKOS_CONTAINERS_SRCS} - ) - - target_compile_options( - kokkos - PUBLIC $<$:${KOKKOS_CXX_FLAGS}> - ) - - target_include_directories( - kokkos - PUBLIC - ${KOKKOS_TPL_INCLUDE_DIRS} - ) - - foreach(lib IN LISTS KOKKOS_TPL_LIBRARY_NAMES) - if (("${lib}" STREQUAL "cuda") AND (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")) - set(LIB_cuda "-lcuda") - elseif ("${lib}" STREQUAL "hpx") - find_package(HPX REQUIRED) - if(${HPX_FOUND}) - target_link_libraries(kokkos PUBLIC ${HPX_LIBRARIES}) - target_include_directories(kokkos PUBLIC ${HPX_INCLUDE_DIRS}) - else() - message(ERROR "HPX not found. Check the value of HPX_DIR (= ${HPX_DIR}) or CMAKE_PREFIX_PATH (= ${CMAKE_PREFIX_PATH}).") - endif() - else() - find_library(LIB_${lib} ${lib} PATHS ${KOKKOS_TPL_LIBRARY_DIRS}) - endif() - target_link_libraries(kokkos PUBLIC ${LIB_${lib}}) - endforeach() - - target_link_libraries(kokkos PUBLIC "${KOKKOS_LINK_FLAGS}") - - # Install the kokkos library - INSTALL (TARGETS kokkos - EXPORT KokkosTargets - ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib - LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib - RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) - - - SET (Kokkos_LIBRARIES_NAMES kokkos) - -endif() # KOKKOS_SEPARATE_LIBS - -# Install the kokkos headers -INSTALL (DIRECTORY - EXPORT KokkosTargets - ${Kokkos_SOURCE_DIR}/core/src/ - DESTINATION ${KOKKOS_HEADER_DIR} - FILES_MATCHING PATTERN "*.hpp" -) -INSTALL (DIRECTORY - EXPORT KokkosTargets - ${Kokkos_SOURCE_DIR}/containers/src/ - DESTINATION ${KOKKOS_HEADER_DIR} - FILES_MATCHING PATTERN "*.hpp" -) -INSTALL (DIRECTORY - EXPORT KokkosTargets - ${Kokkos_SOURCE_DIR}/algorithms/src/ - DESTINATION ${KOKKOS_HEADER_DIR} - FILES_MATCHING PATTERN "*.hpp" -) - -INSTALL (FILES - ${Kokkos_BINARY_DIR}/KokkosCore_config.h - DESTINATION ${KOKKOS_HEADER_DIR} -) - -# Add all targets to the build-tree export set -export(TARGETS ${Kokkos_LIBRARIES_NAMES} - FILE "${Kokkos_BINARY_DIR}/KokkosTargets.cmake") - -# Export the package for use from the build-tree -# (this registers the build-tree with a global CMake-registry) -export(PACKAGE Kokkos) - -# Create the KokkosConfig.cmake and KokkosConfigVersion files -file(RELATIVE_PATH REL_INCLUDE_DIR "${INSTALL_CMAKE_DIR}" - "${INSTALL_INCLUDE_DIR}") -# ... for the build tree -set(CONF_INCLUDE_DIRS "${Kokkos_SOURCE_DIR}" "${Kokkos_BINARY_DIR}") -configure_file(${Kokkos_SOURCE_DIR}/cmake/KokkosConfig.cmake.in - "${Kokkos_BINARY_DIR}/KokkosConfig.cmake" @ONLY) -# ... for the install tree -set(CONF_INCLUDE_DIRS "\${Kokkos_CMAKE_DIR}/${REL_INCLUDE_DIR}") -configure_file(${Kokkos_SOURCE_DIR}/cmake/KokkosConfig.cmake.in - "${Kokkos_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/KokkosConfig.cmake" @ONLY) - -# Install the KokkosConfig.cmake and KokkosConfigVersion.cmake -install(FILES - "${Kokkos_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/KokkosConfig.cmake" - DESTINATION "${INSTALL_CMAKE_DIR}") - -#This seems not to do anything? -#message(STATUS "KokkosTargets: " ${KokkosTargets}) -# Install the export set for use with the install-tree -INSTALL(EXPORT KokkosTargets DESTINATION - "${INSTALL_CMAKE_DIR}") - -# build and install pkgconfig file -CONFIGURE_FILE(core/src/kokkos.pc.in kokkos.pc @ONLY) -INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/kokkos.pc DESTINATION lib/pkgconfig) diff --git a/lib/kokkos/cmake/kokkos_compiler_id.cmake b/lib/kokkos/cmake/kokkos_compiler_id.cmake new file mode 100644 index 0000000000..d239c3b32e --- /dev/null +++ b/lib/kokkos/cmake/kokkos_compiler_id.cmake @@ -0,0 +1,80 @@ +KOKKOS_CFG_DEPENDS(COMPILER_ID NONE) + +SET(KOKKOS_CXX_COMPILER ${CMAKE_CXX_COMPILER}) +SET(KOKKOS_CXX_COMPILER_ID ${CMAKE_CXX_COMPILER_ID}) +SET(KOKKOS_CXX_COMPILER_VERSION ${CMAKE_CXX_COMPILER_VERSION}) + +# Check if the compiler is nvcc (which really means nvcc_wrapper). +EXECUTE_PROCESS(COMMAND ${CMAKE_CXX_COMPILER} --version + COMMAND grep nvcc + COMMAND wc -l + OUTPUT_VARIABLE INTERNAL_HAVE_COMPILER_NVCC + OUTPUT_STRIP_TRAILING_WHITESPACE) + + +STRING(REGEX REPLACE "^ +" "" + INTERNAL_HAVE_COMPILER_NVCC ${INTERNAL_HAVE_COMPILER_NVCC}) + + +IF(INTERNAL_HAVE_COMPILER_NVCC) + # SET the compiler id to nvcc. We use the value used by CMake 3.8. + SET(KOKKOS_CXX_COMPILER_ID NVIDIA CACHE STRING INTERNAL FORCE) + + # SET nvcc's compiler version. + EXECUTE_PROCESS(COMMAND ${CMAKE_CXX_COMPILER} --version + COMMAND grep release + OUTPUT_VARIABLE INTERNAL_CXX_COMPILER_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + + STRING(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+$" + TEMP_CXX_COMPILER_VERSION ${INTERNAL_CXX_COMPILER_VERSION}) + SET(KOKKOS_CXX_COMPILER_VERSION ${TEMP_CXX_COMPILER_VERSION} CACHE STRING INTERNAL FORCE) +ENDIF() + +IF(KOKKOS_CXX_COMPILER_ID STREQUAL Cray) + + # SET nvcc's compiler version. + EXECUTE_PROCESS(COMMAND ${CMAKE_CXX_COMPILER} --version + OUTPUT_VARIABLE INTERNAL_CXX_COMPILER_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + + STRING(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+$" + TEMP_CXX_COMPILER_VERSION ${INTERNAL_CXX_COMPILER_VERSION}) + SET(KOKKOS_CXX_COMPILER_VERSION ${TEMP_CXX_COMPILER_VERSION} CACHE STRING INTERNAL FORCE) +ENDIF() + +# Enforce the minimum compilers supported by Kokkos. +SET(KOKKOS_MESSAGE_TEXT "Compiler not supported by Kokkos. Required compiler versions:") +SET(KOKKOS_MESSAGE_TEXT "${KOKKOS_MESSAGE_TEXT}\n Clang 3.5.2 or higher") +SET(KOKKOS_MESSAGE_TEXT "${KOKKOS_MESSAGE_TEXT}\n GCC 4.8.4 or higher") +SET(KOKKOS_MESSAGE_TEXT "${KOKKOS_MESSAGE_TEXT}\n Intel 15.0.2 or higher") +SET(KOKKOS_MESSAGE_TEXT "${KOKKOS_MESSAGE_TEXT}\n NVCC 9.0.69 or higher") +SET(KOKKOS_MESSAGE_TEXT "${KOKKOS_MESSAGE_TEXT}\n PGI 17.1 or higher\n") + +IF(KOKKOS_CXX_COMPILER_ID STREQUAL Clang) + IF(KOKKOS_CXX_COMPILER_VERSION VERSION_LESS 3.5.2) + MESSAGE(FATAL_ERROR "${KOKKOS_MESSAGE_TEXT}") + ENDIF() +ELSEIF(KOKKOS_CXX_COMPILER_ID STREQUAL GNU) + IF(KOKKOS_CXX_COMPILER_VERSION VERSION_LESS 4.8.4) + MESSAGE(FATAL_ERROR "${KOKKOS_MESSAGE_TEXT}") + ENDIF() +ELSEIF(KOKKOS_CXX_COMPILER_ID STREQUAL Intel) + IF(KOKKOS_CXX_COMPILER_VERSION VERSION_LESS 15.0.2) + MESSAGE(FATAL_ERROR "${KOKKOS_MESSAGE_TEXT}") + ENDIF() +ELSEIF(KOKKOS_CXX_COMPILER_ID STREQUAL NVIDIA) + IF(KOKKOS_CXX_COMPILER_VERSION VERSION_LESS 9.0.69) + MESSAGE(FATAL_ERROR "${KOKKOS_MESSAGE_TEXT}") + ENDIF() + SET(CMAKE_CXX_EXTENSIONS OFF CACHE BOOL "Kokkos turns off CXX extensions" FORCE) +ELSEIF(KOKKOS_CXX_COMPILER_ID STREQUAL PGI) + IF(KOKKOS_CXX_COMPILER_VERSION VERSION_LESS 17.1) + MESSAGE(FATAL_ERROR "${KOKKOS_MESSAGE_TEXT}") + ENDIF() +ENDIF() + +STRING(REPLACE "." ";" VERSION_LIST ${KOKKOS_CXX_COMPILER_VERSION}) +LIST(GET VERSION_LIST 0 KOKKOS_COMPILER_VERSION_MAJOR) +LIST(GET VERSION_LIST 1 KOKKOS_COMPILER_VERSION_MINOR) +LIST(GET VERSION_LIST 2 KOKKOS_COMPILER_VERSION_PATCH) diff --git a/lib/kokkos/cmake/kokkos_corner_cases.cmake b/lib/kokkos/cmake/kokkos_corner_cases.cmake new file mode 100644 index 0000000000..c03c385faf --- /dev/null +++ b/lib/kokkos/cmake/kokkos_corner_cases.cmake @@ -0,0 +1,35 @@ +IF(KOKKOS_CXX_COMPILER_ID STREQUAL Clang AND KOKKOS_ENABLE_OPENMP) + # The clang "version" doesn't actually tell you what runtimes and tools + # were built into Clang. We should therefore make sure that libomp + # was actually built into Clang. Otherwise the user will get nonsensical + # errors when they try to build. + + #Try compile is the height of CMake nonsense + #I can't just give it compiler and link flags + #I have to hackily pretend that compiler flags are compiler definitions + #and that linker flags are libraries + #also - this is easier to use than CMakeCheckCXXSourceCompiles + TRY_COMPILE(CLANG_HAS_OMP + ${KOKKOS_TOP_BUILD_DIR}/corner_cases + ${KOKKOS_SOURCE_DIR}/cmake/compile_tests/clang_omp.cpp + COMPILE_DEFINITIONS -fopenmp=libomp + LINK_LIBRARIES -fopenmp=libomp + ) + IF (NOT CLANG_HAS_OMP) + UNSET(CLANG_HAS_OMP CACHE) #make sure CMake always re-runs this + MESSAGE(FATAL_ERROR "Clang failed OpenMP check. You have requested -DKokkos_ENABLE_OPENMP=ON, but the Clang compiler does not appear to have been built with OpenMP support") + ENDIF() + UNSET(CLANG_HAS_OMP CACHE) #make sure CMake always re-runs this +ENDIF() + + +IF (KOKKOS_CXX_STANDARD STREQUAL 17) + IF (KOKKOS_CXX_COMPILER_ID STREQUAL GNU AND KOKKOS_CXX_COMPILER_VERSION VERSION_LESS 7) + MESSAGE(FATAL_ERROR "You have requested c++17 support for GCC ${KOKKOS_CXX_COMPILER_VERSION}. Although CMake has allowed this and GCC accepts -std=c++1z/c++17, GCC <= 6 does not properly support *this capture. Please reduce the C++ standard to 14 or upgrade the compiler if you do need 17 support") + ENDIF() + + IF (KOKKOS_CXX_COMPILER_ID STREQUAL NVIDIA) + MESSAGE(FATAL_ERROR "You have requested c++17 support for NVCC. Please reduce the C++ standard to 14. No versions of NVCC currently support 17.") + ENDIF() +ENDIF() + diff --git a/lib/kokkos/cmake/kokkos_enable_devices.cmake b/lib/kokkos/cmake/kokkos_enable_devices.cmake new file mode 100644 index 0000000000..ff09876673 --- /dev/null +++ b/lib/kokkos/cmake/kokkos_enable_devices.cmake @@ -0,0 +1,61 @@ + +FUNCTION(KOKKOS_DEVICE_OPTION SUFFIX DEFAULT DEV_TYPE DOCSTRING) + KOKKOS_OPTION(ENABLE_${SUFFIX} ${DEFAULT} BOOL ${DOCSTRING}) + STRING(TOUPPER ${SUFFIX} UC_NAME) + IF (KOKKOS_ENABLE_${UC_NAME}) + LIST(APPEND KOKKOS_ENABLED_DEVICES ${SUFFIX}) + #I hate that CMake makes me do this + SET(KOKKOS_ENABLED_DEVICES ${KOKKOS_ENABLED_DEVICES} PARENT_SCOPE) + ENDIF() + SET(KOKKOS_ENABLE_${UC_NAME} ${KOKKOS_ENABLE_${UC_NAME}} PARENT_SCOPE) + IF (KOKKOS_ENABLE_${UC_NAME} AND DEV_TYPE STREQUAL "HOST") + SET(KOKKOS_HAS_HOST ON PARENT_SCOPE) + ENDIF() +ENDFUNCTION() + +KOKKOS_CFG_DEPENDS(DEVICES NONE) + +# Put a check in just in case people are using this option +KOKKOS_DEPRECATED_LIST(DEVICES ENABLE) + + +KOKKOS_DEVICE_OPTION(PTHREAD OFF HOST "Whether to build Pthread backend") +IF (KOKKOS_ENABLE_PTHREAD) + #patch the naming here + SET(KOKKOS_ENABLE_THREADS ON) +ENDIF() + +IF(Trilinos_ENABLE_Kokkos AND Trilinos_ENABLE_OpenMP) + SET(OMP_DEFAULT ON) +ELSE() + SET(OMP_DEFAULT OFF) +ENDIF() +KOKKOS_DEVICE_OPTION(OPENMP ${OMP_DEFAULT} HOST "Whether to build OpenMP backend") + +IF(Trilinos_ENABLE_Kokkos AND TPL_ENABLE_CUDA) + SET(CUDA_DEFAULT ON) +ELSE() + SET(CUDA_DEFAULT OFF) +ENDIF() +KOKKOS_DEVICE_OPTION(CUDA ${CUDA_DEFAULT} DEVICE "Whether to build CUDA backend") + +IF (KOKKOS_ENABLE_CUDA) + GLOBAL_SET(KOKKOS_DONT_ALLOW_EXTENSIONS "CUDA enabled") +ENDIF() + +# We want this to default to OFF for cache reasons, but if no +# host space is given, then activate serial +IF (KOKKOS_HAS_TRILINOS) + #However, Trilinos always wants Serial ON + SET(SERIAL_DEFAULT ON) +ELSEIF (KOKKOS_HAS_HOST) + SET(SERIAL_DEFAULT OFF) +ELSE() + SET(SERIAL_DEFAULT ON) + IF (NOT DEFINED Kokkos_ENABLE_SERIAL) + MESSAGE(STATUS "SERIAL backend is being turned on to ensure there is at least one Host space. To change this, you must enable another host execution space and configure with -DKokkos_ENABLE_SERIAL=OFF or change CMakeCache.txt") + ENDIF() +ENDIF() +KOKKOS_DEVICE_OPTION(SERIAL ${SERIAL_DEFAULT} HOST "Whether to build serial backend") + +KOKKOS_DEVICE_OPTION(HPX OFF HOST "Whether to build HPX backend (experimental)") diff --git a/lib/kokkos/cmake/kokkos_enable_options.cmake b/lib/kokkos/cmake/kokkos_enable_options.cmake new file mode 100644 index 0000000000..c0e49482b6 --- /dev/null +++ b/lib/kokkos/cmake/kokkos_enable_options.cmake @@ -0,0 +1,92 @@ +########################## NOTES ############################################### +# List the options for configuring kokkos using CMake method of doing it. +# These options then get mapped onto KOKKOS_SETTINGS environment variable by +# kokkos_settings.cmake. It is separate to allow other packages to override +# these variables (e.g., TriBITS). + +########################## AVAILABLE OPTIONS ################################### +# Use lists for documentation, verification, and programming convenience + + +FUNCTION(KOKKOS_ENABLE_OPTION SUFFIX DEFAULT DOCSTRING) + KOKKOS_OPTION(ENABLE_${SUFFIX} ${DEFAULT} BOOL ${DOCSTRING}) + STRING(TOUPPER ${SUFFIX} UC_NAME) + IF (KOKKOS_ENABLE_${UC_NAME}) + LIST(APPEND KOKKOS_ENABLED_OPTIONS ${UC_NAME}) + #I hate that CMake makes me do this + SET(KOKKOS_ENABLED_OPTIONS ${KOKKOS_ENABLED_OPTIONS} PARENT_SCOPE) + ENDIF() + SET(KOKKOS_ENABLE_${UC_NAME} ${KOKKOS_ENABLE_${UC_NAME}} PARENT_SCOPE) +ENDFUNCTION() + +# Certain defaults will depend on knowing the enabled devices +KOKKOS_CFG_DEPENDS(OPTIONS DEVICES) + +# Put a check in just in case people are using this option +KOKKOS_DEPRECATED_LIST(OPTIONS ENABLE) + +KOKKOS_ENABLE_OPTION(CUDA_RELOCATABLE_DEVICE_CODE OFF "Whether to enable relocatable device code (RDC) for CUDA") +KOKKOS_ENABLE_OPTION(CUDA_UVM OFF "Whether to use unified memory (UM) for CUDA by default") +KOKKOS_ENABLE_OPTION(CUDA_LDG_INTRINSIC OFF "Whether to use CUDA LDG intrinsics") +KOKKOS_ENABLE_OPTION(HPX_ASYNC_DISPATCH OFF "Whether HPX supports asynchronous dispatch") +KOKKOS_ENABLE_OPTION(TESTS OFF "Whether to build the unit tests") +STRING(TOUPPER "${CMAKE_BUILD_TYPE}" UPPERCASE_CMAKE_BUILD_TYPE) +IF(UPPERCASE_CMAKE_BUILD_TYPE STREQUAL "DEBUG") + KOKKOS_ENABLE_OPTION(DEBUG ON "Whether to activate extra debug features - may increase compile times") + KOKKOS_ENABLE_OPTION(DEBUG_DUALVIEW_MODIFY_CHECK ON "Debug check on dual views") +ELSE() + KOKKOS_ENABLE_OPTION(DEBUG OFF "Whether to activate extra debug features - may increase compile times") + KOKKOS_ENABLE_OPTION(DEBUG_DUALVIEW_MODIFY_CHECK OFF "Debug check on dual views") +ENDIF() +UNSET(_UPPERCASE_CMAKE_BUILD_TYPE) +KOKKOS_ENABLE_OPTION(LARGE_MEM_TESTS OFF "Whether to perform extra large memory tests") +KOKKOS_ENABLE_OPTION(DEBUG_BOUNDS_CHECK OFF "Whether to use bounds checking - will increase runtime") +KOKKOS_ENABLE_OPTION(COMPILER_WARNINGS OFF "Whether to print all compiler warnings") +KOKKOS_ENABLE_OPTION(PROFILING ON "Whether to create bindings for profiling tools") +KOKKOS_ENABLE_OPTION(PROFILING_LOAD_PRINT OFF "Whether to print information about which profiling tools got loaded") +KOKKOS_ENABLE_OPTION(AGGRESSIVE_VECTORIZATION OFF "Whether to aggressively vectorize loops") +KOKKOS_ENABLE_OPTION(DEPRECATED_CODE OFF "Whether to enable deprecated code") + +IF (KOKKOS_ENABLE_CUDA) + SET(KOKKOS_COMPILER_CUDA_VERSION "${KOKKOS_COMPILER_VERSION_MAJOR}${KOKKOS_COMPILER_VERSION_MINOR}") +ENDIF() + +IF (Trilinos_ENABLE_Kokkos AND TPL_ENABLE_CUDA AND DEFINED KOKKOS_COMPILER_CUDA_VERSION AND KOKKOS_COMPILER_CUDA_VERSION GREATER 70) + SET(LAMBDA_DEFAULT ON) +ELSE() + SET(LAMBDA_DEFAULT OFF) +ENDIF() +KOKKOS_ENABLE_OPTION(CUDA_LAMBDA ${LAMBDA_DEFAULT} "Whether to activate experimental lambda features") +IF (Trilinos_ENABLE_Kokkos) + SET(COMPLEX_ALIGN_DEFAULT OFF) +ELSE() + SET(COMPLEX_ALIGN_DEFAULT ON) +ENDIF() +KOKKOS_ENABLE_OPTION(COMPLEX_ALIGN ${COMPLEX_ALIGN_DEFAULT} "Whether to align Kokkos::complex to 2*alignof(RealType)") + +KOKKOS_ENABLE_OPTION(CUDA_CONSTEXPR OFF "Whether to activate experimental relaxed constexpr functions") + +FUNCTION(check_device_specific_options) + CMAKE_PARSE_ARGUMENTS(SOME "" "DEVICE" "OPTIONS" ${ARGN}) + IF(NOT KOKKOS_ENABLE_${SOME_DEVICE}) + FOREACH(OPTION ${SOME_OPTIONS}) + IF(CMAKE_VERSION VERSION_GREATER_EQUAL 3.14) + IF(NOT DEFINED CACHE{Kokkos_ENABLE_${OPTION}} OR NOT DEFINED CACHE{Kokkos_ENABLE_${SOME_DEVICE}}) + MESSAGE(FATAL_ERROR "Internal logic error: option '${OPTION}' or device '${SOME_DEVICE}' not recognized.") + ENDIF() + ENDIF() + IF(KOKKOS_ENABLE_${OPTION}) + MESSAGE(WARNING "Kokkos_ENABLE_${OPTION} is ON but ${SOME_DEVICE} backend is not enabled. Option will be ignored.") + UNSET(KOKKOS_ENABLE_${OPTION} PARENT_SCOPE) + ENDIF() + ENDFOREACH() + ENDIF() +ENDFUNCTION() + +CHECK_DEVICE_SPECIFIC_OPTIONS(DEVICE CUDA OPTIONS CUDA_UVM CUDA_RELOCATABLE_DEVICE_CODE CUDA_LAMBDA CUDA_CONSTEXPR CUDA_LDG_INTRINSIC) +CHECK_DEVICE_SPECIFIC_OPTIONS(DEVICE HPX OPTIONS HPX_ASYNC_DISPATCH) + +# Needed due to change from deprecated name to new header define name +IF (KOKKOS_ENABLE_AGGRESSIVE_VECTORIZATION) + SET(KOKKOS_OPT_RANGE_AGGRESSIVE_VECTORIZATION ON) +ENDIF() diff --git a/lib/kokkos/cmake/kokkos_functions.cmake b/lib/kokkos/cmake/kokkos_functions.cmake index 616618753b..3644c48ddd 100644 --- a/lib/kokkos/cmake/kokkos_functions.cmake +++ b/lib/kokkos/cmake/kokkos_functions.cmake @@ -1,345 +1,700 @@ ################################### FUNCTIONS ################################## # List of functions -# set_kokkos_cxx_compiler -# set_kokkos_cxx_standard -# set_kokkos_srcs - -#------------------------------------------------------------------------------- -# function(set_kokkos_cxx_compiler) -# Sets the following compiler variables that are analogous to the CMAKE_* -# versions. We add the ability to detect NVCC (really nvcc_wrapper). -# KOKKOS_CXX_COMPILER -# KOKKOS_CXX_COMPILER_ID -# KOKKOS_CXX_COMPILER_VERSION -# -# Inputs: -# KOKKOS_ENABLE_CUDA -# CMAKE_CXX_COMPILER -# CMAKE_CXX_COMPILER_ID -# CMAKE_CXX_COMPILER_VERSION -# -# Also verifies the compiler version meets the minimum required by Kokkos. -function(set_kokkos_cxx_compiler) - # Since CMake doesn't recognize the nvcc compiler until 3.8, we use our own - # version of the CMake variables and detect nvcc ourselves. Initially set to - # the CMake variable values. - set(INTERNAL_CXX_COMPILER ${CMAKE_CXX_COMPILER}) - set(INTERNAL_CXX_COMPILER_ID ${CMAKE_CXX_COMPILER_ID}) - set(INTERNAL_CXX_COMPILER_VERSION ${CMAKE_CXX_COMPILER_VERSION}) - - # Check if the compiler is nvcc (which really means nvcc_wrapper). - execute_process(COMMAND ${INTERNAL_CXX_COMPILER} --version - COMMAND grep nvcc - COMMAND wc -l - OUTPUT_VARIABLE INTERNAL_HAVE_COMPILER_NVCC - OUTPUT_STRIP_TRAILING_WHITESPACE) - - string(REGEX REPLACE "^ +" "" - INTERNAL_HAVE_COMPILER_NVCC ${INTERNAL_HAVE_COMPILER_NVCC}) - - if(INTERNAL_HAVE_COMPILER_NVCC) - # Set the compiler id to nvcc. We use the value used by CMake 3.8. - set(INTERNAL_CXX_COMPILER_ID NVIDIA) - - # Set nvcc's compiler version. - execute_process(COMMAND ${INTERNAL_CXX_COMPILER} --version - COMMAND grep release - OUTPUT_VARIABLE INTERNAL_CXX_COMPILER_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE) - - string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+$" - INTERNAL_CXX_COMPILER_VERSION ${INTERNAL_CXX_COMPILER_VERSION}) - endif() - - # Enforce the minimum compilers supported by Kokkos. - set(KOKKOS_MESSAGE_TEXT "Compiler not supported by Kokkos. Required compiler versions:") - set(KOKKOS_MESSAGE_TEXT "${KOKKOS_MESSAGE_TEXT}\n Clang 3.5.2 or higher") - set(KOKKOS_MESSAGE_TEXT "${KOKKOS_MESSAGE_TEXT}\n GCC 4.8.4 or higher") - set(KOKKOS_MESSAGE_TEXT "${KOKKOS_MESSAGE_TEXT}\n Intel 15.0.2 or higher") - set(KOKKOS_MESSAGE_TEXT "${KOKKOS_MESSAGE_TEXT}\n NVCC 7.0.28 or higher") - set(KOKKOS_MESSAGE_TEXT "${KOKKOS_MESSAGE_TEXT}\n PGI 17.1 or higher\n") - - if(INTERNAL_CXX_COMPILER_ID STREQUAL Clang) - if(INTERNAL_CXX_COMPILER_VERSION VERSION_LESS 3.5.2) - message(FATAL_ERROR "${KOKKOS_MESSAGE_TEXT}") - endif() - elseif(INTERNAL_CXX_COMPILER_ID STREQUAL GNU) - if(INTERNAL_CXX_COMPILER_VERSION VERSION_LESS 4.8.4) - message(FATAL_ERROR "${KOKKOS_MESSAGE_TEXT}") - endif() - elseif(INTERNAL_CXX_COMPILER_ID STREQUAL Intel) - if(INTERNAL_CXX_COMPILER_VERSION VERSION_LESS 15.0.2) - message(FATAL_ERROR "${KOKKOS_MESSAGE_TEXT}") - endif() - elseif(INTERNAL_CXX_COMPILER_ID STREQUAL NVIDIA) - if(INTERNAL_CXX_COMPILER_VERSION VERSION_LESS 7.0.28) - message(FATAL_ERROR "${KOKKOS_MESSAGE_TEXT}") - endif() - elseif(INTERNAL_CXX_COMPILER_ID STREQUAL PGI) - if(INTERNAL_CXX_COMPILER_VERSION VERSION_LESS 17.1) - message(FATAL_ERROR "${KOKKOS_MESSAGE_TEXT}") - endif() - endif() - - # Enforce that extensions are turned off for nvcc_wrapper. - if(INTERNAL_CXX_COMPILER_ID STREQUAL NVIDIA) - if(DEFINED CMAKE_CXX_EXTENSIONS AND CMAKE_CXX_EXTENSIONS STREQUAL ON) - message(FATAL_ERROR "NVCC doesn't support C++ extensions. Set CMAKE_CXX_EXTENSIONS to OFF in your CMakeLists.txt.") - endif() - endif() - - if(KOKKOS_ENABLE_CUDA) - # Enforce that the compiler can compile CUDA code. - if(INTERNAL_CXX_COMPILER_ID STREQUAL Clang) - if(INTERNAL_CXX_COMPILER_VERSION VERSION_LESS 4.0.0) - message(FATAL_ERROR "Compiling CUDA code directly with Clang requires version 4.0.0 or higher.") - endif() - elseif(NOT INTERNAL_CXX_COMPILER_ID STREQUAL NVIDIA) - message(FATAL_ERROR "Invalid compiler for CUDA. The compiler must be nvcc_wrapper or Clang, but compiler ID was ${INTERNAL_CXX_COMPILER_ID}") - endif() - endif() - - set(KOKKOS_CXX_COMPILER ${INTERNAL_CXX_COMPILER} PARENT_SCOPE) - set(KOKKOS_CXX_COMPILER_ID ${INTERNAL_CXX_COMPILER_ID} PARENT_SCOPE) - set(KOKKOS_CXX_COMPILER_VERSION ${INTERNAL_CXX_COMPILER_VERSION} PARENT_SCOPE) -endfunction() - -#------------------------------------------------------------------------------- -# function(set_kokkos_cxx_standard) -# Transitively enforces that the appropriate CXX standard compile flags (C++11 -# or above) are added to targets that use the Kokkos library. Compile features -# are used if possible. Otherwise, the appropriate flags are added to -# KOKKOS_CXX_FLAGS. Values set by the user to CMAKE_CXX_STANDARD and -# CMAKE_CXX_EXTENSIONS are honored. -# -# Outputs: -# KOKKOS_CXX11_FEATURES -# KOKKOS_CXX_FLAGS -# -# Inputs: -# KOKKOS_CXX_COMPILER -# KOKKOS_CXX_COMPILER_ID -# KOKKOS_CXX_COMPILER_VERSION -# -function(set_kokkos_cxx_standard) - # The following table lists the versions of CMake that supports CXX_STANDARD - # and the CXX compile features for different compilers. The versions are - # based on CMake documentation, looking at CMake code, and verifying by - # testing with specific CMake versions. - # - # COMPILER CXX_STANDARD Compile Features - # --------------------------------------------------------------- - # Clang 3.1 3.1 - # GNU 3.1 3.2 - # AppleClang 3.2 3.2 - # Intel 3.6 3.6 - # Cray No No - # PGI No No - # XL No No - # - # For compiling CUDA code using nvcc_wrapper, we will use the host compiler's - # flags for turning on C++11. Since for compiler ID and versioning purposes - # CMake recognizes the host compiler when calling nvcc_wrapper, this just - # works. Both NVCC and nvcc_wrapper only recognize '-std=c++11' which means - # that we can only use host compilers for CUDA builds that use those flags. - # It also means that extensions (gnu++11) can't be turned on for CUDA builds. - - # Check if we can use compile features. - if(NOT KOKKOS_CXX_COMPILER_ID STREQUAL NVIDIA) - if(CMAKE_CXX_COMPILER_ID STREQUAL Clang) - if(NOT CMAKE_VERSION VERSION_LESS 3.1) - set(INTERNAL_USE_COMPILE_FEATURES ON) - endif() - elseif(CMAKE_CXX_COMPILER_ID STREQUAL AppleClang OR CMAKE_CXX_COMPILER_ID STREQUAL GNU) - if(NOT CMAKE_VERSION VERSION_LESS 3.2) - set(INTERNAL_USE_COMPILE_FEATURES ON) - endif() - elseif(CMAKE_CXX_COMPILER_ID STREQUAL Intel) - if(NOT CMAKE_VERSION VERSION_LESS 3.6) - set(INTERNAL_USE_COMPILE_FEATURES ON) - endif() - endif() - endif() - - if(INTERNAL_USE_COMPILE_FEATURES) - # Use the compile features aspect of CMake to transitively cause C++ flags - # to populate to user code. - - # I'm using a hack by requiring features that I know force the lowest version - # of the compilers we want to support. Clang 3.3 and later support all of - # the C++11 standard. With CMake 3.8 and higher, we could switch to using - # cxx_std_11. - set(KOKKOS_CXX11_FEATURES - cxx_nonstatic_member_init # Forces GCC 4.7 or later and Intel 14.0 or later. - PARENT_SCOPE - ) - else() - # CXX compile features are not yet implemented for this combination of - # compiler and version of CMake. - - if(CMAKE_CXX_COMPILER_ID STREQUAL AppleClang) - # Versions of CMAKE before 3.2 don't support CXX_STANDARD or C++ compile - # features for the AppleClang compiler. Set compiler flags transitively - # here such that they trickle down to a call to target_compile_options(). - - # The following two blocks of code were copied from - # /Modules/Compiler/AppleClang-CXX.cmake from CMake 3.7.2 and then - # modified. - if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.0) - set(INTERNAL_CXX11_STANDARD_COMPILE_OPTION "-std=c++11") - set(INTERNAL_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11") - endif() - - if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.1) - set(INTERNAL_CXX14_STANDARD_COMPILE_OPTION "-std=c++14") - set(INTERNAL_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++14") - elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1) - # AppleClang 5.0 knows this flag, but does not set a __cplusplus macro - # greater than 201103L. - set(INTERNAL_CXX14_STANDARD_COMPILE_OPTION "-std=c++1y") - set(INTERNAL_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++1y") - endif() - elseif(CMAKE_CXX_COMPILER_ID STREQUAL Intel) - # Versions of CMAKE before 3.6 don't support CXX_STANDARD or C++ compile - # features for the Intel compiler. Set compiler flags transitively here - # such that they trickle down to a call to target_compile_options(). - - # The following three blocks of code were copied from - # /Modules/Compiler/Intel-CXX.cmake from CMake 3.7.2 and then modified. - if("x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC") - set(_std -Qstd) - set(_ext c++) - else() - set(_std -std) - set(_ext gnu++) - endif() - - if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0.2) - set(INTERNAL_CXX14_STANDARD_COMPILE_OPTION "${_std}=c++14") - # TODO: There is no gnu++14 value supported; figure out what to do. - set(INTERNAL_CXX14_EXTENSION_COMPILE_OPTION "${_std}=c++14") - elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0.0) - set(INTERNAL_CXX14_STANDARD_COMPILE_OPTION "${_std}=c++1y") - # TODO: There is no gnu++14 value supported; figure out what to do. - set(INTERNAL_CXX14_EXTENSION_COMPILE_OPTION "${_std}=c++1y") - endif() - - if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.0) - set(INTERNAL_CXX11_STANDARD_COMPILE_OPTION "${_std}=c++11") - set(INTERNAL_CXX11_EXTENSION_COMPILE_OPTION "${_std}=${_ext}11") - elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.1) - set(INTERNAL_CXX11_STANDARD_COMPILE_OPTION "${_std}=c++0x") - set(INTERNAL_CXX11_EXTENSION_COMPILE_OPTION "${_std}=${_ext}0x") - endif() - elseif(CMAKE_CXX_COMPILER_ID STREQUAL Cray) - # CMAKE doesn't support CXX_STANDARD or C++ compile features for the Cray - # compiler. Set compiler options transitively here such that they trickle - # down to a call to target_compile_options(). - set(INTERNAL_CXX11_STANDARD_COMPILE_OPTION "-hstd=c++11") - set(INTERNAL_CXX11_EXTENSION_COMPILE_OPTION "-hstd=c++11") - set(INTERNAL_CXX14_STANDARD_COMPILE_OPTION "-hstd=c++11") - set(INTERNAL_CXX14_EXTENSION_COMPILE_OPTION "-hstd=c++11") - elseif(CMAKE_CXX_COMPILER_ID STREQUAL PGI) - # CMAKE doesn't support CXX_STANDARD or C++ compile features for the PGI - # compiler. Set compiler options transitively here such that they trickle - # down to a call to target_compile_options(). - set(INTERNAL_CXX11_STANDARD_COMPILE_OPTION "--c++11") - set(INTERNAL_CXX11_EXTENSION_COMPILE_OPTION "--c++11") - set(INTERNAL_CXX14_STANDARD_COMPILE_OPTION "--c++11") - set(INTERNAL_CXX14_EXTENSION_COMPILE_OPTION "--c++11") - elseif(CMAKE_CXX_COMPILER_ID STREQUAL XL) - # CMAKE doesn't support CXX_STANDARD or C++ compile features for the XL - # compiler. Set compiler options transitively here such that they trickle - # down to a call to target_compile_options(). - set(INTERNAL_CXX11_STANDARD_COMPILE_OPTION "-std=c++11") - set(INTERNAL_CXX11_EXTENSION_COMPILE_OPTION "-std=c++11") - set(INTERNAL_CXX14_STANDARD_COMPILE_OPTION "-std=c++11") - set(INTERNAL_CXX14_EXTENSION_COMPILE_OPTION "-std=c++11") - else() - # Assume GNU. CMAKE_CXX_STANDARD is handled correctly by CMake 3.1 and - # above for this compiler. If the user explicitly requests a C++ - # standard, CMake takes care of it. If not, transitively require C++11. - if(NOT CMAKE_CXX_STANDARD) - set(INTERNAL_CXX11_STANDARD_COMPILE_OPTION ${CMAKE_CXX11_STANDARD_COMPILE_OPTION}) - set(INTERNAL_CXX11_EXTENSION_COMPILE_OPTION ${CMAKE_CXX11_EXTENSION_COMPILE_OPTION}) - endif() - endif() - - # Set the C++ standard info for Kokkos respecting user set values for - # CMAKE_CXX_STANDARD and CMAKE_CXX_EXTENSIONS. - # Only use cxx extension if explicitly requested - if(CMAKE_CXX_STANDARD EQUAL 14) - if(DEFINED CMAKE_CXX_EXTENSIONS AND CMAKE_CXX_EXTENSIONS STREQUAL ON) - set(INTERNAL_CXX_FLAGS ${INTERNAL_CXX14_EXTENSION_COMPILE_OPTION}) - else() - set(INTERNAL_CXX_FLAGS ${INTERNAL_CXX14_STANDARD_COMPILE_OPTION}) - endif() - elseif(CMAKE_CXX_STANDARD EQUAL 11) - if(DEFINED CMAKE_CXX_EXTENSIONS AND CMAKE_CXX_EXTENSIONS STREQUAL ON) - set(INTERNAL_CXX_FLAGS ${INTERNAL_CXX11_EXTENSION_COMPILE_OPTION}) - else() - set(INTERNAL_CXX_FLAGS ${INTERNAL_CXX11_STANDARD_COMPILE_OPTION}) - endif() - else() - # The user didn't explicitly request a standard, transitively require - # C++11 respecting CMAKE_CXX_EXTENSIONS. - if(DEFINED CMAKE_CXX_EXTENSIONS AND CMAKE_CXX_EXTENSIONS STREQUAL ON) - set(INTERNAL_CXX_FLAGS ${INTERNAL_CXX11_EXTENSION_COMPILE_OPTION}) - else() - set(INTERNAL_CXX_FLAGS ${INTERNAL_CXX11_STANDARD_COMPILE_OPTION}) - endif() - endif() - - set(KOKKOS_CXX_FLAGS ${INTERNAL_CXX_FLAGS} PARENT_SCOPE) - endif() -endfunction() - - -#------------------------------------------------------------------------------- -# function(set_kokkos_sources) -# Takes a list of sources for kokkos (e.g., KOKKOS_SRC from Makefile.kokkos and -# put it into kokkos_generated_settings.cmake) and sorts the files into the subpackages or -# separate_libraries. This is core and containers (algorithms is pure header -# files). -# -# Inputs: -# KOKKOS_SRC +# kokkos_option + +# Validate options are given with correct case and define an internal +# upper-case version for use within + # -# Outputs: -# KOKKOS_CORE_SRCS -# KOKKOS_CONTAINERS_SRCS -# -function(set_kokkos_srcs) - set(opts ) # no-value args - set(oneValArgs ) - set(multValArgs KOKKOS_SRC) # e.g., lists - cmake_parse_arguments(IN "${opts}" "${oneValArgs}" "${multValArgs}" ${ARGN}) - - foreach(sfile ${IN_KOKKOS_SRC}) - string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" stripfile "${sfile}") - string(REPLACE "/" ";" striplist "${stripfile}") - list(GET striplist 0 firstdir) - if(${firstdir} STREQUAL "core") - list(APPEND KOKKOS_CORE_SRCS ${sfile}) - else() - list(APPEND KOKKOS_CONTAINERS_SRCS ${sfile}) - endif() - endforeach() - set(KOKKOS_CORE_SRCS ${KOKKOS_CORE_SRCS} PARENT_SCOPE) - set(KOKKOS_CONTAINERS_SRCS ${KOKKOS_CONTAINERS_SRCS} PARENT_SCOPE) - return() -endfunction() - -# Setting a default value if it is not already set -macro(set_kokkos_default_default VARIABLE DEFAULT) - IF( "${KOKKOS_INTERNAL_ENABLE_${VARIABLE}_DEFAULT}" STREQUAL "" ) - IF( "${KOKKOS_ENABLE_${VARIABLE}}" STREQUAL "" ) - set(KOKKOS_INTERNAL_ENABLE_${VARIABLE}_DEFAULT ${DEFAULT}) - # MESSAGE(WARNING "Set: KOKKOS_INTERNAL_ENABLE_${VARIABLE}_DEFAULT to ${KOKKOS_INTERNAL_ENABLE_${VARIABLE}_DEFAULT}") +# +# @FUNCTION: kokkos_deprecated_list +# +# Function that checks if a deprecated list option like Kokkos_ARCH was given. +# This prints an error and prevents configure from completing. +# It attempts to print a helpful message about updating the options for the new CMake. +# Kokkos_${SUFFIX} is the name of the option (like Kokkos_ARCH) being checked. +# Kokkos_${PREFIX}_X is the name of new option to be defined from a list X,Y,Z,... +FUNCTION(kokkos_deprecated_list SUFFIX PREFIX) + SET(CAMEL_NAME Kokkos_${SUFFIX}) + STRING(TOUPPER ${CAMEL_NAME} UC_NAME) + + #I don't love doing it this way but better to be safe + FOREACH(opt ${KOKKOS_GIVEN_VARIABLES}) + STRING(TOUPPER ${opt} OPT_UC) + IF ("${OPT_UC}" STREQUAL "${UC_NAME}") + STRING(REPLACE "," ";" optlist "${${opt}}") + SET(ERROR_MSG "Given deprecated option list ${opt}. This must now be given as separate -D options, which assuming you spelled options correctly would be:") + FOREACH(entry ${optlist}) + STRING(TOUPPER ${entry} ENTRY_UC) + STRING(APPEND ERROR_MSG "\n -DKokkos_${PREFIX}_${ENTRY_UC}=ON") + ENDFOREACH() + STRING(APPEND ERROR_MSG "\nRemove CMakeCache.txt and re-run. For a list of valid options, refer to BUILD.md or even look at CMakeCache.txt (before deleting it).") + IF (KOKKOS_HAS_TRILINOS) + MESSAGE(WARNING ${ERROR_MSG}) + FOREACH(entry ${optlist}) + STRING(TOUPPER ${entry} ENTRY_UC) + SET(${CAMEL_NAME}_${ENTRY_UC} ON CACHE BOOL "Deprecated Trilinos translation") + ENDFOREACH() + UNSET(${opt} CACHE) + ELSE() + MESSAGE(SEND_ERROR ${ERROR_MSG}) + ENDIF() + ENDIF() + ENDFOREACH() +ENDFUNCTION() + +FUNCTION(kokkos_option CAMEL_SUFFIX DEFAULT TYPE DOCSTRING) + SET(CAMEL_NAME Kokkos_${CAMEL_SUFFIX}) + STRING(TOUPPER ${CAMEL_NAME} UC_NAME) + + # Make sure this appears in the cache with the appropriate DOCSTRING + SET(${CAMEL_NAME} ${DEFAULT} CACHE ${TYPE} ${DOCSTRING}) + + #I don't love doing it this way because it's N^2 in number options, but cest la vie + FOREACH(opt ${KOKKOS_GIVEN_VARIABLES}) + STRING(TOUPPER ${opt} OPT_UC) + IF ("${OPT_UC}" STREQUAL "${UC_NAME}") + IF (NOT "${opt}" STREQUAL "${CAMEL_NAME}") + IF (KOKKOS_HAS_TRILINOS) + #Allow this for now if Trilinos... we need to bootstrap our way to integration + MESSAGE(WARNING "Deprecated option ${opt} found - please change spelling to ${CAMEL_NAME}") + SET(${CAMEL_NAME} "${${opt}}" CACHE ${TYPE} ${DOCSTRING} FORCE) + UNSET(${opt} CACHE) + ELSE() + MESSAGE(FATAL_ERROR "Matching option found for ${CAMEL_NAME} with the wrong case ${opt}. Please delete your CMakeCache.txt and change option to -D${CAMEL_NAME}=${${opt}}. This is now enforced to avoid hard-to-debug CMake cache inconsistencies.") + ENDIF() + ENDIF() + ENDIF() + ENDFOREACH() + + #okay, great, we passed the validation test - use the default + IF (DEFINED ${CAMEL_NAME}) + SET(${UC_NAME} ${${CAMEL_NAME}} PARENT_SCOPE) + ELSE() + SET(${UC_NAME} ${DEFAULT} PARENT_SCOPE) + ENDIF() + +ENDFUNCTION() + +FUNCTION(kokkos_append_config_line LINE) + GLOBAL_APPEND(KOKKOS_TPL_EXPORTS "${LINE}") +ENDFUNCTION() + +MACRO(kokkos_export_cmake_tpl NAME) + #CMake TPLs are located with a call to find_package + #find_package locates XConfig.cmake files through + #X_DIR or X_ROOT variables set prior to calling find_package + + #If Kokkos was configured to find the TPL through a _DIR variable + #make sure thar DIR variable is available to downstream packages + IF (DEFINED ${NAME}_DIR) + #The downstream project may override the TPL location that Kokkos used + #Check if the downstream project chose its own TPL location + #If not, make the Kokkos found location available + KOKKOS_APPEND_CONFIG_LINE("IF(NOT DEFINED ${NAME}_DIR)") + KOKKOS_APPEND_CONFIG_LINE(" SET(${NAME}_DIR ${${NAME}_DIR})") + KOKKOS_APPEND_CONFIG_LINE("ENDIF()") + ENDIF() + + IF (DEFINED ${NAME}_ROOT) + #The downstream project may override the TPL location that Kokkos used + #Check if the downstream project chose its own TPL location + #If not, make the Kokkos found location available + KOKKOS_APPEND_CONFIG_LINE("IF(NOT DEFINED ${NAME}_ROOT)") + KOKKOS_APPEND_CONFIG_LINE(" SET(${NAME}_ROOT ${${NAME}_ROOT})") + KOKKOS_APPEND_CONFIG_LINE("ENDIF()") + ENDIF() + KOKKOS_APPEND_CONFIG_LINE("FIND_DEPENDENCY(${NAME})") +ENDMACRO() + +MACRO(kokkos_export_imported_tpl NAME) + IF (NOT KOKKOS_HAS_TRILINOS) + GET_TARGET_PROPERTY(LIB_TYPE ${NAME} TYPE) + IF (${LIB_TYPE} STREQUAL "INTERFACE_LIBRARY") + # This is not an imported target + # This an interface library that we created + INSTALL( + TARGETS ${NAME} + EXPORT KokkosTargets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) ELSE() - set(KOKKOS_INTERNAL_ENABLE_${VARIABLE}_DEFAULT ${KOKKOS_ENABLE_${VARIABLE}}) - # MESSAGE(WARNING "Set: KOKKOS_INTERNAL_ENABLE_${VARIABLE}_DEFAULT to ${KOKKOS_INTERNAL_ENABLE_${VARIABLE}_DEFAULT}") + #make sure this also gets "exported" in the config file + KOKKOS_APPEND_CONFIG_LINE("IF(NOT TARGET ${NAME})") + KOKKOS_APPEND_CONFIG_LINE("ADD_LIBRARY(${NAME} UNKNOWN IMPORTED)") + KOKKOS_APPEND_CONFIG_LINE("SET_TARGET_PROPERTIES(${NAME} PROPERTIES") + + GET_TARGET_PROPERTY(TPL_LIBRARY ${NAME} IMPORTED_LOCATION) + IF(TPL_LIBRARY) + KOKKOS_APPEND_CONFIG_LINE("IMPORTED_LOCATION ${TPL_LIBRARY}") + ENDIF() + + GET_TARGET_PROPERTY(TPL_INCLUDES ${NAME} INTERFACE_INCLUDE_DIRECTORIES) + IF(TPL_INCLUDES) + KOKKOS_APPEND_CONFIG_LINE("INTERFACE_INCLUDE_DIRECTORIES ${TPL_INCLUDES}") + ENDIF() + + GET_TARGET_PROPERTY(TPL_COMPILE_OPTIONS ${NAME} INTERFACE_COMPILE_OPTIONS) + IF(TPL_COMPILE_OPTIONS) + KOKKOS_APPEND_CONFIG_LINE("INTERFACE_COMPILE_OPTIONS ${TPL_COMPILE_OPTIONS}") + ENDIF() + + SET(TPL_LINK_OPTIONS) + IF(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.13.0") + GET_TARGET_PROPERTY(TPL_LINK_OPTIONS ${NAME} INTERFACE_LINK_OPTIONS) + ENDIF() + IF(TPL_LINK_OPTIONS) + KOKKOS_APPEND_CONFIG_LINE("INTERFACE_LINK_OPTIONS ${TPL_LINK_OPTIONS}") + ENDIF() + + GET_TARGET_PROPERTY(TPL_LINK_LIBRARIES ${NAME} INTERFACE_LINK_LIBRARIES) + IF(TPL_LINK_LIBRARIES) + KOKKOS_APPEND_CONFIG_LINE("INTERFACE_LINK_LIBRARIES ${TPL_LINK_LIBRARIES}") + ENDIF() + KOKKOS_APPEND_CONFIG_LINE(")") + KOKKOS_APPEND_CONFIG_LINE("ENDIF()") ENDIF() ENDIF() - UNSET(KOKKOS_ENABLE_${VARIABLE} CACHE) -endmacro() +ENDMACRO() + + +# +# @MACRO: KOKKOS_IMPORT_TPL() +# +# Function that checks if a third-party library (TPL) has been enabled and calls `find_package` +# to create an imported target encapsulating all the flags and libraries +# needed to use the TPL +# +# Usage:: +# +# KOKKOS_IMPORT_TPL( +# +# NO_EXPORT +# INTERFACE +# +# ``NO_EXPORT`` +# +# If specified, this TPL will not be added to KokkosConfig.cmake as an export +# +# ``INTERFACE`` +# +# If specified, this TPL will build an INTERFACE library rather than an +# IMPORTED target +MACRO(kokkos_import_tpl NAME) + CMAKE_PARSE_ARGUMENTS(TPL + "NO_EXPORT;INTERFACE" + "" + "" + ${ARGN}) + IF (TPL_INTERFACE) + SET(TPL_IMPORTED_NAME ${NAME}) + ELSE() + SET(TPL_IMPORTED_NAME Kokkos::${NAME}) + ENDIF() + + # Even though this policy gets set in the top-level CMakeLists.txt, + # I have still been getting errors about ROOT variables being ignored + # I'm not sure if this is a scope issue - but make sure + # the policy is set before we do any find_package calls + IF(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.12.0") + CMAKE_POLICY(SET CMP0074 NEW) + ENDIF() + + IF (KOKKOS_ENABLE_${NAME}) + #Tack on a TPL here to make sure we avoid using anyone else's find + FIND_PACKAGE(TPL${NAME} REQUIRED MODULE) + IF(NOT TARGET ${TPL_IMPORTED_NAME}) + MESSAGE(FATAL_ERROR "Find module succeeded for ${NAME}, but did not produce valid target ${TPL_IMPORTED_NAME}") + ENDIF() + IF(NOT TPL_NO_EXPORT) + KOKKOS_EXPORT_IMPORTED_TPL(${TPL_IMPORTED_NAME}) + ENDIF() + LIST(APPEND KOKKOS_ENABLED_TPLS ${NAME}) + ENDIF() +ENDMACRO(kokkos_import_tpl) + +MACRO(kokkos_import_cmake_tpl MODULE_NAME) + kokkos_import_tpl(${MODULE_NAME} ${ARGN} NO_EXPORT) + CMAKE_PARSE_ARGUMENTS(TPL + "NO_EXPORT" + "OPTION_NAME" + "" + ${ARGN}) + + IF (NOT TPL_OPTION_NAME) + SET(TPL_OPTION_NAME ${MODULE_NAME}) + ENDIF() + + IF (NOT TPL_NO_EXPORT) + KOKKOS_EXPORT_CMAKE_TPL(${MODULE_NAME}) + ENDIF() +ENDMACRO() + +# +# @MACRO: KOKKOS_CREATE_IMPORTED_TPL() +# +# Function that creates an imported target encapsulating all the flags +# and libraries needed to use the TPL +# +# Usage:: +# +# KOKKOS_CREATE_IMPORTED_TPL( +# +# INTERFACE +# LIBRARY +# LINK_LIBRARIES ... +# COMPILE_OPTIONS ... +# LINK_OPTIONS ... +# +# ``INTERFACE`` +# +# If specified, this TPL will build an INTERFACE library rather than an +# IMPORTED target +# +# ``LIBRARY `` +# +# If specified, this gives the IMPORTED_LOCATION of the library. +# +# ``LINK_LIBRARIES ...`` +# +# If specified, this gives a list of dependent libraries that also +# need to be linked against. Each entry can be a library path or +# the name of a valid CMake target. +# +# ``INCLUDES ...`` +# +# If specified, this gives a list of directories that must be added +# to the include path for using this library. +# +# ``COMPILE_OPTIONS ...`` +# +# If specified, this gives a list of compiler flags that must be used +# for using this library. +# +# ``LINK_OPTIONS ...`` +# +# If specified, this gives a list of linker flags that must be used +# for using this library. +MACRO(kokkos_create_imported_tpl NAME) + CMAKE_PARSE_ARGUMENTS(TPL + "INTERFACE" + "LIBRARY" + "LINK_LIBRARIES;INCLUDES;COMPILE_OPTIONS;LINK_OPTIONS" + ${ARGN}) + + + IF (KOKKOS_HAS_TRILINOS) + #TODO: we need to set a bunch of cache variables here + ELSEIF (TPL_INTERFACE) + ADD_LIBRARY(${NAME} INTERFACE) + #Give this an importy-looking name + ADD_LIBRARY(Kokkos::${NAME} ALIAS ${NAME}) + IF (TPL_LIBRARY) + MESSAGE(SEND_ERROR "TPL Interface library ${NAME} should not have an IMPORTED_LOCATION") + ENDIF() + #Things have to go in quoted in case we have multiple list entries + IF(TPL_LINK_LIBRARIES) + TARGET_LINK_LIBRARIES(${NAME} INTERFACE ${TPL_LINK_LIBRARIES}) + ENDIF() + IF(TPL_INCLUDES) + TARGET_INCLUDE_DIRECTORIES(${NAME} INTERFACE ${TPL_INCLUDES}) + ENDIF() + IF(TPL_COMPILE_OPTIONS) + TARGET_COMPILE_OPTIONS(${NAME} INTERFACE ${TPL_COMPILE_OPTIONS}) + ENDIF() + IF(TPL_LINK_OPTIONS) + TARGET_LINK_LIBRARIES(${NAME} INTERFACE ${TPL_LINK_OPTIONS}) + ENDIF() + ELSE() + ADD_LIBRARY(${NAME} UNKNOWN IMPORTED) + IF(TPL_LIBRARY) + SET_TARGET_PROPERTIES(${NAME} PROPERTIES + IMPORTED_LOCATION ${TPL_LIBRARY}) + ENDIF() + #Things have to go in quoted in case we have multiple list entries + IF(TPL_LINK_LIBRARIES) + SET_TARGET_PROPERTIES(${NAME} PROPERTIES + INTERFACE_LINK_LIBRARIES "${TPL_LINK_LIBRARIES}") + ENDIF() + IF(TPL_INCLUDES) + SET_TARGET_PROPERTIES(${NAME} PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${TPL_INCLUDES}") + ENDIF() + IF(TPL_COMPILE_OPTIONS) + SET_TARGET_PROPERTIES(${NAME} PROPERTIES + INTERFACE_COMPILE_OPTIONS "${TPL_COMPILE_OPTIONS}") + ENDIF() + IF(TPL_LINK_OPTIONS) + SET_TARGET_PROPERTIES(${NAME} PROPERTIES + INTERFACE_LINK_LIBRARIES "${TPL_LINK_OPTIONS}") + ENDIF() + ENDIF() +ENDMACRO() + +# +# @MACRO: KOKKOS_FIND_HEADER +# +# Function that finds a particular header. This searches custom paths +# or default system paths depending on options. In constrast to CMake +# default, custom paths are prioritized over system paths. The searched +# order is: +# 1. _ROOT variable +# 2. Kokkos__DIR variable +# 3. Locations in the PATHS option +# 4. Default system paths, if allowed. +# +# Default system paths are allowed if none of options (1)-(3) are specified +# or if default paths are specifically allowed via ALLOW_SYSTEM_PATH_FALLBACK +# +# Usage:: +# +# KOKKOS_FIND_HEADER( +# +#
    +# +# [ALLOW_SYSTEM_PATH_FALLBACK] +# [PATHS path1 [path2 ...]] +# ) +# +# ```` +# +# The variable to define with the success or failure of the find +# +# ``
    `` +# +# The name of the header to find +# +# ```` +# +# The name of the TPL the header corresponds to +# +# ``[ALLOW_SYSTEM_PATH_FALLBACK]`` +# +# If custom paths are given and the header is not found +# should we be allowed to search default system paths +# or error out if not found in given paths +# +# ``[PATHS path1 [path2 ...]]`` +# +# Custom paths to search for the header +# +MACRO(kokkos_find_header VAR_NAME HEADER TPL_NAME) + CMAKE_PARSE_ARGUMENTS(TPL + "ALLOW_SYSTEM_PATH_FALLBACK" + "" + "PATHS" + ${ARGN}) + + SET(${HEADER}_FOUND FALSE) + SET(HAVE_CUSTOM_PATHS FALSE) + IF(NOT ${HEADER}_FOUND AND DEFINED ${TPL_NAME}_ROOT) + #ONLY look in the root directory + FIND_PATH(${VAR_NAME} ${HEADER} PATHS ${${TPL_NAME}_ROOT}/include NO_DEFAULT_PATH) + SET(HAVE_CUSTOM_PATHS TRUE) + ENDIF() + + IF(NOT ${HEADER}_FOUND AND DEFINED KOKKOS_${TPL_NAME}_DIR) + #ONLY look in the root directory + FIND_PATH(${VAR_NAME} ${HEADER} PATHS ${KOKKOS_${TPL_NAME}_DIR}/include NO_DEFAULT_PATH) + SET(HAVE_CUSTOM_PATHS TRUE) + ENDIF() + + IF (NOT ${HEADER}_FOUND AND TPL_PATHS) + #we got custom paths + #ONLY look in these paths and nowhere else + FIND_PATH(${VAR_NAME} ${HEADER} PATHS ${TPL_PATHS} NO_DEFAULT_PATH) + SET(HAVE_CUSTOM_PATHS TRUE) + ENDIF() + + IF (NOT HAVE_CUSTOM_PATHS OR TPL_ALLOW_SYSTEM_PATH_FALLBACK) + #Now go ahead and look in system paths + IF (NOT ${HEADER}_FOUND) + FIND_PATH(${VAR_NAME} ${HEADER}) + ENDIF() + ENDIF() +ENDMACRO() + +# +# @MACRO: KOKKOS_FIND_LIBRARY +# +# Function that find a particular library. This searches custom paths +# or default system paths depending on options. In constrast to CMake +# default, custom paths are prioritized over system paths. The search +# order is: +# 1. _ROOT variable +# 2. Kokkos__DIR variable +# 3. Locations in the PATHS option +# 4. Default system paths, if allowed. +# +# Default system paths are allowed if none of options (1)-(3) are specified +# or if default paths are specifically allowed via ALLOW_SYSTEM_PATH_FALLBACK +# +# Usage:: +# +# KOKKOS_FIND_LIBRARY( +# +#
    +# +# [ALLOW_SYSTEM_PATH_FALLBACK] +# [PATHS path1 [path2 ...]] +# ) +# +# ```` +# +# The variable to define with the success or failure of the find +# +# ```` +# +# The name of the library to find (NOT prefixed with -l) +# +# ```` +# +# The name of the TPL the library corresponds to +# +# ``ALLOW_SYSTEM_PATH_FALLBACK`` +# +# If custom paths are given and the library is not found +# should we be allowed to search default system paths +# or error out if not found in given paths +# +# ``PATHS`` +# +# Custom paths to search for the library +# +MACRO(kokkos_find_library VAR_NAME LIB TPL_NAME) + CMAKE_PARSE_ARGUMENTS(TPL + "ALLOW_SYSTEM_PATH_FALLBACK" + "" + "PATHS" + ${ARGN}) + + SET(${LIB}_FOUND FALSE) + SET(HAVE_CUSTOM_PATHS FALSE) + IF(NOT ${LIB}_FOUND AND DEFINED ${TPL_NAME}_ROOT) + FIND_LIBRARY(${VAR_NAME} ${LIB} PATHS ${${TPL_NAME}_ROOT}/lib ${${TPL_NAME}_ROOT}/lib64 NO_DEFAULT_PATH) + SET(HAVE_CUSTOM_PATHS TRUE) + ENDIF() + + IF(NOT ${LIB}_FOUND AND DEFINED KOKKOS_${TPL_NAME}_DIR) + #we got root paths, only look in these paths and nowhere else + FIND_LIBRARY(${VAR_NAME} ${LIB} PATHS ${KOKKOS_${TPL_NAME}_DIR}/lib ${KOKKOS_${TPL_NAME}_DIR}/lib64 NO_DEFAULT_PATH) + SET(HAVE_CUSTOM_PATHS TRUE) + ENDIF() + + IF (NOT ${LIB}_FOUND AND TPL_PATHS) + #we got custom paths, only look in these paths and nowhere else + FIND_LIBRARY(${VAR_NAME} ${LIB} PATHS ${TPL_PATHS} NO_DEFAULT_PATH) + SET(HAVE_CUSTOM_PATHS TRUE) + ENDIF() + + + IF (NOT HAVE_CUSTOM_PATHS OR TPL_ALLOW_SYSTEM_PATH_FALLBACK) + IF (NOT ${LIB}_FOUND) + #Now go ahead and look in system paths + FIND_LIBRARY(${VAR_NAME} ${LIB}) + ENDIF() + ENDIF() +ENDMACRO() + +# +# @MACRO: KOKKOS_FIND_IMPORTED +# +# Function that finds all libraries and headers needed for the tpl +# and creates an imported target encapsulating all the flags and libraries +# +# Usage:: +# +# KOKKOS_FIND_IMPORTED( +# +# INTERFACE +# ALLOW_SYSTEM_PATH_FALLBACK +# LIBRARY +# LINK_LIBRARIES ... +# COMPILE_OPTIONS ... +# LINK_OPTIONS ... +# +# ``INTERFACE`` +# +# If specified, this TPL will build an INTERFACE library rather than an +# IMPORTED target +# +# ``ALLOW_SYSTEM_PATH_FALLBACK" +# +# If custom paths are given and the library is not found +# should we be allowed to search default system paths +# or error out if not found in given paths. +# +# ``LIBRARY `` +# +# If specified, this gives the name of the library to look for +# +# ``MODULE_NAME `` +# +# If specified, the name of the enclosing module passed to +# FIND_PACKAGE(). Defaults to TPL${NAME} if not +# given. +# +# ``IMPORTED_NAME `` +# +# If specified, this gives the name of the target to build. +# Defaults to Kokkos:: +# +# ``LIBRARY_PATHS ...`` +# +# If specified, this gives a list of paths to search for the library +# If not given, _ROOT/lib and _ROOT/lib64 will be searched. +# +# ``HEADER_PATHS ...`` +# +# If specified, this gives a list of paths to search for the headers +# If not given, _ROOT/include and _ROOT/include will be searched. +# +# ``HEADERS ...`` +# +# If specified, this gives a list of headers to find for the package +# +# ``LIBRARIES ...`` +# +# If specified, this gives a list of libraries to find for the package +# +MACRO(kokkos_find_imported NAME) + CMAKE_PARSE_ARGUMENTS(TPL + "INTERFACE;ALLOW_SYSTEM_PATH_FALLBACK" + "HEADER;LIBRARY;IMPORTED_NAME;MODULE_NAME" + "HEADER_PATHS;LIBRARY_PATHS;HEADERS;LIBRARIES" + ${ARGN}) + + IF(NOT TPL_MODULE_NAME) + SET(TPL_MODULE_NAME TPL${NAME}) + ENDIF() + + IF (TPL_ALLOW_SYSTEM_PATH_FALLBACK) + SET(ALLOW_PATH_FALLBACK_OPT ALLOW_SYSTEM_PATH_FALLBACK) + ELSE() + SET(ALLOW_PATH_FALLBACK_OPT) + ENDIF() + + IF (NOT TPL_IMPORTED_NAME) + IF (TPL_INTERFACE) + SET(TPL_IMPORTED_NAME ${NAME}) + ELSE() + SET(TPL_IMPORTED_NAME Kokkos::${NAME}) + ENDIF() + ENDIF() + + SET(${NAME}_INCLUDE_DIRS) + IF (TPL_HEADER) + KOKKOS_FIND_HEADER(${NAME}_INCLUDE_DIRS ${TPL_HEADER} ${NAME} ${ALLOW_PATH_FALLBACK_OPT} PATHS ${TPL_HEADER_PATHS}) + ENDIF() + + FOREACH(HEADER ${TPL_HEADERS}) + KOKKOS_FIND_HEADER(HEADER_FIND_TEMP ${HEADER} ${NAME} ${ALLOW_PATH_FALLBACK_OPT} PATHS ${TPL_HEADER_PATHS}) + IF(HEADER_FIND_TEMP) + LIST(APPEND ${NAME}_INCLUDE_DIRS ${HEADER_FIND_TEMP}) + ENDIF() + ENDFOREACH() + + SET(${NAME}_LIBRARY) + IF(TPL_LIBRARY) + KOKKOS_FIND_LIBRARY(${NAME}_LIBRARY ${TPL_LIBRARY} ${NAME} ${ALLOW_PATH_FALLBACK_OPT} PATHS ${TPL_LIBRARY_PATHS}) + ENDIF() + + SET(${NAME}_FOUND_LIBRARIES) + FOREACH(LIB ${TPL_LIBRARIES}) + KOKKOS_FIND_LIBRARY(${LIB}_LOCATION ${LIB} ${NAME} ${ALLOW_PATH_FALLBACK_OPT} PATHS ${TPL_LIBRARY_PATHS}) + IF(${LIB}_LOCATION) + LIST(APPEND ${NAME}_FOUND_LIBRARIES ${${LIB}_LOCATION}) + ELSE() + SET(${NAME}_FOUND_LIBRARIES ${${LIB}_LOCATION}) + BREAK() + ENDIF() + ENDFOREACH() + + INCLUDE(FindPackageHandleStandardArgs) + #Collect all the variables we need to be valid for + #find_package to have succeeded + SET(TPL_VARS_NEEDED) + IF (TPL_LIBRARY) + LIST(APPEND TPL_VARS_NEEDED ${NAME}_LIBRARY) + ENDIF() + IF(TPL_HEADER) + LIST(APPEND TPL_VARS_NEEDED ${NAME}_INCLUDE_DIRS) + ENDIF() + IF(TPL_LIBRARIES) + LIST(APPEND TPL_VARS_NEEDED ${NAME}_FOUND_LIBRARIES) + ENDIF() + FIND_PACKAGE_HANDLE_STANDARD_ARGS(${TPL_MODULE_NAME} REQUIRED_VARS ${TPL_VARS_NEEDED}) + + MARK_AS_ADVANCED(${NAME}_INCLUDE_DIRS ${NAME}_FOUND_LIBRARIES ${NAME}_LIBRARY) + + IF (${TPL_MODULE_NAME}_FOUND) + SET(IMPORT_TYPE) + IF (TPL_INTERFACE) + SET(IMPORT_TYPE "INTERFACE") + ENDIF() + KOKKOS_CREATE_IMPORTED_TPL(${TPL_IMPORTED_NAME} + ${IMPORT_TYPE} + INCLUDES "${${NAME}_INCLUDE_DIRS}" + LIBRARY "${${NAME}_LIBRARY}" + LINK_LIBRARIES "${${NAME}_FOUND_LIBRARIES}") + ENDIF() +ENDMACRO(kokkos_find_imported) + +# +# @MACRO: KOKKOS_LINK_TPL() +# +# Function that checks if a third-party library (TPL) has been enabled and +# calls target_link_libraries on the given target +# +# Usage:: +# +# KOKKOS_LINK_TPL( +# +# PUBLIC +# PRIVATE +# INTERFACE +# IMPORTED_NAME +# +# +# Checks if Kokkos_ENABLE_=ON and if so links the library +# +# ``PUBLIC/PRIVATE/INTERFACE`` +# +# Specifies the linkage mode. One of these arguments should be given. +# This will then invoke target_link_libraries( PUBLIC/PRIVATE/INTERFACE ) +# +# ``IMPORTED_NAME `` +# +# If specified, this gives the exact name of the target to link against +# target_link_libraries( ) +# +FUNCTION(kokkos_link_tpl TARGET) + CMAKE_PARSE_ARGUMENTS(TPL + "PUBLIC;PRIVATE;INTERFACE" + "IMPORTED_NAME" + "" + ${ARGN}) + #the name of the TPL + SET(TPL ${TPL_UNPARSED_ARGUMENTS}) + IF (KOKKOS_HAS_TRILINOS) + #Do nothing, they will have already been linked + ELSE() + IF (NOT TPL_IMPORTED_NAME) + SET(TPL_IMPORTED_NAME Kokkos::${TPL}) + ENDIF() + IF (KOKKOS_ENABLE_${TPL}) + IF (TPL_PUBLIC) + TARGET_LINK_LIBRARIES(${TARGET} PUBLIC ${TPL_IMPORTED_NAME}) + ELSEIF (TPL_PRIVATE) + TARGET_LINK_LIBRARIES(${TARGET} PRIVATE ${TPL_IMPORTED_NAME}) + ELSEIF (TPL_INTERFACE) + TARGET_LINK_LIBRARIES(${TARGET} INTERFACE ${TPL_IMPORTED_NAME}) + ELSE() + TARGET_LINK_LIBRARIES(${TARGET} ${TPL_IMPORTED_NAME}) + ENDIF() + ENDIF() + ENDIF() +ENDFUNCTION() + diff --git a/lib/kokkos/cmake/kokkos_install.cmake b/lib/kokkos/cmake/kokkos_install.cmake new file mode 100644 index 0000000000..1e4a5a2aad --- /dev/null +++ b/lib/kokkos/cmake/kokkos_install.cmake @@ -0,0 +1,42 @@ +IF (NOT KOKKOS_HAS_TRILINOS) + INCLUDE(GNUInstallDirs) + + #Set all the variables needed for KokkosConfig.cmake + GET_PROPERTY(KOKKOS_PROP_LIBS GLOBAL PROPERTY KOKKOS_LIBRARIES_NAMES) + SET(KOKKOS_LIBRARIES ${KOKKOS_PROP_LIBS}) + + INCLUDE(CMakePackageConfigHelpers) + CONFIGURE_PACKAGE_CONFIG_FILE( + cmake/KokkosConfig.cmake.in + "${Kokkos_BINARY_DIR}/KokkosConfig.cmake" + INSTALL_DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/cmake) + + INCLUDE(CMakePackageConfigHelpers) + CONFIGURE_PACKAGE_CONFIG_FILE( + cmake/KokkosConfigCommon.cmake.in + "${Kokkos_BINARY_DIR}/KokkosConfigCommon.cmake" + INSTALL_DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/cmake) + + WRITE_BASIC_PACKAGE_VERSION_FILE("${Kokkos_BINARY_DIR}/KokkosConfigVersion.cmake" + VERSION "${Kokkos_VERSION}" + COMPATIBILITY SameMajorVersion) + + # Install the KokkosConfig*.cmake files + install(FILES + "${Kokkos_BINARY_DIR}/KokkosConfig.cmake" + "${Kokkos_BINARY_DIR}/KokkosConfigCommon.cmake" + "${Kokkos_BINARY_DIR}/KokkosConfigVersion.cmake" + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Kokkos) + install(EXPORT KokkosTargets NAMESPACE Kokkos:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Kokkos) +ELSE() + CONFIGURE_FILE(cmake/KokkosConfigCommon.cmake.in ${Kokkos_BINARY_DIR}/KokkosConfigCommon.cmake @ONLY) + file(READ ${Kokkos_BINARY_DIR}/KokkosConfigCommon.cmake KOKKOS_CONFIG_COMMON) + file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/KokkosConfig_install.cmake" ${KOKKOS_CONFIG_COMMON}) +ENDIF() + +# build and install pkgconfig file +CONFIGURE_FILE(core/src/kokkos.pc.in kokkos.pc @ONLY) +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/kokkos.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/KokkosCore_config.h DESTINATION ${KOKKOS_HEADER_DIR}) + diff --git a/lib/kokkos/cmake/kokkos_options.cmake b/lib/kokkos/cmake/kokkos_options.cmake deleted file mode 100644 index 239301925c..0000000000 --- a/lib/kokkos/cmake/kokkos_options.cmake +++ /dev/null @@ -1,419 +0,0 @@ -########################## NOTES ############################################### -# List the options for configuring kokkos using CMake method of doing it. -# These options then get mapped onto KOKKOS_SETTINGS environment variable by -# kokkos_settings.cmake. It is separate to allow other packages to override -# these variables (e.g., TriBITS). - -########################## AVAILABLE OPTIONS ################################### -# Use lists for documentation, verification, and programming convenience - -# All CMake options of the type KOKKOS_ENABLE_* -set(KOKKOS_INTERNAL_ENABLE_OPTIONS_LIST) -list(APPEND KOKKOS_INTERNAL_ENABLE_OPTIONS_LIST - Serial - OpenMP - Pthread - Qthread - HPX - Cuda - ROCm - HWLOC - MEMKIND - LIBRT - Cuda_Lambda - Cuda_Relocatable_Device_Code - Cuda_UVM - Cuda_LDG_Intrinsic - HPX_ASYNC_DISPATCH - Debug - Debug_DualView_Modify_Check - Debug_Bounds_Check - Compiler_Warnings - Profiling - Profiling_Load_Print - Aggressive_Vectorization - Deprecated_Code - Explicit_Instantiation - ) - -#------------------------------------------------------------------------------- -#------------------------------- Recognize CamelCase Options --------------------------- -#------------------------------------------------------------------------------- - -foreach(opt ${KOKKOS_INTERNAL_ENABLE_OPTIONS_LIST}) - string(TOUPPER ${opt} OPT ) - IF(DEFINED Kokkos_ENABLE_${opt}) - IF(DEFINED KOKKOS_ENABLE_${OPT}) - IF(NOT ("${KOKKOS_ENABLE_${OPT}}" STREQUAL "${Kokkos_ENABLE_${opt}}")) - IF(DEFINED KOKKOS_ENABLE_${OPT}_INTERNAL) - MESSAGE(WARNING "Defined both Kokkos_ENABLE_${opt}=[${Kokkos_ENABLE_${opt}}] and KOKKOS_ENABLE_${OPT}=[${KOKKOS_ENABLE_${OPT}}] and they differ! Could be caused by old CMakeCache Variable. Run CMake again and warning should disappear. If not you are truly setting both variables.") - IF(NOT ("${Kokkos_ENABLE_${opt}}" STREQUAL "${KOKKOS_ENABLE_${OPT}_INTERNAL}")) - UNSET(KOKKOS_ENABLE_${OPT} CACHE) - SET(KOKKOS_ENABLE_${OPT} ${Kokkos_ENABLE_${opt}}) - MESSAGE(WARNING "SET BOTH VARIABLES KOKKOS_ENABLE_${OPT}: ${KOKKOS_ENABLE_${OPT}}") - ELSE() - SET(Kokkos_ENABLE_${opt} ${KOKKOS_ENABLE_${OPT}}) - ENDIF() - ELSE() - MESSAGE(FATAL_ERROR "Defined both Kokkos_ENABLE_${opt}=[${Kokkos_ENABLE_${opt}}] and KOKKOS_ENABLE_${OPT}=[${KOKKOS_ENABLE_${OPT}}] and they differ!") - ENDIF() - ENDIF() - ELSE() - SET(KOKKOS_INTERNAL_ENABLE_${OPT}_DEFAULT ${Kokkos_ENABLE_${opt}}) - ENDIF() - ENDIF() -endforeach() - -IF(DEFINED Kokkos_ARCH) - MESSAGE(FATAL_ERROR "Defined Kokkos_ARCH, use KOKKOS_ARCH instead!") -ENDIF() -IF(DEFINED Kokkos_Arch) - MESSAGE(FATAL_ERROR "Defined Kokkos_Arch, use KOKKOS_ARCH instead!") -ENDIF() - -#------------------------------------------------------------------------------- -# List of possible host architectures. -#------------------------------------------------------------------------------- -set(KOKKOS_ARCH_LIST) -list(APPEND KOKKOS_ARCH_LIST - None # No architecture optimization - AMDAVX # (HOST) AMD chip - EPYC # (HOST) AMD EPYC Zen-Core CPU - ARMv80 # (HOST) ARMv8.0 Compatible CPU - ARMv81 # (HOST) ARMv8.1 Compatible CPU - ARMv8-ThunderX # (HOST) ARMv8 Cavium ThunderX CPU - ARMv8-TX2 # (HOST) ARMv8 Cavium ThunderX2 CPU - WSM # (HOST) Intel Westmere CPU - SNB # (HOST) Intel Sandy/Ivy Bridge CPUs - HSW # (HOST) Intel Haswell CPUs - BDW # (HOST) Intel Broadwell Xeon E-class CPUs - SKX # (HOST) Intel Sky Lake Xeon E-class HPC CPUs (AVX512) - KNC # (HOST) Intel Knights Corner Xeon Phi - KNL # (HOST) Intel Knights Landing Xeon Phi - BGQ # (HOST) IBM Blue Gene Q - Power7 # (HOST) IBM POWER7 CPUs - Power8 # (HOST) IBM POWER8 CPUs - Power9 # (HOST) IBM POWER9 CPUs - Kepler # (GPU) NVIDIA Kepler default (generation CC 3.5) - Kepler30 # (GPU) NVIDIA Kepler generation CC 3.0 - Kepler32 # (GPU) NVIDIA Kepler generation CC 3.2 - Kepler35 # (GPU) NVIDIA Kepler generation CC 3.5 - Kepler37 # (GPU) NVIDIA Kepler generation CC 3.7 - Maxwell # (GPU) NVIDIA Maxwell default (generation CC 5.0) - Maxwell50 # (GPU) NVIDIA Maxwell generation CC 5.0 - Maxwell52 # (GPU) NVIDIA Maxwell generation CC 5.2 - Maxwell53 # (GPU) NVIDIA Maxwell generation CC 5.3 - Pascal60 # (GPU) NVIDIA Pascal generation CC 6.0 - Pascal61 # (GPU) NVIDIA Pascal generation CC 6.1 - Volta70 # (GPU) NVIDIA Volta generation CC 7.0 - Volta72 # (GPU) NVIDIA Volta generation CC 7.2 - Turing75 # (GPU) NVIDIA Turing generation CC 7.5 - ) - -# List of possible device architectures. -# The case and spelling here needs to match Makefile.kokkos -set(KOKKOS_DEVICES_LIST) -# Options: Cuda,ROCm,OpenMP,Pthread,Qthreads,Serial -list(APPEND KOKKOS_DEVICES_LIST - Cuda # NVIDIA GPU -- see below - OpenMP # OpenMP - Pthread # pthread - Qthreads # qthreads - HPX # HPX - Serial # serial - ROCm # Relocatable device code - ) - -# List of possible TPLs for Kokkos -# From Makefile.kokkos: Options: hwloc,librt,experimental_memkind -set(KOKKOS_USE_TPLS_LIST) -if(APPLE) -list(APPEND KOKKOS_USE_TPLS_LIST - HWLOC # hwloc - MEMKIND # experimental_memkind - ) -else() -list(APPEND KOKKOS_USE_TPLS_LIST - HWLOC # hwloc - LIBRT # librt - MEMKIND # experimental_memkind - ) -endif() -# Map of cmake variables to Makefile variables -set(KOKKOS_INTERNAL_HWLOC hwloc) -set(KOKKOS_INTERNAL_LIBRT librt) -set(KOKKOS_INTERNAL_MEMKIND experimental_memkind) - -# List of possible Advanced options -set(KOKKOS_OPTIONS_LIST) -list(APPEND KOKKOS_OPTIONS_LIST - AGGRESSIVE_VECTORIZATION - DISABLE_PROFILING - DISABLE_DUALVIEW_MODIFY_CHECK - ENABLE_PROFILE_LOAD_PRINT - ) -# Map of cmake variables to Makefile variables -set(KOKKOS_INTERNAL_LDG_INTRINSIC use_ldg) -set(KOKKOS_INTERNAL_UVM librt) -set(KOKKOS_INTERNAL_RELOCATABLE_DEVICE_CODE rdc) - - -#------------------------------------------------------------------------------- -# List of possible Options for CUDA -#------------------------------------------------------------------------------- -# From Makefile.kokkos: Options: use_ldg,force_uvm,rdc -set(KOKKOS_CUDA_OPTIONS_LIST) -list(APPEND KOKKOS_CUDA_OPTIONS_LIST - LDG_INTRINSIC # use_ldg - UVM # force_uvm - RELOCATABLE_DEVICE_CODE # rdc - LAMBDA # enable_lambda - ) - -# Map of cmake variables to Makefile variables -set(KOKKOS_INTERNAL_LDG_INTRINSIC use_ldg) -set(KOKKOS_INTERNAL_UVM force_uvm) -set(KOKKOS_INTERNAL_RELOCATABLE_DEVICE_CODE rdc) -set(KOKKOS_INTERNAL_LAMBDA enable_lambda) - - -#------------------------------------------------------------------------------- -# List of possible Options for HPX -#------------------------------------------------------------------------------- -# From Makefile.kokkos: Options: enable_async_dispatch -set(KOKKOS_HPX_OPTIONS_LIST) -list(APPEND KOKKOS_HPX_OPTIONS_LIST - ASYNC_DISPATCH # enable_async_dispatch - ) - -# Map of cmake variables to Makefile variables -set(KOKKOS_INTERNAL_ENABLE_ASYNC_DISPATCH enable_async_dispatch) - - -#------------------------------------------------------------------------------- -#------------------------------- Create doc strings ---------------------------- -#------------------------------------------------------------------------------- - -set(tmpr "\n ") -string(REPLACE ";" ${tmpr} KOKKOS_INTERNAL_ARCH_DOCSTR "${KOKKOS_ARCH_LIST}") -set(KOKKOS_INTERNAL_ARCH_DOCSTR "${tmpr}${KOKKOS_INTERNAL_ARCH_DOCSTR}") -# This would be useful, but we use Foo_ENABLE mechanisms -#string(REPLACE ";" ${tmpr} KOKKOS_INTERNAL_DEVICES_DOCSTR "${KOKKOS_DEVICES_LIST}") -#string(REPLACE ";" ${tmpr} KOKKOS_INTERNAL_USE_TPLS_DOCSTR "${KOKKOS_USE_TPLS_LIST}") -#string(REPLACE ";" ${tmpr} KOKKOS_INTERNAL_CUDA_OPTIONS_DOCSTR "${KOKKOS_CUDA_OPTIONS_LIST}") - -#------------------------------------------------------------------------------- -#------------------------------- GENERAL OPTIONS ------------------------------- -#------------------------------------------------------------------------------- - -# Setting this variable to a value other than "None" can improve host -# performance by turning on architecture specific code. -# NOT SET is used to determine if the option is passed in. It is reset to -# default "None" down below. -set(KOKKOS_ARCH "NOT_SET" CACHE STRING - "Optimize for specific host architecture. Options are: ${KOKKOS_INTERNAL_ARCH_DOCSTR}") - -# Whether to build separate libraries or now -set(KOKKOS_SEPARATE_LIBS OFF CACHE BOOL "OFF = kokkos. ON = kokkoscore, kokkoscontainers, and kokkosalgorithms.") - -# Qthreads options. -set(KOKKOS_QTHREADS_DIR "" CACHE PATH "Location of Qthreads library.") - -# HPX options. -set(KOKKOS_HPX_DIR "" CACHE PATH "Location of HPX library.") - -# Whether to build separate libraries or now -set(KOKKOS_SEPARATE_TESTS OFF CACHE BOOL "Provide unit test targets with finer granularity.") - -#------------------------------------------------------------------------------- -#------------------------------- KOKKOS_DEVICES -------------------------------- -#------------------------------------------------------------------------------- -# Figure out default settings -IF(Trilinos_ENABLE_Kokkos) - set_kokkos_default_default(SERIAL ON) - set_kokkos_default_default(PTHREAD OFF) - IF(TPL_ENABLE_QTHREAD) - set_kokkos_default_default(QTHREADS ${TPL_ENABLE_QTHREAD}) - ELSE() - set_kokkos_default_default(QTHREADS OFF) - ENDIF() - IF(TPL_ENABLE_HPX) - set_kokkos_default_default(HPX ON) - ELSE() - set_kokkos_default_default(HPX OFF) - ENDIF() - IF(Trilinos_ENABLE_OpenMP) - set_kokkos_default_default(OPENMP ${Trilinos_ENABLE_OpenMP}) - ELSE() - set_kokkos_default_default(OPENMP OFF) - ENDIF() - IF(TPL_ENABLE_CUDA) - set_kokkos_default_default(CUDA ${TPL_ENABLE_CUDA}) - ELSE() - set_kokkos_default_default(CUDA OFF) - ENDIF() - set_kokkos_default_default(ROCM OFF) -ELSE() - set_kokkos_default_default(SERIAL ON) - set_kokkos_default_default(OPENMP OFF) - set_kokkos_default_default(PTHREAD OFF) - set_kokkos_default_default(QTHREAD OFF) - set_kokkos_default_default(HPX OFF) - set_kokkos_default_default(CUDA OFF) - set_kokkos_default_default(ROCM OFF) -ENDIF() - -# Set which Kokkos backend to use. -# These are the actual options that define the settings. -set(KOKKOS_ENABLE_SERIAL ${KOKKOS_INTERNAL_ENABLE_SERIAL_DEFAULT} CACHE BOOL "Whether to enable the Kokkos::Serial device. This device executes \"parallel\" kernels sequentially on a single CPU thread. It is enabled by default. If you disable this device, please enable at least one other CPU device, such as Kokkos::OpenMP or Kokkos::Threads.") -set(KOKKOS_ENABLE_OPENMP ${KOKKOS_INTERNAL_ENABLE_OPENMP_DEFAULT} CACHE BOOL "Enable OpenMP support in Kokkos." FORCE) -set(KOKKOS_ENABLE_PTHREAD ${KOKKOS_INTERNAL_ENABLE_PTHREAD_DEFAULT} CACHE BOOL "Enable Pthread support in Kokkos.") -set(KOKKOS_ENABLE_QTHREADS ${KOKKOS_INTERNAL_ENABLE_QTHREADS_DEFAULT} CACHE BOOL "Enable Qthreads support in Kokkos.") -set(KOKKOS_ENABLE_HPX ${KOKKOS_INTERNAL_ENABLE_HPX_DEFAULT} CACHE BOOL "Enable HPX support in Kokkos.") -set(KOKKOS_ENABLE_CUDA ${KOKKOS_INTERNAL_ENABLE_CUDA_DEFAULT} CACHE BOOL "Enable CUDA support in Kokkos.") -set(KOKKOS_ENABLE_ROCM ${KOKKOS_INTERNAL_ENABLE_ROCM_DEFAULT} CACHE BOOL "Enable ROCm support in Kokkos.") - - - -#------------------------------------------------------------------------------- -#------------------------------- KOKKOS DEBUG and PROFILING -------------------- -#------------------------------------------------------------------------------- - -# Debug related options enable compiler warnings - -set_kokkos_default_default(DEBUG OFF) -set(KOKKOS_ENABLE_DEBUG ${KOKKOS_INTERNAL_ENABLE_DEBUG_DEFAULT} CACHE BOOL "Enable Kokkos Debug.") - -# From Makefile.kokkos: Advanced Options: -#compiler_warnings, aggressive_vectorization, disable_profiling, disable_dualview_modify_check, enable_profile_load_print -set_kokkos_default_default(COMPILER_WARNINGS OFF) -set(KOKKOS_ENABLE_COMPILER_WARNINGS ${KOKKOS_INTERNAL_ENABLE_COMPILER_WARNINGS_DEFAULT} CACHE BOOL "Enable compiler warnings.") - -set_kokkos_default_default(DEBUG_DUALVIEW_MODIFY_CHECK OFF) -set(KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK ${KOKKOS_INTERNAL_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK_DEFAULT} CACHE BOOL "Enable dualview modify check.") - -# Enable aggressive vectorization. -set_kokkos_default_default(AGGRESSIVE_VECTORIZATION OFF) -set(KOKKOS_ENABLE_AGGRESSIVE_VECTORIZATION ${KOKKOS_INTERNAL_ENABLE_AGGRESSIVE_VECTORIZATION_DEFAULT} CACHE BOOL "Enable aggressive vectorization.") - -# Enable profiling. -set_kokkos_default_default(PROFILING ON) -set(KOKKOS_ENABLE_PROFILING ${KOKKOS_INTERNAL_ENABLE_PROFILING_DEFAULT} CACHE BOOL "Enable profiling.") - -set_kokkos_default_default(PROFILING_LOAD_PRINT OFF) -set(KOKKOS_ENABLE_PROFILING_LOAD_PRINT ${KOKKOS_INTERNAL_ENABLE_PROFILING_LOAD_PRINT_DEFAULT} CACHE BOOL "Enable profile load print.") - -set_kokkos_default_default(DEPRECATED_CODE ON) -set(KOKKOS_ENABLE_DEPRECATED_CODE ${KOKKOS_INTERNAL_ENABLE_DEPRECATED_CODE_DEFAULT} CACHE BOOL "Enable deprecated code.") - -set_kokkos_default_default(EXPLICIT_INSTANTIATION OFF) -set(KOKKOS_ENABLE_EXPLICIT_INSTANTIATION ${KOKKOS_INTERNAL_ENABLE_EXPLICIT_INSTANTIATION_DEFAULT} CACHE BOOL "Enable explicit template instantiation.") - -#------------------------------------------------------------------------------- -#------------------------------- KOKKOS_USE_TPLS ------------------------------- -#------------------------------------------------------------------------------- -# Enable hwloc library. -# Figure out default: -IF(Trilinos_ENABLE_Kokkos AND TPL_ENABLE_HWLOC) - set_kokkos_default_default(HWLOC ON) -ELSE() - set_kokkos_default_default(HWLOC OFF) -ENDIF() -set(KOKKOS_ENABLE_HWLOC ${KOKKOS_INTERNAL_ENABLE_HWLOC_DEFAULT} CACHE BOOL "Enable hwloc for better process placement.") -set(KOKKOS_HWLOC_DIR "" CACHE PATH "Location of hwloc library. (kokkos tpl)") - -# Enable memkind library. -set_kokkos_default_default(MEMKIND OFF) -set(KOKKOS_ENABLE_MEMKIND ${KOKKOS_INTERNAL_ENABLE_MEMKIND_DEFAULT} CACHE BOOL "Enable memkind. (kokkos tpl)") -set(KOKKOS_MEMKIND_DIR "" CACHE PATH "Location of memkind library. (kokkos tpl)") - -# Enable rt library. -IF(Trilinos_ENABLE_Kokkos) - IF(DEFINED TPL_ENABLE_LIBRT) - set_kokkos_default_default(LIBRT ${TPL_ENABLE_LIBRT}) - ELSE() - set_kokkos_default_default(LIBRT OFF) - ENDIF() -ELSE() - set_kokkos_default_default(LIBRT ON) -ENDIF() -set(KOKKOS_ENABLE_LIBRT ${KOKKOS_INTERNAL_ENABLE_LIBRT_DEFAULT} CACHE BOOL "Enable librt for more precise timer. (kokkos tpl)") - - -#------------------------------------------------------------------------------- -#------------------------------- KOKKOS_CUDA_OPTIONS --------------------------- -#------------------------------------------------------------------------------- - -# CUDA options. -# Set Defaults -set_kokkos_default_default(CUDA_LDG_INTRINSIC_DEFAULT OFF) -set_kokkos_default_default(CUDA_UVM_DEFAULT OFF) -set_kokkos_default_default(CUDA_RELOCATABLE_DEVICE_CODE OFF) -IF(Trilinos_ENABLE_Kokkos) - IF(KOKKOS_ENABLE_CUDA) - find_package(CUDA) - ENDIF() - IF (DEFINED CUDA_VERSION) - IF (CUDA_VERSION VERSION_GREATER "7.0") - set_kokkos_default_default(CUDA_LAMBDA ON) - ELSE() - set_kokkos_default_default(CUDA_LAMBDA OFF) - ENDIF() - ENDIF() -ELSE() - set_kokkos_default_default(CUDA_LAMBDA OFF) -ENDIF() - -# Set actual options -set(KOKKOS_CUDA_DIR "" CACHE PATH "Location of CUDA library. Defaults to where nvcc installed.") -set(KOKKOS_ENABLE_CUDA_LDG_INTRINSIC ${KOKKOS_INTERNAL_ENABLE_CUDA_LDG_INTRINSIC_DEFAULT} CACHE BOOL "Enable CUDA LDG. (cuda option)") -set(KOKKOS_ENABLE_CUDA_UVM ${KOKKOS_INTERNAL_ENABLE_CUDA_UVM_DEFAULT} CACHE BOOL "Enable CUDA unified virtual memory.") -set(KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE ${KOKKOS_INTERNAL_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE_DEFAULT} CACHE BOOL "Enable relocatable device code for CUDA. (cuda option)") -set(KOKKOS_ENABLE_CUDA_LAMBDA ${KOKKOS_INTERNAL_ENABLE_CUDA_LAMBDA_DEFAULT} CACHE BOOL "Enable lambdas for CUDA. (cuda option)") - - -#------------------------------------------------------------------------------- -#------------------------------- KOKKOS_HPX_OPTIONS ---------------------------- -#------------------------------------------------------------------------------- - -# HPX options. -# Set Defaults -set_kokkos_default_default(HPX_ASYNC_DISPATCH OFF) - -# Set actual options -set(KOKKOS_ENABLE_HPX_ASYNC_DISPATCH ${KOKKOS_INTERNAL_ENABLE_HPX_ASYNC_DISPATCH_DEFAULT} CACHE BOOL "Enable HPX async dispatch.") - - -#------------------------------------------------------------------------------- -#----------------------- HOST ARCH AND LEGACY TRIBITS -------------------------- -#------------------------------------------------------------------------------- - -# This defines the previous legacy TriBITS builds. -set(KOKKOS_LEGACY_TRIBITS False) -IF ("${KOKKOS_ARCH}" STREQUAL "NOT_SET") - set(KOKKOS_ARCH "None") - IF(KOKKOS_HAS_TRILINOS) - set(KOKKOS_LEGACY_TRIBITS True) - ENDIF() -ENDIF() -IF (KOKKOS_HAS_TRILINOS) - IF (KOKKOS_LEGACY_TRIBITS) - message(STATUS "Using the legacy tribits build because KOKKOS_ARCH not set") - ELSE() - message(STATUS "NOT using the legacy tribits build because KOKKOS_ARCH *is* set") - ENDIF() -ENDIF() - -#------------------------------------------------------------------------------- -#----------------------- Set CamelCase Options if they are not yet set --------- -#------------------------------------------------------------------------------- - -foreach(opt ${KOKKOS_INTERNAL_ENABLE_OPTIONS_LIST}) - string(TOUPPER ${opt} OPT ) - UNSET(KOKKOS_ENABLE_${OPT}_INTERNAL CACHE) - SET(KOKKOS_ENABLE_${OPT}_INTERNAL ${KOKKOS_ENABLE_${OPT}} CACHE BOOL INTERNAL) - IF(DEFINED KOKKOS_ENABLE_${OPT}) - UNSET(Kokkos_ENABLE_${opt} CACHE) - SET(Kokkos_ENABLE_${opt} ${KOKKOS_ENABLE_${OPT}} CACHE BOOL "CamelCase Compatibility setting for KOKKOS_ENABLE_${OPT}") - ENDIF() -endforeach() diff --git a/lib/kokkos/cmake/kokkos_pick_cxx_std.cmake b/lib/kokkos/cmake/kokkos_pick_cxx_std.cmake new file mode 100644 index 0000000000..cf14948f43 --- /dev/null +++ b/lib/kokkos/cmake/kokkos_pick_cxx_std.cmake @@ -0,0 +1,46 @@ +# From CMake 3.10 documentation + +#This can run at any time +KOKKOS_OPTION(CXX_STANDARD "" STRING "The C++ standard for Kokkos to use: 11, 14, 17, or 20. If empty, this will default to CMAKE_CXX_STANDARD. If both CMAKE_CXX_STANDARD and Kokkos_CXX_STANDARD are empty, this will default to 11") + +# Set CXX standard flags +SET(KOKKOS_ENABLE_CXX11 OFF) +SET(KOKKOS_ENABLE_CXX14 OFF) +SET(KOKKOS_ENABLE_CXX17 OFF) +SET(KOKKOS_ENABLE_CXX20 OFF) +IF (KOKKOS_CXX_STANDARD) + IF (${KOKKOS_CXX_STANDARD} STREQUAL "c++98") + MESSAGE(FATAL_ERROR "Kokkos no longer supports C++98 - minimum C++11") + ELSEIF (${KOKKOS_CXX_STANDARD} STREQUAL "c++11") + MESSAGE(WARNING "Deprecated Kokkos C++ standard set as 'c++11'. Use '11' instead.") + SET(KOKKOS_CXX_STANDARD "11") + ELSEIF(${KOKKOS_CXX_STANDARD} STREQUAL "c++14") + MESSAGE(WARNING "Deprecated Kokkos C++ standard set as 'c++14'. Use '14' instead.") + SET(KOKKOS_CXX_STANDARD "14") + ELSEIF(${KOKKOS_CXX_STANDARD} STREQUAL "c++17") + MESSAGE(WARNING "Deprecated Kokkos C++ standard set as 'c++17'. Use '17' instead.") + SET(KOKKOS_CXX_STANDARD "17") + ELSEIF(${KOKKOS_CXX_STANDARD} STREQUAL "c++1y") + MESSAGE(WARNING "Deprecated Kokkos C++ standard set as 'c++1y'. Use '1Y' instead.") + SET(KOKKOS_CXX_STANDARD "1Y") + ELSEIF(${KOKKOS_CXX_STANDARD} STREQUAL "c++1z") + MESSAGE(WARNING "Deprecated Kokkos C++ standard set as 'c++1z'. Use '1Z' instead.") + SET(KOKKOS_CXX_STANDARD "1Z") + ELSEIF(${KOKKOS_CXX_STANDARD} STREQUAL "c++2a") + MESSAGE(WARNING "Deprecated Kokkos C++ standard set as 'c++2a'. Use '2A' instead.") + SET(KOKKOS_CXX_STANDARD "2A") + ENDIF() +ENDIF() + +IF (NOT KOKKOS_CXX_STANDARD AND NOT CMAKE_CXX_STANDARD) + MESSAGE(STATUS "Setting default Kokkos CXX standard to 11") + SET(KOKKOS_CXX_STANDARD "11") +ELSEIF(NOT KOKKOS_CXX_STANDARD) + MESSAGE(STATUS "Setting default Kokkos CXX standard to ${CMAKE_CXX_STANDARD}") + SET(KOKKOS_CXX_STANDARD ${CMAKE_CXX_STANDARD}) +ENDIF() + + + + + diff --git a/lib/kokkos/cmake/kokkos_settings.cmake b/lib/kokkos/cmake/kokkos_settings.cmake deleted file mode 100644 index 2c622d0de9..0000000000 --- a/lib/kokkos/cmake/kokkos_settings.cmake +++ /dev/null @@ -1,259 +0,0 @@ -########################## NOTES ############################################### -# This files goal is to take CMake options found in kokkos_options.cmake but -# possibly set from elsewhere -# (see: trilinos/cmake/ProjectCOmpilerPostConfig.cmake) -# using CMake idioms and map them onto the KOKKOS_SETTINGS variables that gets -# passed to the kokkos makefile configuration: -# make -f ${CMAKE_SOURCE_DIR}/core/src/Makefile ${KOKKOS_SETTINGS} build-makefile-cmake-kokkos -# that generates KokkosCore_config.h and kokkos_generated_settings.cmake -# To understand how to form KOKKOS_SETTINGS, see -# /Makefile.kokkos - -#------------------------------------------------------------------------------- -#------------------------------- GENERAL OPTIONS ------------------------------- -#------------------------------------------------------------------------------- - -# Ensure that KOKKOS_ARCH is in the ARCH_LIST -if (KOKKOS_ARCH MATCHES ",") - message("-- Detected a comma in: KOKKOS_ARCH=`${KOKKOS_ARCH}`") - message("-- Although we prefer KOKKOS_ARCH to be semicolon-delimited, we do allow") - message("-- comma-delimited values for compatibility with scripts (see github.com/trilinos/Trilinos/issues/2330)") - string(REPLACE "," ";" KOKKOS_ARCH "${KOKKOS_ARCH}") - message("-- Commas were changed to semicolons, now KOKKOS_ARCH=`${KOKKOS_ARCH}`") -endif() -foreach(arch ${KOKKOS_ARCH}) - list(FIND KOKKOS_ARCH_LIST ${arch} indx) - if (indx EQUAL -1) - message(FATAL_ERROR "`${arch}` is not an accepted value in KOKKOS_ARCH=`${KOKKOS_ARCH}`." - " Please pick from these choices: ${KOKKOS_INTERNAL_ARCH_DOCSTR}") - endif () -endforeach() - -# KOKKOS_SETTINGS uses KOKKOS_ARCH -string(REPLACE ";" "," KOKKOS_GMAKE_ARCH "${KOKKOS_ARCH}") - -# From Makefile.kokkos: Options: yes,no -if(${KOKKOS_ENABLE_DEBUG}) - set(KOKKOS_GMAKE_DEBUG yes) -else() - set(KOKKOS_GMAKE_DEBUG no) -endif() - -#------------------------------- KOKKOS_DEVICES -------------------------------- -# Can have multiple devices -set(KOKKOS_DEVICESl) -foreach(devopt ${KOKKOS_DEVICES_LIST}) - string(TOUPPER ${devopt} devoptuc) - if (${KOKKOS_ENABLE_${devoptuc}}) - list(APPEND KOKKOS_DEVICESl ${devopt}) - endif () -endforeach() -# List needs to be comma-delmitted -string(REPLACE ";" "," KOKKOS_GMAKE_DEVICES "${KOKKOS_DEVICESl}") - -#------------------------------- KOKKOS_OPTIONS -------------------------------- -# From Makefile.kokkos: Options: aggressive_vectorization,disable_profiling,disable_deprecated_code -#compiler_warnings, aggressive_vectorization, disable_profiling, disable_dualview_modify_check, enable_profile_load_print - -set(KOKKOS_OPTIONSl) -if(${KOKKOS_ENABLE_COMPILER_WARNINGS}) - list(APPEND KOKKOS_OPTIONSl compiler_warnings) -endif() -if(${KOKKOS_ENABLE_AGGRESSIVE_VECTORIZATION}) - list(APPEND KOKKOS_OPTIONSl aggressive_vectorization) -endif() -if(NOT ${KOKKOS_ENABLE_PROFILING}) - list(APPEND KOKKOS_OPTIONSl disable_profiling) -endif() -if(NOT ${KOKKOS_ENABLE_DEPRECATED_CODE}) - list(APPEND KOKKOS_OPTIONSl disable_deprecated_code) -endif() -if(NOT ${KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK}) - list(APPEND KOKKOS_OPTIONSl disable_dualview_modify_check) -endif() -if(${KOKKOS_ENABLE_PROFILING_LOAD_PRINT}) - list(APPEND KOKKOS_OPTIONSl enable_profile_load_print) -endif() -if(${KOKKOS_ENABLE_EXPLICIT_INSTANTIATION}) - list(APPEND KOKKOS_OPTIONSl enable_eti) -endif() -# List needs to be comma-delimitted -string(REPLACE ";" "," KOKKOS_GMAKE_OPTIONS "${KOKKOS_OPTIONSl}") - - -#------------------------------- KOKKOS_USE_TPLS ------------------------------- -# Construct the Makefile options -set(KOKKOS_USE_TPLSl) -foreach(tplopt ${KOKKOS_USE_TPLS_LIST}) - if (${KOKKOS_ENABLE_${tplopt}}) - list(APPEND KOKKOS_USE_TPLSl ${KOKKOS_INTERNAL_${tplopt}}) - endif () -endforeach() -# List needs to be comma-delimitted -string(REPLACE ";" "," KOKKOS_GMAKE_USE_TPLS "${KOKKOS_USE_TPLSl}") - - -#------------------------------- KOKKOS_CUDA_OPTIONS --------------------------- -# Construct the Makefile options -set(KOKKOS_CUDA_OPTIONSl) -foreach(cudaopt ${KOKKOS_CUDA_OPTIONS_LIST}) - if (${KOKKOS_ENABLE_CUDA_${cudaopt}}) - list(APPEND KOKKOS_CUDA_OPTIONSl ${KOKKOS_INTERNAL_${cudaopt}}) - endif () -endforeach() -# List needs to be comma-delmitted -string(REPLACE ";" "," KOKKOS_GMAKE_CUDA_OPTIONS "${KOKKOS_CUDA_OPTIONSl}") - -#------------------------------- PATH VARIABLES -------------------------------- -# Want makefile to use same executables specified which means modifying -# the path so the $(shell ...) commands in the makefile see the right exec -# Also, the Makefile's use FOO_PATH naming scheme for -I/-L construction -#TODO: Makefile.kokkos allows this to be overwritten? ROCM_HCC_PATH - -set(KOKKOS_INTERNAL_PATHS) -set(addpathl) -foreach(kvar IN LISTS KOKKOS_USE_TPLS_LIST ITEMS CUDA QTHREADS) - if(${KOKKOS_ENABLE_${kvar}}) - if(DEFINED KOKKOS_${kvar}_DIR) - set(KOKKOS_INTERNAL_PATHS ${KOKKOS_INTERNAL_PATHS} "${kvar}_PATH=${KOKKOS_${kvar}_DIR}") - if(IS_DIRECTORY ${KOKKOS_${kvar}_DIR}/bin) - list(APPEND addpathl ${KOKKOS_${kvar}_DIR}/bin) - endif() - endif() - endif() -endforeach() -# Path env is : delimitted -string(REPLACE ";" ":" KOKKOS_INTERNAL_ADDTOPATH "${addpathl}") - - -######################### SET KOKKOS_SETTINGS ################################## -# Set the KOKKOS_SETTINGS String -- this is the primary communication with the -# makefile configuration. See Makefile.kokkos - -set(KOKKOS_SETTINGS KOKKOS_CMAKE=yes) -set(KOKKOS_SETTINGS ${KOKKOS_SETTINGS} KOKKOS_SRC_PATH=${KOKKOS_SRC_PATH}) -set(KOKKOS_SETTINGS ${KOKKOS_SETTINGS} KOKKOS_PATH=${KOKKOS_PATH}) -set(KOKKOS_SETTINGS ${KOKKOS_SETTINGS} KOKKOS_INSTALL_PATH=${CMAKE_INSTALL_PREFIX}) - -# Form of KOKKOS_foo=$KOKKOS_foo -foreach(kvar ARCH;DEVICES;DEBUG;OPTIONS;CUDA_OPTIONS;USE_TPLS) - if(DEFINED KOKKOS_GMAKE_${kvar}) - if (NOT "${KOKKOS_GMAKE_${kvar}}" STREQUAL "") - set(KOKKOS_SETTINGS ${KOKKOS_SETTINGS} KOKKOS_${kvar}=${KOKKOS_GMAKE_${kvar}}) - endif() - endif() -endforeach() - -# Form of VAR=VAL -#TODO: Makefile supports MPICH_CXX, OMPI_CXX as well -foreach(ovar CXX;CXXFLAGS;LDFLAGS) - if(DEFINED ${ovar}) - if (NOT "${${ovar}}" STREQUAL "") - set(KOKKOS_SETTINGS ${KOKKOS_SETTINGS} ${ovar}=${${ovar}}) - endif() - endif() -endforeach() - -# Finally, do the paths -if (NOT "${KOKKOS_INTERNAL_PATHS}" STREQUAL "") - set(KOKKOS_SETTINGS ${KOKKOS_SETTINGS} ${KOKKOS_INTERNAL_PATHS}) -endif() -if (NOT "${KOKKOS_INTERNAL_ADDTOPATH}" STREQUAL "") - set(KOKKOS_SETTINGS ${KOKKOS_SETTINGS} "PATH=${KOKKOS_INTERNAL_ADDTOPATH}:$ENV{PATH}") -endif() - -if (CMAKE_CXX_STANDARD) - if (CMAKE_CXX_STANDARD STREQUAL "98") - message(FATAL_ERROR "Kokkos requires C++11 or newer!") - endif() - set(KOKKOS_CXX_STANDARD "c++${CMAKE_CXX_STANDARD}") - if (CMAKE_CXX_EXTENSIONS) - if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set(KOKKOS_CXX_STANDARD "gnu++${CMAKE_CXX_STANDARD}") - endif() - endif() - set(KOKKOS_SETTINGS ${KOKKOS_SETTINGS} "KOKKOS_CXX_STANDARD=\"${KOKKOS_CXX_STANDARD}\"") -endif() - -# Final form that gets passed to make -set(KOKKOS_SETTINGS env ${KOKKOS_SETTINGS}) - - -############################ PRINT CONFIGURE STATUS ############################ - -if(KOKKOS_CMAKE_VERBOSE) - message(STATUS "") - message(STATUS "****************** Kokkos Settings ******************") - message(STATUS "Execution Spaces") - - if(KOKKOS_ENABLE_CUDA) - message(STATUS " Device Parallel: Cuda") - else() - message(STATUS " Device Parallel: None") - endif() - - if(KOKKOS_ENABLE_OPENMP) - message(STATUS " Host Parallel: OpenMP") - elseif(KOKKOS_ENABLE_PTHREAD) - message(STATUS " Host Parallel: Pthread") - elseif(KOKKOS_ENABLE_QTHREADS) - message(STATUS " Host Parallel: Qthreads") - elseif(KOKKOS_ENABLE_HPX) - message(STATUS " Host Parallel: HPX") - else() - message(STATUS " Host Parallel: None") - endif() - - if(KOKKOS_ENABLE_SERIAL) - message(STATUS " Host Serial: Serial") - else() - message(STATUS " Host Serial: None") - endif() - - message(STATUS "") - message(STATUS "Architectures:") - message(STATUS " ${KOKKOS_GMAKE_ARCH}") - - message(STATUS "") - message(STATUS "Enabled options") - - if(KOKKOS_SEPARATE_LIBS) - message(STATUS " KOKKOS_SEPARATE_LIBS") - endif() - - foreach(opt IN LISTS KOKKOS_INTERNAL_ENABLE_OPTIONS_LIST) - string(TOUPPER ${opt} OPT) - if (KOKKOS_ENABLE_${OPT}) - message(STATUS " KOKKOS_ENABLE_${OPT}") - endif() - endforeach() - - if(KOKKOS_ENABLE_CUDA) - if(KOKKOS_CUDA_DIR) - message(STATUS " KOKKOS_CUDA_DIR: ${KOKKOS_CUDA_DIR}") - endif() - endif() - - if(KOKKOS_QTHREADS_DIR) - message(STATUS " KOKKOS_QTHREADS_DIR: ${KOKKOS_QTHREADS_DIR}") - endif() - - if(KOKKOS_HWLOC_DIR) - message(STATUS " KOKKOS_HWLOC_DIR: ${KOKKOS_HWLOC_DIR}") - endif() - - if(KOKKOS_MEMKIND_DIR) - message(STATUS " KOKKOS_MEMKIND_DIR: ${KOKKOS_MEMKIND_DIR}") - endif() - - if(KOKKOS_HPX_DIR) - message(STATUS " KOKKOS_HPX_DIR: ${KOKKOS_HPX_DIR}") - endif() - - message(STATUS "") - message(STATUS "Final kokkos settings variable:") - message(STATUS " ${KOKKOS_SETTINGS}") - - message(STATUS "*****************************************************") - message(STATUS "") -endif() diff --git a/lib/kokkos/cmake/kokkos_test_cxx_std.cmake b/lib/kokkos/cmake/kokkos_test_cxx_std.cmake new file mode 100644 index 0000000000..c264517abe --- /dev/null +++ b/lib/kokkos/cmake/kokkos_test_cxx_std.cmake @@ -0,0 +1,144 @@ +KOKKOS_CFG_DEPENDS(CXX_STD COMPILER_ID) + +FUNCTION(kokkos_set_cxx_standard_feature standard) + SET(EXTENSION_NAME CMAKE_CXX${standard}_EXTENSION_COMPILE_OPTION) + SET(STANDARD_NAME CMAKE_CXX${standard}_STANDARD_COMPILE_OPTION) + SET(FEATURE_NAME cxx_std_${standard}) + #CMake's way of telling us that the standard (or extension) + #flags are supported is the extension/standard variables + IF (NOT DEFINED CMAKE_CXX_EXTENSIONS) + IF(KOKKOS_DONT_ALLOW_EXTENSIONS) + GLOBAL_SET(KOKKOS_USE_CXX_EXTENSIONS OFF) + ELSE() + GLOBAL_SET(KOKKOS_USE_CXX_EXTENSIONS ON) + ENDIF() + ELSEIF(CMAKE_CXX_EXTENSIONS) + IF(KOKKOS_DONT_ALLOW_EXTENSIONS) + MESSAGE(FATAL_ERROR "The chosen configuration does not support CXX extensions flags: ${KOKKOS_DONT_ALLOW_EXTENSIONS}. Must set CMAKE_CXX_EXTENSIONS=OFF to continue") + ELSE() + GLOBAL_SET(KOKKOS_USE_CXX_EXTENSIONS ON) + ENDIF() + ELSE() + #For trilinos, we need to make sure downstream projects + GLOBAL_SET(KOKKOS_USE_CXX_EXTENSIONS OFF) + ENDIF() + + IF (KOKKOS_USE_CXX_EXTENSIONS AND ${EXTENSION_NAME}) + MESSAGE(STATUS "Using ${${EXTENSION_NAME}} for C++${standard} extensions as feature") + GLOBAL_SET(KOKKOS_CXX_STANDARD_FEATURE ${FEATURE_NAME}) + ELSEIF(NOT KOKKOS_USE_CXX_EXTENSIONS AND ${STANDARD_NAME}) + MESSAGE(STATUS "Using ${${STANDARD_NAME}} for C++${standard} standard as feature") + GLOBAL_SET(KOKKOS_CXX_STANDARD_FEATURE ${FEATURE_NAME}) + ELSE() + #nope, we can't do anything here + MESSAGE(WARNING "C++${standard} is not supported as a compiler feature. We will choose custom flags for now, but this behavior has been deprecated. Please open an issue at https://github.com/kokkos/kokkos/issues reporting that ${KOKKOS_CXX_COMPILER_ID} ${KOKKOS_CXX_COMPILER_VERSION} failed for ${KOKKOS_CXX_STANDARD}, preferrably including your CMake command.") + GLOBAL_SET(KOKKOS_CXX_STANDARD_FEATURE "") + ENDIF() + + IF(NOT ${FEATURE_NAME} IN_LIST CMAKE_CXX_COMPILE_FEATURES) + MESSAGE(FATAL_ERROR "Compiler ${KOKKOS_CXX_COMPILER_ID} should support ${FEATURE_NAME}, but CMake reports feature not supported") + ENDIF() +ENDFUNCTION() + + +IF (KOKKOS_CXX_STANDARD AND CMAKE_CXX_STANDARD) + #make sure these are consistent + IF (NOT KOKKOS_CXX_STANDARD STREQUAL CMAKE_CXX_STANDARD) + MESSAGE(WARNING "Specified both CMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} and KOKKOS_CXX_STANDARD=${KOKKOS_CXX_STANDARD}, but they don't match") + SET(CMAKE_CXX_STANDARD ${KOKKOS_CXX_STANDARD} CACHE STRING "C++ standard" FORCE) + ENDIF() +ENDIF() + + +IF (KOKKOS_CXX_STANDARD STREQUAL "11" ) + kokkos_set_cxx_standard_feature(11) + SET(KOKKOS_ENABLE_CXX11 ON) + SET(KOKKOS_CXX_INTERMEDIATE_STANDARD "11") +ELSEIF(KOKKOS_CXX_STANDARD STREQUAL "14") + kokkos_set_cxx_standard_feature(14) + SET(KOKKOS_CXX_INTERMEDIATE_STANDARD "1Y") + SET(KOKKOS_ENABLE_CXX14 ON) +ELSEIF(KOKKOS_CXX_STANDARD STREQUAL "17") + kokkos_set_cxx_standard_feature(17) + SET(KOKKOS_CXX_INTERMEDIATE_STANDARD "1Z") + SET(KOKKOS_ENABLE_CXX17 ON) +ELSEIF(KOKKOS_CXX_STANDARD STREQUAL "20") + kokkos_set_cxx_standard_feature(20) + SET(KOKKOS_CXX_INTERMEDIATE_STANDARD "2A") + SET(KOKKOS_ENABLE_CXX20 ON) +ELSEIF(KOKKOS_CXX_STANDARD STREQUAL "98") + MESSAGE(FATAL_ERROR "Kokkos requires C++11 or newer!") +ELSE() + MESSAGE(FATAL_ERROR "Unknown C++ standard ${KOKKOS_CXX_STANDARD} - must be 11, 14, 17, or 20") +ENDIF() + + + +# Enforce that extensions are turned off for nvcc_wrapper. +# For compiling CUDA code using nvcc_wrapper, we will use the host compiler's +# flags for turning on C++11. Since for compiler ID and versioning purposes +# CMake recognizes the host compiler when calling nvcc_wrapper, this just +# works. Both NVCC and nvcc_wrapper only recognize '-std=c++11' which means +# that we can only use host compilers for CUDA builds that use those flags. +# It also means that extensions (gnu++11) can't be turned on for CUDA builds. + +IF(KOKKOS_CXX_COMPILER_ID STREQUAL NVIDIA) + IF(NOT DEFINED CMAKE_CXX_EXTENSIONS) + SET(CMAKE_CXX_EXTENSIONS OFF) + ELSEIF(CMAKE_CXX_EXTENSIONS) + MESSAGE(FATAL_ERROR "NVCC doesn't support C++ extensions. Set -DCMAKE_CXX_EXTENSIONS=OFF") + ENDIF() +ENDIF() + +IF(KOKKOS_ENABLE_CUDA) + # ENFORCE that the compiler can compile CUDA code. + IF(KOKKOS_CXX_COMPILER_ID STREQUAL Clang) + IF(KOKKOS_CXX_COMPILER_VERSION VERSION_LESS 4.0.0) + MESSAGE(FATAL_ERROR "Compiling CUDA code directly with Clang requires version 4.0.0 or higher.") + ENDIF() + IF(NOT DEFINED CMAKE_CXX_EXTENSIONS) + SET(CMAKE_CXX_EXTENSIONS OFF) + ELSEIF(CMAKE_CXX_EXTENSIONS) + MESSAGE(FATAL_ERROR "Compiling CUDA code with clang doesn't support C++ extensions. Set -DCMAKE_CXX_EXTENSIONS=OFF") + ENDIF() + ELSEIF(NOT KOKKOS_CXX_COMPILER_ID STREQUAL NVIDIA) + MESSAGE(FATAL_ERROR "Invalid compiler for CUDA. The compiler must be nvcc_wrapper or Clang, but compiler ID was ${KOKKOS_CXX_COMPILER_ID}") + ENDIF() +ENDIF() + +IF (NOT KOKKOS_CXX_STANDARD_FEATURE) + #we need to pick the C++ flags ourselves + UNSET(CMAKE_CXX_STANDARD) + UNSET(CMAKE_CXX_STANDARD CACHE) + IF(KOKKOS_CXX_COMPILER_ID STREQUAL Cray) + INCLUDE(${KOKKOS_SRC_PATH}/cmake/cray.cmake) + kokkos_set_cray_flags(${KOKKOS_CXX_STANDARD} ${KOKKOS_CXX_INTERMEDIATE_STANDARD}) + ELSEIF(KOKKOS_CXX_COMPILER_ID STREQUAL PGI) + INCLUDE(${KOKKOS_SRC_PATH}/cmake/pgi.cmake) + kokkos_set_pgi_flags(${KOKKOS_CXX_STANDARD} ${KOKKOS_CXX_INTERMEDIATE_STANDARD}) + ELSEIF(KOKKOS_CXX_COMPILER_ID STREQUAL Intel) + INCLUDE(${KOKKOS_SRC_PATH}/cmake/intel.cmake) + kokkos_set_intel_flags(${KOKKOS_CXX_STANDARD} ${KOKKOS_CXX_INTERMEDIATE_STANDARD}) + ELSE() + INCLUDE(${KOKKOS_SRC_PATH}/cmake/gnu.cmake) + kokkos_set_gnu_flags(${KOKKOS_CXX_STANDARD} ${KOKKOS_CXX_INTERMEDIATE_STANDARD}) + ENDIF() + #check that the compiler accepts the C++ standard flag + INCLUDE(CheckCXXCompilerFlag) + IF (DEFINED CXX_STD_FLAGS_ACCEPTED) + UNSET(CXX_STD_FLAGS_ACCEPTED CACHE) + ENDIF() + CHECK_CXX_COMPILER_FLAG(${KOKKOS_CXX_STANDARD_FLAG} CXX_STD_FLAGS_ACCEPTED) + IF (NOT CXX_STD_FLAGS_ACCEPTED) + CHECK_CXX_COMPILER_FLAG(${KOKKOS_CXX_INTERMEDIATE_STANDARD_FLAG} CXX_INT_STD_FLAGS_ACCEPTED) + IF (NOT CXX_INT_STD_FLAGS_ACCEPTED) + MESSAGE(FATAL_ERROR "${KOKKOS_CXX_COMPILER_ID} did not accept ${KOKKOS_CXX_STANDARD_FLAG} or ${KOKKOS_CXX_INTERMEDIATE_STANDARD_FLAG}. You likely need to reduce the level of the C++ standard from ${KOKKOS_CXX_STANDARD}") + ENDIF() + SET(KOKKOS_CXX_STANDARD_FLAG ${KOKKOS_CXX_INTERMEDIATE_STANDARD_FLAG}) + ENDIF() + MESSAGE(STATUS "Compiler features not supported, but ${KOKKOS_CXX_COMPILER_ID} accepts ${KOKKOS_CXX_STANDARD_FLAG}") +ENDIF() + + + + diff --git a/lib/kokkos/cmake/kokkos_tpls.cmake b/lib/kokkos/cmake/kokkos_tpls.cmake new file mode 100644 index 0000000000..181a497d52 --- /dev/null +++ b/lib/kokkos/cmake/kokkos_tpls.cmake @@ -0,0 +1,47 @@ +KOKKOS_CFG_DEPENDS(TPLS OPTIONS) +KOKKOS_CFG_DEPENDS(TPLS DEVICES) + +FUNCTION(KOKKOS_TPL_OPTION PKG DEFAULT) + KOKKOS_ENABLE_OPTION(${PKG} ${DEFAULT} "Whether to enable the ${PKG} library") + KOKKOS_OPTION(${PKG}_DIR "" PATH "Location of ${PKG} library") + SET(KOKKOS_ENABLE_${PKG} ${KOKKOS_ENABLE_${PKG}} PARENT_SCOPE) + SET(KOKKOS_${PKG}_DIR ${KOKKOS_${PKG}_DIR} PARENT_SCOPE) +ENDFUNCTION() + +KOKKOS_TPL_OPTION(HWLOC Off) +KOKKOS_TPL_OPTION(LIBNUMA Off) +KOKKOS_TPL_OPTION(MEMKIND Off) +KOKKOS_TPL_OPTION(CUDA Off) +KOKKOS_TPL_OPTION(LIBRT Off) +KOKKOS_TPL_OPTION(LIBDL On) + +IF(Trilinos_ENABLE_Kokkos AND TPL_ENABLE_HPX) +SET(HPX_DEFAULT ON) +ELSE() +SET(HPX_DEFAULT OFF) +ENDIF() +KOKKOS_TPL_OPTION(HPX ${HPX_DEFAULT}) + +IF(Trilinos_ENABLE_Kokkos AND TPL_ENABLE_PTHREAD) +SET(PTHREAD_DEFAULT ON) +ELSE() +SET(PTHREAD_DEFAULT OFF) +ENDIF() +KOKKOS_TPL_OPTION(PTHREAD ${PTHREAD_DEFAULT}) + + +#Make sure we use our local FindKokkosCuda.cmake +KOKKOS_IMPORT_TPL(HPX INTERFACE) +KOKKOS_IMPORT_TPL(CUDA INTERFACE) +KOKKOS_IMPORT_TPL(HWLOC) +KOKKOS_IMPORT_TPL(LIBNUMA) +KOKKOS_IMPORT_TPL(LIBRT) +KOKKOS_IMPORT_TPL(LIBDL) +KOKKOS_IMPORT_TPL(MEMKIND) +KOKKOS_IMPORT_TPL(PTHREAD INTERFACE) + +#Convert list to newlines (which CMake doesn't always like in cache variables) +STRING(REPLACE ";" "\n" KOKKOS_TPL_EXPORT_TEMP "${KOKKOS_TPL_EXPORTS}") +#Convert to a regular variable +UNSET(KOKKOS_TPL_EXPORTS CACHE) +SET(KOKKOS_TPL_EXPORTS ${KOKKOS_TPL_EXPORT_TEMP}) diff --git a/lib/kokkos/cmake/kokkos_tribits.cmake b/lib/kokkos/cmake/kokkos_tribits.cmake new file mode 100644 index 0000000000..d2317d2446 --- /dev/null +++ b/lib/kokkos/cmake/kokkos_tribits.cmake @@ -0,0 +1,392 @@ +#These are tribits wrappers only ever called by Kokkos itself + +INCLUDE(CMakeParseArguments) +INCLUDE(CTest) +INCLUDE(GNUInstallDirs) + +MESSAGE(STATUS "The project name is: ${PROJECT_NAME}") + +#Leave this here for now - but only do for tribits +#This breaks the standalone CMake +IF (KOKKOS_HAS_TRILINOS) + IF(NOT DEFINED ${PROJECT_NAME}_ENABLE_OpenMP) + SET(${PROJECT_NAME}_ENABLE_OpenMP OFF) + ENDIF() + + IF(NOT DEFINED ${PROJECT_NAME}_ENABLE_HPX) + SET(${PROJECT_NAME}_ENABLE_HPX OFF) + ENDIF() + + IF(NOT DEFINED ${PROJECT_NAME}_ENABLE_DEBUG) + SET(${PROJECT_NAME}_ENABLE_DEBUG OFF) + ENDIF() + + IF(NOT DEFINED ${PROJECT_NAME}_ENABLE_CXX11) + SET(${PROJECT_NAME}_ENABLE_CXX11 ON) + ENDIF() + + IF(NOT DEFINED ${PROJECT_NAME}_ENABLE_TESTS) + SET(${PROJECT_NAME}_ENABLE_TESTS OFF) + ENDIF() + + IF(NOT DEFINED TPL_ENABLE_Pthread) + SET(TPL_ENABLE_Pthread OFF) + ENDIF() +ENDIF() + +MACRO(KOKKOS_SUBPACKAGE NAME) + if (KOKKOS_HAS_TRILINOS) + TRIBITS_SUBPACKAGE(${NAME}) + else() + SET(PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + SET(PARENT_PACKAGE_NAME ${PACKAGE_NAME}) + SET(PACKAGE_NAME ${PACKAGE_NAME}${NAME}) + STRING(TOUPPER ${PACKAGE_NAME} PACKAGE_NAME_UC) + SET(${PACKAGE_NAME}_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + endif() +ENDMACRO() + +MACRO(KOKKOS_SUBPACKAGE_POSTPROCESS) + if (KOKKOS_HAS_TRILINOS) + TRIBITS_SUBPACKAGE_POSTPROCESS() + endif() +ENDMACRO() + +MACRO(KOKKOS_PACKAGE_DECL) + + if (KOKKOS_HAS_TRILINOS) + TRIBITS_PACKAGE_DECL(Kokkos) + else() + SET(PACKAGE_NAME Kokkos) + SET(${PACKAGE_NAME}_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + STRING(TOUPPER ${PACKAGE_NAME} PACKAGE_NAME_UC) + endif() + + #SET(TRIBITS_DEPS_DIR "${CMAKE_SOURCE_DIR}/cmake/deps") + #FILE(GLOB TPLS_FILES "${TRIBITS_DEPS_DIR}/*.cmake") + #FOREACH(TPL_FILE ${TPLS_FILES}) + # TRIBITS_PROCESS_TPL_DEP_FILE(${TPL_FILE}) + #ENDFOREACH() + +ENDMACRO() + + +MACRO(KOKKOS_PROCESS_SUBPACKAGES) + if (KOKKOS_HAS_TRILINOS) + TRIBITS_PROCESS_SUBPACKAGES() + else() + ADD_SUBDIRECTORY(core) + ADD_SUBDIRECTORY(containers) + ADD_SUBDIRECTORY(algorithms) + ADD_SUBDIRECTORY(example) + endif() +ENDMACRO() + +MACRO(KOKKOS_PACKAGE_DEF) + if (KOKKOS_HAS_TRILINOS) + TRIBITS_PACKAGE_DEF() + else() + #do nothing + endif() +ENDMACRO() + +MACRO(KOKKOS_INTERNAL_ADD_LIBRARY_INSTALL LIBRARY_NAME) + KOKKOS_LIB_TYPE(${LIBRARY_NAME} INCTYPE) + TARGET_INCLUDE_DIRECTORIES(${LIBRARY_NAME} ${INCTYPE} $) + + INSTALL( + TARGETS ${LIBRARY_NAME} + EXPORT ${PROJECT_NAME} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT ${PACKAGE_NAME} + ) + + INSTALL( + TARGETS ${LIBRARY_NAME} + EXPORT KokkosTargets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) + + VERIFY_EMPTY(KOKKOS_ADD_LIBRARY ${PARSE_UNPARSED_ARGUMENTS}) +ENDMACRO() + +FUNCTION(KOKKOS_ADD_EXECUTABLE EXE_NAME) + if (KOKKOS_HAS_TRILINOS) + TRIBITS_ADD_EXECUTABLE(${EXE_NAME} ${ARGN}) + else() + CMAKE_PARSE_ARGUMENTS(PARSE + "TESTONLY" + "" + "SOURCES;TESTONLYLIBS" + ${ARGN}) + + ADD_EXECUTABLE(${EXE_NAME} ${PARSE_SOURCES}) + IF (PARSE_TESTONLYLIBS) + TARGET_LINK_LIBRARIES(${EXE_NAME} ${PARSE_TESTONLYLIBS}) + ENDIF() + VERIFY_EMPTY(KOKKOS_ADD_EXECUTABLE ${PARSE_UNPARSED_ARGUMENTS}) + endif() +ENDFUNCTION() + +IF(NOT TARGET check) + ADD_CUSTOM_TARGET(check COMMAND ${CMAKE_CTEST_COMMAND} -VV -C ${CMAKE_CFG_INTDIR}) +ENDIF() + + +FUNCTION(KOKKOS_ADD_EXECUTABLE_AND_TEST ROOT_NAME) +IF (KOKKOS_HAS_TRILINOS) + TRIBITS_ADD_EXECUTABLE_AND_TEST( + ${ROOT_NAME} + TESTONLYLIBS kokkos_gtest + ${ARGN} + NUM_MPI_PROCS 1 + COMM serial mpi + FAIL_REGULAR_EXPRESSION " FAILED " + ) +ELSE() + CMAKE_PARSE_ARGUMENTS(PARSE + "" + "" + "SOURCES;CATEGORIES" + ${ARGN}) + VERIFY_EMPTY(KOKKOS_ADD_EXECUTABLE_AND_TEST ${PARSE_UNPARSED_ARGUMENTS}) + SET(EXE_NAME ${PACKAGE_NAME}_${ROOT_NAME}) + KOKKOS_ADD_TEST_EXECUTABLE(${EXE_NAME} + SOURCES ${PARSE_SOURCES} + ) + KOKKOS_ADD_TEST(NAME ${ROOT_NAME} + EXE ${EXE_NAME} + FAIL_REGULAR_EXPRESSION " FAILED " + ) +ENDIF() +ENDFUNCTION() + +MACRO(KOKKOS_SETUP_BUILD_ENVIRONMENT) + INCLUDE(${KOKKOS_SRC_PATH}/cmake/kokkos_compiler_id.cmake) + INCLUDE(${KOKKOS_SRC_PATH}/cmake/kokkos_enable_devices.cmake) + INCLUDE(${KOKKOS_SRC_PATH}/cmake/kokkos_enable_options.cmake) + INCLUDE(${KOKKOS_SRC_PATH}/cmake/kokkos_test_cxx_std.cmake) + INCLUDE(${KOKKOS_SRC_PATH}/cmake/kokkos_arch.cmake) + IF (NOT KOKKOS_HAS_TRILINOS) + SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${Kokkos_SOURCE_DIR}/cmake/Modules/") + INCLUDE(${KOKKOS_SRC_PATH}/cmake/kokkos_tpls.cmake) + ENDIF() + INCLUDE(${KOKKOS_SRC_PATH}/cmake/kokkos_corner_cases.cmake) +ENDMACRO() + +MACRO(KOKKOS_ADD_TEST_EXECUTABLE EXE_NAME) + CMAKE_PARSE_ARGUMENTS(PARSE + "" + "" + "SOURCES" + ${ARGN}) + KOKKOS_ADD_EXECUTABLE(${EXE_NAME} + SOURCES ${PARSE_SOURCES} + ${PARSE_UNPARSED_ARGUMENTS} + TESTONLYLIBS kokkos_gtest + ) + IF (NOT KOKKOS_HAS_TRILINOS) + ADD_DEPENDENCIES(check ${EXE_NAME}) + ENDIF() +ENDMACRO() + +MACRO(KOKKOS_PACKAGE_POSTPROCESS) + if (KOKKOS_HAS_TRILINOS) + TRIBITS_PACKAGE_POSTPROCESS() + endif() +ENDMACRO() + +FUNCTION(KOKKOS_SET_LIBRARY_PROPERTIES LIBRARY_NAME) + CMAKE_PARSE_ARGUMENTS(PARSE + "PLAIN_STYLE" + "" + "" + ${ARGN}) + + IF(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.13") + #great, this works the "right" way + TARGET_LINK_OPTIONS( + ${LIBRARY_NAME} PUBLIC ${KOKKOS_LINK_OPTIONS} + ) + ELSE() + IF (PARSE_PLAIN_STYLE) + TARGET_LINK_LIBRARIES( + ${LIBRARY_NAME} ${KOKKOS_LINK_OPTIONS} + ) + ELSE() + #well, have to do it the wrong way for now + TARGET_LINK_LIBRARIES( + ${LIBRARY_NAME} PUBLIC ${KOKKOS_LINK_OPTIONS} + ) + ENDIF() + ENDIF() + + TARGET_COMPILE_OPTIONS( + ${LIBRARY_NAME} PUBLIC + $<$:${KOKKOS_COMPILE_OPTIONS}> + ) + + IF (KOKKOS_ENABLE_CUDA) + TARGET_COMPILE_OPTIONS( + ${LIBRARY_NAME} + PUBLIC $<$:${KOKKOS_CUDA_OPTIONS}> + ) + SET(NODEDUP_CUDAFE_OPTIONS) + FOREACH(OPT ${KOKKOS_CUDAFE_OPTIONS}) + LIST(APPEND NODEDUP_CUDAFE_OPTIONS -Xcudafe ${OPT}) + ENDFOREACH() + TARGET_COMPILE_OPTIONS( + ${LIBRARY_NAME} + PUBLIC $<$:${NODEDUP_CUDAFE_OPTIONS}> + ) + ENDIF() + + LIST(LENGTH KOKKOS_XCOMPILER_OPTIONS XOPT_LENGTH) + IF (XOPT_LENGTH GREATER 1) + MESSAGE(FATAL_ERROR "CMake deduplication does not allow multiple -Xcompiler flags (${KOKKOS_XCOMPILER_OPTIONS}): will require Kokkos to upgrade to minimum 3.12") + ENDIF() + IF(KOKKOS_XCOMPILER_OPTIONS) + SET(NODEDUP_XCOMPILER_OPTIONS) + FOREACH(OPT ${KOKKOS_XCOMPILER_OPTIONS}) + #I have to do this for now because we can't guarantee 3.12 support + #I really should do this with the shell option + LIST(APPEND NODEDUP_XCOMPILER_OPTIONS -Xcompiler) + LIST(APPEND NODEDUP_XCOMPILER_OPTIONS ${OPT}) + ENDFOREACH() + TARGET_COMPILE_OPTIONS( + ${LIBRARY_NAME} + PUBLIC $<$:${NODEDUP_XCOMPILER_OPTIONS}> + ) + ENDIF() + + IF (KOKKOS_CXX_STANDARD_FEATURE) + #GREAT! I can do this the right way + TARGET_COMPILE_FEATURES(${LIBRARY_NAME} PUBLIC ${KOKKOS_CXX_STANDARD_FEATURE}) + IF (NOT KOKKOS_USE_CXX_EXTENSIONS) + SET_TARGET_PROPERTIES(${LIBRARY_NAME} PROPERTIES CXX_EXTENSIONS OFF) + ENDIF() + ELSE() + #OH, well, no choice but the wrong way + TARGET_COMPILE_OPTIONS(${LIBRARY_NAME} PUBLIC ${KOKKOS_CXX_STANDARD_FLAG}) + ENDIF() +ENDFUNCTION() + +FUNCTION(KOKKOS_INTERNAL_ADD_LIBRARY LIBRARY_NAME) + CMAKE_PARSE_ARGUMENTS(PARSE + "STATIC;SHARED" + "" + "HEADERS;SOURCES" + ${ARGN}) + + IF(PARSE_HEADERS) + LIST(REMOVE_DUPLICATES PARSE_HEADERS) + ENDIF() + IF(PARSE_SOURCES) + LIST(REMOVE_DUPLICATES PARSE_SOURCES) + ENDIF() + + ADD_LIBRARY( + ${LIBRARY_NAME} + ${PARSE_HEADERS} + ${PARSE_SOURCES} + ) + + KOKKOS_INTERNAL_ADD_LIBRARY_INSTALL(${LIBRARY_NAME}) + + INSTALL( + FILES ${PARSE_HEADERS} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + COMPONENT ${PACKAGE_NAME} + ) + + #In case we are building in-tree, add an alias name + #that matches the install Kokkos:: name + ADD_LIBRARY(Kokkos::${LIBRARY_NAME} ALIAS ${LIBRARY_NAME}) +ENDFUNCTION() + +FUNCTION(KOKKOS_ADD_LIBRARY LIBRARY_NAME) + IF (KOKKOS_HAS_TRILINOS) + TRIBITS_ADD_LIBRARY(${LIBRARY_NAME} ${ARGN}) + #Stolen from Tribits - it can add prefixes + SET(TRIBITS_LIBRARY_NAME_PREFIX "${${PROJECT_NAME}_LIBRARY_NAME_PREFIX}") + SET(TRIBITS_LIBRARY_NAME ${TRIBITS_LIBRARY_NAME_PREFIX}${LIBRARY_NAME}) + #Tribits has way too much techinical debt and baggage to even + #allow PUBLIC target_compile_options to be used. It forces C++ flags on projects + #as a giant blob of space-separated strings. We end up with duplicated + #flags between the flags implicitly forced on Kokkos-dependent and those Kokkos + #has in its public INTERFACE_COMPILE_OPTIONS. + #These do NOT get de-deduplicated because Tribits + #creates flags as a giant monolithic space-separated string + #Do not set any transitive properties and keep everything working as before + #KOKKOS_SET_LIBRARY_PROPERTIES(${TRIBITS_LIBRARY_NAME} PLAIN_STYLE) + ELSE() + KOKKOS_INTERNAL_ADD_LIBRARY( + ${LIBRARY_NAME} ${ARGN}) + KOKKOS_SET_LIBRARY_PROPERTIES(${LIBRARY_NAME}) + ENDIF() +ENDFUNCTION() + +FUNCTION(KOKKOS_ADD_INTERFACE_LIBRARY NAME) +IF (KOKKOS_HAS_TRILINOS) + TRIBITS_ADD_LIBRARY(${NAME} ${ARGN}) +ELSE() + CMAKE_PARSE_ARGUMENTS(PARSE + "" + "" + "HEADERS;SOURCES" + ${ARGN} + ) + + ADD_LIBRARY(${NAME} INTERFACE) + KOKKOS_INTERNAL_ADD_LIBRARY_INSTALL(${NAME}) + + INSTALL( + FILES ${PARSE_HEADERS} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) + + INSTALL( + FILES ${PARSE_HEADERS} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + COMPONENT ${PACKAGE_NAME} + ) +ENDIF() +ENDFUNCTION() + +FUNCTION(KOKKOS_LIB_INCLUDE_DIRECTORIES TARGET) + IF(KOKKOS_HAS_TRILINOS) + #ignore the target, tribits doesn't do anything directly with targets + TRIBITS_INCLUDE_DIRECTORIES(${ARGN}) + ELSE() #append to a list for later + KOKKOS_LIB_TYPE(${TARGET} INCTYPE) + FOREACH(DIR ${ARGN}) + TARGET_INCLUDE_DIRECTORIES(${TARGET} ${INCTYPE} $) + ENDFOREACH() + ENDIF() +ENDFUNCTION() + +FUNCTION(KOKKOS_LIB_COMPILE_OPTIONS TARGET) + IF(KOKKOS_HAS_TRILINOS) + #don't trust tribits to do this correctly + KOKKOS_TARGET_COMPILE_OPTIONS(${TARGET} ${ARGN}) + ELSE() + KOKKOS_LIB_TYPE(${TARGET} INCTYPE) + KOKKOS_TARGET_COMPILE_OPTIONS(${${PROJECT_NAME}_LIBRARY_NAME_PREFIX}${TARGET} ${INCTYPE} ${ARGN}) + ENDIF() +ENDFUNCTION() + +MACRO(KOKKOS_ADD_TEST_DIRECTORIES) + IF (KOKKOS_HAS_TRILINOS) + TRIBITS_ADD_TEST_DIRECTORIES(${ARGN}) + ELSE() + IF(KOKKOS_ENABLE_TESTS) + FOREACH(TEST_DIR ${ARGN}) + ADD_SUBDIRECTORY(${TEST_DIR}) + ENDFOREACH() + ENDIF() + ENDIF() +ENDMACRO() diff --git a/lib/kokkos/cmake/pgi.cmake b/lib/kokkos/cmake/pgi.cmake new file mode 100644 index 0000000000..e98e849558 --- /dev/null +++ b/lib/kokkos/cmake/pgi.cmake @@ -0,0 +1,8 @@ + +function(kokkos_set_pgi_flags full_standard int_standard) + STRING(TOLOWER ${full_standard} FULL_LC_STANDARD) + STRING(TOLOWER ${int_standard} INT_LC_STANDARD) + SET(KOKKOS_CXX_STANDARD_FLAG "--c++${FULL_LC_STANDARD}" PARENT_SCOPE) + SET(KOKKOS_CXX_INTERMDIATE_STANDARD_FLAG "--c++${INT_LC_STANDARD}" PARENT_SCOPE) +endfunction() + diff --git a/lib/kokkos/cmake/tpls/FindTPLCUSPARSE.cmake b/lib/kokkos/cmake/tpls/FindTPLCUSPARSE.cmake index aad1e2bad7..b8cee04804 100644 --- a/lib/kokkos/cmake/tpls/FindTPLCUSPARSE.cmake +++ b/lib/kokkos/cmake/tpls/FindTPLCUSPARSE.cmake @@ -67,7 +67,7 @@ ELSE() IF(CUDA_cusparse_LIBRARY STREQUAL "CUDA_cusparse_LIBRARY-NOTFOUND") MESSAGE(FATAL_ERROR "\nCUSPARSE: could not find cuspasre library.") ENDIF() - ENDIF(CMAKE_VERSION VERSION_LESS "2.8.8") + ENDIF() GLOBAL_SET(TPL_CUSPARSE_LIBRARY_DIRS) GLOBAL_SET(TPL_CUSPARSE_INCLUDE_DIRS ${TPL_CUDA_INCLUDE_DIRS}) GLOBAL_SET(TPL_CUSPARSE_LIBRARIES ${CUDA_cusparse_LIBRARY}) diff --git a/lib/kokkos/cmake/tpls/FindTPLHWLOC.cmake b/lib/kokkos/cmake/tpls/FindTPLHWLOC.cmake index 715b3e9bde..a4c55e1d7b 100644 --- a/lib/kokkos/cmake/tpls/FindTPLHWLOC.cmake +++ b/lib/kokkos/cmake/tpls/FindTPLHWLOC.cmake @@ -64,7 +64,7 @@ # Version: 1.3 # -TRIBITS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES( HWLOC +KOKKOS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES( HWLOC REQUIRED_HEADERS hwloc.h REQUIRED_LIBS_NAMES "hwloc" ) diff --git a/lib/kokkos/cmake/tpls/FindTPLPthread.cmake b/lib/kokkos/cmake/tpls/FindTPLPthread.cmake index fc401d7543..4dc1a87e18 100644 --- a/lib/kokkos/cmake/tpls/FindTPLPthread.cmake +++ b/lib/kokkos/cmake/tpls/FindTPLPthread.cmake @@ -75,7 +75,7 @@ IF(USE_THREADS) SET(TPL_Pthread_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}") SET(TPL_Pthread_LIBRARY_DIRS "") ELSE() - TRIBITS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES( Pthread + KOKKOS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES( Pthread REQUIRED_HEADERS pthread.h REQUIRED_LIBS_NAMES pthread ) diff --git a/lib/kokkos/cmake/tpls/FindTPLQTHREADS.cmake b/lib/kokkos/cmake/tpls/FindTPLQTHREADS.cmake deleted file mode 100644 index c312f2590b..0000000000 --- a/lib/kokkos/cmake/tpls/FindTPLQTHREADS.cmake +++ /dev/null @@ -1,69 +0,0 @@ -# @HEADER -# ************************************************************************ -# -# Trilinos: An Object-Oriented Solver Framework -# Copyright (2001) Sandia Corporation -# -# -# Copyright (2001) Sandia Corporation. Under the terms of Contract -# DE-AC04-94AL85000, there is a non-exclusive license for use of this -# work by or on behalf of the U.S. Government. Export of this program -# may require a license from the United States Government. -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the Corporation nor the names of the -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY -# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# NOTICE: The United States Government is granted for itself and others -# acting on its behalf a paid-up, nonexclusive, irrevocable worldwide -# license in this data to reproduce, prepare derivative works, and -# perform publicly and display publicly. Beginning five (5) years from -# July 25, 2001, the United States Government is granted for itself and -# others acting on its behalf a paid-up, nonexclusive, irrevocable -# worldwide license in this data to reproduce, prepare derivative works, -# distribute copies to the public, perform publicly and display -# publicly, and to permit others to do so. -# -# NEITHER THE UNITED STATES GOVERNMENT, NOR THE UNITED STATES DEPARTMENT -# OF ENERGY, NOR SANDIA CORPORATION, NOR ANY OF THEIR EMPLOYEES, MAKES -# ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL LIABILITY OR -# RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR USEFULNESS OF ANY -# INFORMATION, APPARATUS, PRODUCT, OR PROCESS DISCLOSED, OR REPRESENTS -# THAT ITS USE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS. -# -# ************************************************************************ -# @HEADER - - -#----------------------------------------------------------------------------- -# Hardware locality detection and control library. -# -# Acquisition information: -# Date checked: July 2014 -# Checked by: H. Carter Edwards -# Source: https://code.google.com/p/qthreads -# - -TRIBITS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES( QTHREADS - REQUIRED_HEADERS qthread.h - REQUIRED_LIBS_NAMES "qthread" - ) diff --git a/lib/kokkos/cmake/tribits.cmake b/lib/kokkos/cmake/tribits.cmake deleted file mode 100644 index 1f467f0662..0000000000 --- a/lib/kokkos/cmake/tribits.cmake +++ /dev/null @@ -1,531 +0,0 @@ -INCLUDE(CMakeParseArguments) -INCLUDE(CTest) - -cmake_policy(SET CMP0054 NEW) - -MESSAGE(STATUS "The project name is: ${PROJECT_NAME}") - -IF(NOT DEFINED ${PROJECT_NAME}_ENABLE_OpenMP) - SET(${PROJECT_NAME}_ENABLE_OpenMP OFF) -ENDIF() - -IF(NOT DEFINED ${PROJECT_NAME}_ENABLE_HPX) - SET(${PROJECT_NAME}_ENABLE_HPX OFF) -ENDIF() - -IF(NOT DEFINED ${PROJECT_NAME}_ENABLE_DEBUG) - SET(${PROJECT_NAME}_ENABLE_DEBUG OFF) -ENDIF() - -IF(NOT DEFINED ${PROJECT_NAME}_ENABLE_CXX11) - SET(${PROJECT_NAME}_ENABLE_CXX11 ON) -ENDIF() - -IF(NOT DEFINED ${PROJECT_NAME}_ENABLE_TESTS) - SET(${PROJECT_NAME}_ENABLE_TESTS OFF) -ENDIF() - -IF(NOT DEFINED TPL_ENABLE_Pthread) - SET(TPL_ENABLE_Pthread OFF) -ENDIF() - -FUNCTION(ASSERT_DEFINED VARS) - FOREACH(VAR ${VARS}) - IF(NOT DEFINED ${VAR}) - MESSAGE(SEND_ERROR "Error, the variable ${VAR} is not defined!") - ENDIF() - ENDFOREACH() -ENDFUNCTION() - -MACRO(GLOBAL_SET VARNAME) - SET(${VARNAME} ${ARGN} CACHE INTERNAL "") -ENDMACRO() - -MACRO(PREPEND_GLOBAL_SET VARNAME) - ASSERT_DEFINED(${VARNAME}) - GLOBAL_SET(${VARNAME} ${ARGN} ${${VARNAME}}) -ENDMACRO() - -#FUNCTION(REMOVE_GLOBAL_DUPLICATES VARNAME) -# ASSERT_DEFINED(${VARNAME}) -# IF (${VARNAME}) -# SET(TMP ${${VARNAME}}) -# LIST(REMOVE_DUPLICATES TMP) -# GLOBAL_SET(${VARNAME} ${TMP}) -# ENDIF() -#ENDFUNCTION() - -#MACRO(TRIBITS_ADD_OPTION_AND_DEFINE USER_OPTION_NAME MACRO_DEFINE_NAME DOCSTRING DEFAULT_VALUE) -# MESSAGE(STATUS "TRIBITS_ADD_OPTION_AND_DEFINE: '${USER_OPTION_NAME}' '${MACRO_DEFINE_NAME}' '${DEFAULT_VALUE}'") -# SET( ${USER_OPTION_NAME} "${DEFAULT_VALUE}" CACHE BOOL "${DOCSTRING}" ) -# IF(NOT ${MACRO_DEFINE_NAME} STREQUAL "") -# IF(${USER_OPTION_NAME}) -# GLOBAL_SET(${MACRO_DEFINE_NAME} ON) -# ELSE() -# GLOBAL_SET(${MACRO_DEFINE_NAME} OFF) -# ENDIF() -# ENDIF() -#ENDMACRO() - -FUNCTION(TRIBITS_CONFIGURE_FILE PACKAGE_NAME_CONFIG_FILE) - - # Configure the file - CONFIGURE_FILE( - ${PACKAGE_SOURCE_DIR}/cmake/${PACKAGE_NAME_CONFIG_FILE}.in - ${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME_CONFIG_FILE} - ) - -ENDFUNCTION() - -#MACRO(TRIBITS_ADD_DEBUG_OPTION) -# TRIBITS_ADD_OPTION_AND_DEFINE( -# ${PROJECT_NAME}_ENABLE_DEBUG -# HAVE_${PROJECT_NAME_UC}_DEBUG -# "Enable a host of runtime debug checking." -# OFF -# ) -#ENDMACRO() - - -MACRO(TRIBITS_ADD_TEST_DIRECTORIES) - IF(${${PROJECT_NAME}_ENABLE_TESTS}) - FOREACH(TEST_DIR ${ARGN}) - ADD_SUBDIRECTORY(${TEST_DIR}) - ENDFOREACH() - ENDIF() -ENDMACRO() - -MACRO(TRIBITS_ADD_EXAMPLE_DIRECTORIES) - IF(${PACKAGE_NAME}_ENABLE_EXAMPLES OR ${PARENT_PACKAGE_NAME}_ENABLE_EXAMPLES) - FOREACH(EXAMPLE_DIR ${ARGN}) - ADD_SUBDIRECTORY(${EXAMPLE_DIR}) - ENDFOREACH() - ENDIF() -ENDMACRO() - - -function(INCLUDE_DIRECTORIES) - cmake_parse_arguments(INCLUDE_DIRECTORIES "REQUIRED_DURING_INSTALLATION_TESTING" "" "" ${ARGN}) - _INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES_UNPARSED_ARGUMENTS}) -endfunction() - - -MACRO(TARGET_TRANSFER_PROPERTY TARGET_NAME PROP_IN PROP_OUT) - SET(PROP_VALUES) - FOREACH(TARGET_X ${ARGN}) - LIST(APPEND PROP_VALUES "$") - ENDFOREACH() - SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES ${PROP_OUT} "${PROP_VALUES}") -ENDMACRO() - -MACRO(ADD_INTERFACE_LIBRARY LIB_NAME) - FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp "") - ADD_LIBRARY(${LIB_NAME} STATIC ${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp) - SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES INTERFACE TRUE) -ENDMACRO() - -# Older versions of cmake does not make include directories transitive -MACRO(TARGET_LINK_AND_INCLUDE_LIBRARIES TARGET_NAME) - TARGET_LINK_LIBRARIES(${TARGET_NAME} LINK_PUBLIC ${ARGN}) - FOREACH(DEP_LIB ${ARGN}) - TARGET_INCLUDE_DIRECTORIES(${TARGET_NAME} PUBLIC $) - TARGET_INCLUDE_DIRECTORIES(${TARGET_NAME} PUBLIC $) - ENDFOREACH() -ENDMACRO() - -FUNCTION(TRIBITS_ADD_LIBRARY LIBRARY_NAME) - - SET(options STATIC SHARED TESTONLY NO_INSTALL_LIB_OR_HEADERS CUDALIBRARY) - SET(oneValueArgs) - SET(multiValueArgs HEADERS HEADERS_INSTALL_SUBDIR NOINSTALLHEADERS SOURCES DEPLIBS IMPORTEDLIBS DEFINES ADDED_LIB_TARGET_NAME_OUT) - - CMAKE_PARSE_ARGUMENTS(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - IF(PARSE_HEADERS) - LIST(REMOVE_DUPLICATES PARSE_HEADERS) - ENDIF() - IF(PARSE_SOURCES) - LIST(REMOVE_DUPLICATES PARSE_SOURCES) - ENDIF() - - # Local variable to hold all of the libraries that will be directly linked - # to this library. - SET(LINK_LIBS ${${PACKAGE_NAME}_DEPS}) - - # Add dependent libraries passed directly in - - IF (PARSE_IMPORTEDLIBS) - LIST(APPEND LINK_LIBS ${PARSE_IMPORTEDLIBS}) - ENDIF() - - IF (PARSE_DEPLIBS) - LIST(APPEND LINK_LIBS ${PARSE_DEPLIBS}) - ENDIF() - - # Add the library and all the dependencies - - IF (PARSE_DEFINES) - ADD_DEFINITIONS(${PARSE_DEFINES}) - ENDIF() - - IF (PARSE_STATIC) - SET(STATIC_KEYWORD "STATIC") - ELSE() - SET(STATIC_KEYWORD) - ENDIF() - - IF (PARSE_SHARED) - SET(SHARED_KEYWORD "SHARED") - ELSE() - SET(SHARED_KEYWORD) - ENDIF() - - IF (PARSE_TESTONLY) - SET(EXCLUDE_FROM_ALL_KEYWORD "EXCLUDE_FROM_ALL") - ELSE() - SET(EXCLUDE_FROM_ALL_KEYWORD) - ENDIF() - IF (NOT PARSE_CUDALIBRARY) - ADD_LIBRARY( - ${LIBRARY_NAME} - ${STATIC_KEYWORD} - ${SHARED_KEYWORD} - ${EXCLUDE_FROM_ALL_KEYWORD} - ${PARSE_HEADERS} - ${PARSE_NOINSTALLHEADERS} - ${PARSE_SOURCES} - ) - ELSE() - CUDA_ADD_LIBRARY( - ${LIBRARY_NAME} - ${PARSE_HEADERS} - ${PARSE_NOINSTALLHEADERS} - ${PARSE_SOURCES} - ) - ENDIF() - - TARGET_LINK_AND_INCLUDE_LIBRARIES(${LIBRARY_NAME} ${LINK_LIBS}) - - IF (NOT PARSE_TESTONLY OR PARSE_NO_INSTALL_LIB_OR_HEADERS) - - INSTALL( - TARGETS ${LIBRARY_NAME} - EXPORT ${PROJECT_NAME} - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - COMPONENT ${PACKAGE_NAME} - ) - - INSTALL( - FILES ${PARSE_HEADERS} - EXPORT ${PROJECT_NAME} - DESTINATION include - COMPONENT ${PACKAGE_NAME} - ) - - INSTALL( - DIRECTORY ${PARSE_HEADERS_INSTALL_SUBDIR} - EXPORT ${PROJECT_NAME} - DESTINATION include - COMPONENT ${PACKAGE_NAME} - ) - - ENDIF() - - IF (NOT PARSE_TESTONLY) - PREPEND_GLOBAL_SET(${PACKAGE_NAME}_LIBS ${LIBRARY_NAME}) - REMOVE_GLOBAL_DUPLICATES(${PACKAGE_NAME}_LIBS) - ENDIF() - -ENDFUNCTION() - -FUNCTION(TRIBITS_ADD_EXECUTABLE EXE_NAME) - - SET(options NOEXEPREFIX NOEXESUFFIX ADD_DIR_TO_NAME INSTALLABLE TESTONLY) - SET(oneValueArgs ADDED_EXE_TARGET_NAME_OUT) - SET(multiValueArgs SOURCES CATEGORIES HOST XHOST HOSTTYPE XHOSTTYPE DIRECTORY TESTONLYLIBS IMPORTEDLIBS DEPLIBS COMM LINKER_LANGUAGE TARGET_DEFINES DEFINES) - - CMAKE_PARSE_ARGUMENTS(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - IF (PARSE_TARGET_DEFINES) - TARGET_COMPILE_DEFINITIONS(${EXE_NAME} PUBLIC ${PARSE_TARGET_DEFINES}) - ENDIF() - - SET(LINK_LIBS PACKAGE_${PACKAGE_NAME}) - - IF (PARSE_TESTONLYLIBS) - LIST(APPEND LINK_LIBS ${PARSE_TESTONLYLIBS}) - ENDIF() - - IF (PARSE_IMPORTEDLIBS) - LIST(APPEND LINK_LIBS ${PARSE_IMPORTEDLIBS}) - ENDIF() - - SET (EXE_SOURCES) - IF(PARSE_DIRECTORY) - FOREACH( SOURCE_FILE ${PARSE_SOURCES} ) - IF(IS_ABSOLUTE ${SOURCE_FILE}) - SET (EXE_SOURCES ${EXE_SOURCES} ${SOURCE_FILE}) - ELSE() - SET (EXE_SOURCES ${EXE_SOURCES} ${PARSE_DIRECTORY}/${SOURCE_FILE}) - ENDIF() - ENDFOREACH( ) - ELSE() - FOREACH( SOURCE_FILE ${PARSE_SOURCES} ) - SET (EXE_SOURCES ${EXE_SOURCES} ${SOURCE_FILE}) - ENDFOREACH( ) - ENDIF() - - SET(EXE_BINARY_NAME ${EXE_NAME}) - IF(DEFINED PACKAGE_NAME AND NOT PARSE_NOEXEPREFIX) - SET(EXE_BINARY_NAME ${PACKAGE_NAME}_${EXE_BINARY_NAME}) - ENDIF() - - # IF (PARSE_TESTONLY) - # SET(EXCLUDE_FROM_ALL_KEYWORD "EXCLUDE_FROM_ALL") - # ELSE() - # SET(EXCLUDE_FROM_ALL_KEYWORD) - # ENDIF() - ADD_EXECUTABLE(${EXE_BINARY_NAME} ${EXCLUDE_FROM_ALL_KEYWORD} ${EXE_SOURCES}) - - TARGET_LINK_AND_INCLUDE_LIBRARIES(${EXE_BINARY_NAME} ${LINK_LIBS}) - - IF(PARSE_ADDED_EXE_TARGET_NAME_OUT) - SET(${PARSE_ADDED_EXE_TARGET_NAME_OUT} ${EXE_BINARY_NAME} PARENT_SCOPE) - ENDIF() - - IF(PARSE_INSTALLABLE) - INSTALL( - TARGETS ${EXE_BINARY_NAME} - EXPORT ${PROJECT_NAME} - DESTINATION bin - ) - ENDIF() -ENDFUNCTION() - -IF(NOT TARGET check) - ADD_CUSTOM_TARGET(check COMMAND ${CMAKE_CTEST_COMMAND} -VV -C ${CMAKE_CFG_INTDIR}) -ENDIF() - -FUNCTION(TRIBITS_ADD_TEST) -ENDFUNCTION() -FUNCTION(TRIBITS_TPL_TENTATIVELY_ENABLE) -ENDFUNCTION() - -FUNCTION(TRIBITS_ADD_ADVANCED_TEST) - # TODO Write this -ENDFUNCTION() - -FUNCTION(TRIBITS_ADD_EXECUTABLE_AND_TEST EXE_NAME) - - SET(options STANDARD_PASS_OUTPUT WILL_FAIL) - SET(oneValueArgs PASS_REGULAR_EXPRESSION FAIL_REGULAR_EXPRESSION ENVIRONMENT TIMEOUT CATEGORIES ADDED_TESTS_NAMES_OUT ADDED_EXE_TARGET_NAME_OUT) - SET(multiValueArgs) - - CMAKE_PARSE_ARGUMENTS(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - TRIBITS_ADD_EXECUTABLE(${EXE_NAME} TESTONLY ADDED_EXE_TARGET_NAME_OUT TEST_NAME ${PARSE_UNPARSED_ARGUMENTS}) - - IF(WIN32) - ADD_TEST(NAME ${TEST_NAME} WORKING_DIRECTORY ${LIBRARY_OUTPUT_PATH} COMMAND ${TEST_NAME}${CMAKE_EXECUTABLE_SUFFIX}) - ELSE() - ADD_TEST(NAME ${TEST_NAME} COMMAND ${TEST_NAME}) - ENDIF() - ADD_DEPENDENCIES(check ${TEST_NAME}) - - IF(PARSE_FAIL_REGULAR_EXPRESSION) - SET_TESTS_PROPERTIES(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION ${PARSE_FAIL_REGULAR_EXPRESSION}) - ENDIF() - - IF(PARSE_PASS_REGULAR_EXPRESSION) - SET_TESTS_PROPERTIES(${TEST_NAME} PROPERTIES PASS_REGULAR_EXPRESSION ${PARSE_PASS_REGULAR_EXPRESSION}) - ENDIF() - - IF(PARSE_WILL_FAIL) - SET_TESTS_PROPERTIES(${TEST_NAME} PROPERTIES WILL_FAIL ${PARSE_WILL_FAIL}) - ENDIF() - - IF(PARSE_ADDED_TESTS_NAMES_OUT) - SET(${PARSE_ADDED_TESTS_NAMES_OUT} ${TEST_NAME} PARENT_SCOPE) - ENDIF() - - IF(PARSE_ADDED_EXE_TARGET_NAME_OUT) - SET(${PARSE_ADDED_EXE_TARGET_NAME_OUT} ${TEST_NAME} PARENT_SCOPE) - ENDIF() - -ENDFUNCTION() - -MACRO(TIBITS_CREATE_IMPORTED_TPL_LIBRARY TPL_NAME) - ADD_INTERFACE_LIBRARY(TPL_LIB_${TPL_NAME}) - TARGET_LINK_LIBRARIES(TPL_LIB_${TPL_NAME} LINK_PUBLIC ${TPL_${TPL_NAME}_LIBRARIES}) - TARGET_INCLUDE_DIRECTORIES(TPL_LIB_${TPL_NAME} INTERFACE ${TPL_${TPL_NAME}_INCLUDE_DIRS}) -ENDMACRO() - -FUNCTION(TRIBITS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES TPL_NAME) - - SET(options MUST_FIND_ALL_LIBS MUST_FIND_ALL_HEADERS NO_PRINT_ENABLE_SUCCESS_FAIL) - SET(oneValueArgs) - SET(multiValueArgs REQUIRED_HEADERS REQUIRED_LIBS_NAMES) - - CMAKE_PARSE_ARGUMENTS(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - SET(_${TPL_NAME}_ENABLE_SUCCESS TRUE) - IF (PARSE_REQUIRED_LIBS_NAMES) - FIND_LIBRARY(TPL_${TPL_NAME}_LIBRARIES NAMES ${PARSE_REQUIRED_LIBS_NAMES}) - IF(NOT TPL_${TPL_NAME}_LIBRARIES) - SET(_${TPL_NAME}_ENABLE_SUCCESS FALSE) - ENDIF() - ENDIF() - IF (PARSE_REQUIRED_HEADERS) - FIND_PATH(TPL_${TPL_NAME}_INCLUDE_DIRS NAMES ${PARSE_REQUIRED_HEADERS}) - IF(NOT TPL_${TPL_NAME}_INCLUDE_DIRS) - SET(_${TPL_NAME}_ENABLE_SUCCESS FALSE) - ENDIF() - ENDIF() - - - IF (_${TPL_NAME}_ENABLE_SUCCESS) - TIBITS_CREATE_IMPORTED_TPL_LIBRARY(${TPL_NAME}) - ENDIF() - -ENDFUNCTION() - -#MACRO(TRIBITS_PROCESS_TPL_DEP_FILE TPL_FILE) -# GET_FILENAME_COMPONENT(TPL_NAME ${TPL_FILE} NAME_WE) -# INCLUDE("${TPL_FILE}") -# IF(TARGET TPL_LIB_${TPL_NAME}) -# MESSAGE(STATUS "Found tpl library: ${TPL_NAME}") -# SET(TPL_ENABLE_${TPL_NAME} TRUE) -# ELSE() -# MESSAGE(STATUS "Tpl library not found: ${TPL_NAME}") -# SET(TPL_ENABLE_${TPL_NAME} FALSE) -# ENDIF() -#ENDMACRO() - -MACRO(PREPEND_TARGET_SET VARNAME TARGET_NAME TYPE) - IF(TYPE STREQUAL "REQUIRED") - SET(REQUIRED TRUE) - ELSE() - SET(REQUIRED FALSE) - ENDIF() - IF(TARGET ${TARGET_NAME}) - PREPEND_GLOBAL_SET(${VARNAME} ${TARGET_NAME}) - ELSE() - IF(REQUIRED) - MESSAGE(FATAL_ERROR "Missing dependency ${TARGET_NAME}") - ENDIF() - ENDIF() -ENDMACRO() - -MACRO(TRIBITS_APPEND_PACKAGE_DEPS DEP_LIST TYPE) - FOREACH(DEP ${ARGN}) - PREPEND_GLOBAL_SET(${DEP_LIST} PACKAGE_${DEP}) - ENDFOREACH() -ENDMACRO() - -MACRO(TRIBITS_APPEND_TPLS_DEPS DEP_LIST TYPE) - FOREACH(DEP ${ARGN}) - PREPEND_TARGET_SET(${DEP_LIST} TPL_LIB_${DEP} ${TYPE}) - ENDFOREACH() -ENDMACRO() - -MACRO(TRIBITS_ENABLE_TPLS) - FOREACH(TPL ${ARGN}) - IF(TARGET ${TPL}) - GLOBAL_SET(${PACKAGE_NAME}_ENABLE_${TPL} TRUE) - ELSE() - GLOBAL_SET(${PACKAGE_NAME}_ENABLE_${TPL} FALSE) - ENDIF() - ENDFOREACH() -ENDMACRO() - -MACRO(TRIBITS_PACKAGE_DEFINE_DEPENDENCIES) - - SET(options) - SET(oneValueArgs) - SET(multiValueArgs - LIB_REQUIRED_PACKAGES - LIB_OPTIONAL_PACKAGES - TEST_REQUIRED_PACKAGES - TEST_OPTIONAL_PACKAGES - LIB_REQUIRED_TPLS - LIB_OPTIONAL_TPLS - TEST_REQUIRED_TPLS - TEST_OPTIONAL_TPLS - REGRESSION_EMAIL_LIST - SUBPACKAGES_DIRS_CLASSIFICATIONS_OPTREQS - ) - CMAKE_PARSE_ARGUMENTS(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - GLOBAL_SET(${PACKAGE_NAME}_DEPS "") - TRIBITS_APPEND_PACKAGE_DEPS(${PACKAGE_NAME}_DEPS REQUIRED ${PARSE_LIB_REQUIRED_PACKAGES}) - TRIBITS_APPEND_PACKAGE_DEPS(${PACKAGE_NAME}_DEPS OPTIONAL ${PARSE_LIB_OPTIONAL_PACKAGES}) - TRIBITS_APPEND_TPLS_DEPS(${PACKAGE_NAME}_DEPS REQUIRED ${PARSE_LIB_REQUIRED_TPLS}) - TRIBITS_APPEND_TPLS_DEPS(${PACKAGE_NAME}_DEPS OPTIONAL ${PARSE_LIB_OPTIONAL_TPLS}) - - GLOBAL_SET(${PACKAGE_NAME}_TEST_DEPS "") - TRIBITS_APPEND_PACKAGE_DEPS(${PACKAGE_NAME}_TEST_DEPS REQUIRED ${PARSE_TEST_REQUIRED_PACKAGES}) - TRIBITS_APPEND_PACKAGE_DEPS(${PACKAGE_NAME}_TEST_DEPS OPTIONAL ${PARSE_TEST_OPTIONAL_PACKAGES}) - TRIBITS_APPEND_TPLS_DEPS(${PACKAGE_NAME}_TEST_DEPS REQUIRED ${PARSE_TEST_REQUIRED_TPLS}) - TRIBITS_APPEND_TPLS_DEPS(${PACKAGE_NAME}_TEST_DEPS OPTIONAL ${PARSE_TEST_OPTIONAL_TPLS}) - - TRIBITS_ENABLE_TPLS(${PARSE_LIB_REQUIRED_TPLS} ${PARSE_LIB_OPTIONAL_TPLS} ${PARSE_TEST_REQUIRED_TPLS} ${PARSE_TEST_OPTIONAL_TPLS}) - -ENDMACRO() - -MACRO(TRIBITS_SUBPACKAGE NAME) - SET(PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) - SET(PARENT_PACKAGE_NAME ${PACKAGE_NAME}) - SET(PACKAGE_NAME ${PACKAGE_NAME}${NAME}) - STRING(TOUPPER ${PACKAGE_NAME} PACKAGE_NAME_UC) - SET(${PACKAGE_NAME}_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) - - ADD_INTERFACE_LIBRARY(PACKAGE_${PACKAGE_NAME}) - - GLOBAL_SET(${PACKAGE_NAME}_LIBS "") - - INCLUDE(${PACKAGE_SOURCE_DIR}/cmake/Dependencies.cmake) - -ENDMACRO(TRIBITS_SUBPACKAGE) - -MACRO(TRIBITS_SUBPACKAGE_POSTPROCESS) - TARGET_LINK_AND_INCLUDE_LIBRARIES(PACKAGE_${PACKAGE_NAME} ${${PACKAGE_NAME}_LIBS}) -ENDMACRO(TRIBITS_SUBPACKAGE_POSTPROCESS) - -MACRO(TRIBITS_PACKAGE_DECL NAME) - - SET(PACKAGE_NAME ${NAME}) - SET(${PACKAGE_NAME}_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) - STRING(TOUPPER ${PACKAGE_NAME} PACKAGE_NAME_UC) - - #SET(TRIBITS_DEPS_DIR "${CMAKE_SOURCE_DIR}/cmake/deps") - #FILE(GLOB TPLS_FILES "${TRIBITS_DEPS_DIR}/*.cmake") - #FOREACH(TPL_FILE ${TPLS_FILES}) - # TRIBITS_PROCESS_TPL_DEP_FILE(${TPL_FILE}) - #ENDFOREACH() - -ENDMACRO() - - -MACRO(TRIBITS_PROCESS_SUBPACKAGES) - FILE(GLOB SUBPACKAGES RELATIVE ${CMAKE_SOURCE_DIR} */cmake/Dependencies.cmake) - FOREACH(SUBPACKAGE ${SUBPACKAGES}) - GET_FILENAME_COMPONENT(SUBPACKAGE_CMAKE ${SUBPACKAGE} DIRECTORY) - GET_FILENAME_COMPONENT(SUBPACKAGE_DIR ${SUBPACKAGE_CMAKE} DIRECTORY) - ADD_SUBDIRECTORY(${CMAKE_BINARY_DIR}/../${SUBPACKAGE_DIR}) - ENDFOREACH() -ENDMACRO(TRIBITS_PROCESS_SUBPACKAGES) - -MACRO(TRIBITS_PACKAGE_DEF) -ENDMACRO(TRIBITS_PACKAGE_DEF) - -MACRO(TRIBITS_EXCLUDE_AUTOTOOLS_FILES) -ENDMACRO(TRIBITS_EXCLUDE_AUTOTOOLS_FILES) - -MACRO(TRIBITS_EXCLUDE_FILES) -ENDMACRO(TRIBITS_EXCLUDE_FILES) - -MACRO(TRIBITS_PACKAGE_POSTPROCESS) -ENDMACRO(TRIBITS_PACKAGE_POSTPROCESS) - diff --git a/lib/kokkos/containers/CMakeLists.txt b/lib/kokkos/containers/CMakeLists.txt index c37aa3e3e2..2bfaea7a13 100644 --- a/lib/kokkos/containers/CMakeLists.txt +++ b/lib/kokkos/containers/CMakeLists.txt @@ -1,13 +1,10 @@ - - -TRIBITS_SUBPACKAGE(Containers) - - -IF(KOKKOS_HAS_TRILINOS) - ADD_SUBDIRECTORY(src) -ENDIF() - -TRIBITS_ADD_TEST_DIRECTORIES(unit_tests) -TRIBITS_ADD_TEST_DIRECTORIES(performance_tests) - -TRIBITS_SUBPACKAGE_POSTPROCESS() + + +KOKKOS_SUBPACKAGE(Containers) + +ADD_SUBDIRECTORY(src) + +KOKKOS_ADD_TEST_DIRECTORIES(unit_tests) +KOKKOS_ADD_TEST_DIRECTORIES(performance_tests) + +KOKKOS_SUBPACKAGE_POSTPROCESS() diff --git a/lib/kokkos/containers/performance_tests/CMakeLists.txt b/lib/kokkos/containers/performance_tests/CMakeLists.txt index 3c6584bc34..ca76808190 100644 --- a/lib/kokkos/containers/performance_tests/CMakeLists.txt +++ b/lib/kokkos/containers/performance_tests/CMakeLists.txt @@ -1,49 +1,62 @@ -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) -INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${CMAKE_CURRENT_SOURCE_DIR}) -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../src ) - -IF(NOT KOKKOS_HAS_TRILINOS) - IF(KOKKOS_SEPARATE_LIBS) - set(TEST_LINK_TARGETS kokkoscore) - ELSE() - set(TEST_LINK_TARGETS kokkos) - ENDIF() +KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +KOKKOS_INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${CMAKE_CURRENT_SOURCE_DIR}) +KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../src ) + +IF(Kokkos_ENABLE_CUDA) + SET(SOURCES + TestMain.cpp + TestCuda.cpp + ) + + KOKKOS_ADD_TEST_EXECUTABLE( PerfTestExec_Cuda + SOURCES ${SOURCES} + ) + + KOKKOS_ADD_TEST( NAME PerformanceTest_Cuda + EXE PerfTestExec_Cuda + ) ENDIF() -SET(SOURCES - TestMain.cpp - TestCuda.cpp - ) - -IF(Kokkos_ENABLE_Pthread) - LIST( APPEND SOURCES TestThreads.cpp) +IF(Kokkos_ENABLE_PTHREAD) + SET(SOURCES + TestMain.cpp + TestThreads.cpp + ) + KOKKOS_ADD_TEST_EXECUTABLE( PerfTestExec_Threads + SOURCES ${SOURCES} + ) + + KOKKOS_ADD_TEST( NAME PerformanceTest_Threads + EXE PerfTestExec_Threads + ) ENDIF() -IF(Kokkos_ENABLE_OpenMP) - LIST( APPEND SOURCES TestOpenMP.cpp) +IF(Kokkos_ENABLE_OPENMP) + SET(SOURCES + TestMain.cpp + TestOpenMP.cpp + ) + KOKKOS_ADD_TEST_EXECUTABLE( PerfTestExec_OpenMP + SOURCES ${SOURCES} + ) + + KOKKOS_ADD_TEST( NAME PerformanceTest_OpenMP + EXE PerfTestExec_OpenMP + ) ENDIF() IF(Kokkos_ENABLE_HPX) - LIST( APPEND SOURCES TestHPX.cpp) + SET(SOURCES + TestMain.cpp + TestHPX.cpp + ) + KOKKOS_ADD_TEST_EXECUTABLE( PerfTestExec_HPX + SOURCES ${SOURCES} + ) + + KOKKOS_ADD_TEST( NAME PerformanceTest_HPX + EXE PerfTestExec_HPX + ) ENDIF() -# Per #374, we always want to build this test, but we only want to run -# it as a PERFORMANCE test. That's why we separate building the test -# from running the test. - -TRIBITS_ADD_EXECUTABLE( - PerfTestExec - SOURCES ${SOURCES} - COMM serial mpi - TESTONLYLIBS kokkos_gtest ${TEST_LINK_TARGETS} - ) - -TRIBITS_ADD_TEST( - PerformanceTest - NAME PerfTestExec - COMM serial mpi - NUM_MPI_PROCS 1 - CATEGORIES PERFORMANCE - FAIL_REGULAR_EXPRESSION " FAILED " - ) diff --git a/lib/kokkos/containers/performance_tests/TestCuda.cpp b/lib/kokkos/containers/performance_tests/TestCuda.cpp index 351fb86df3..697a006c3c 100644 --- a/lib/kokkos/containers/performance_tests/TestCuda.cpp +++ b/lib/kokkos/containers/performance_tests/TestCuda.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,7 +43,7 @@ */ #include -#if defined( KOKKOS_ENABLE_CUDA ) +#if defined(KOKKOS_ENABLE_CUDA) #include #include @@ -66,45 +67,38 @@ namespace Performance { class cuda : public ::testing::Test { -protected: - static void SetUpTestCase() - { + protected: + static void SetUpTestCase() { std::cout << std::setprecision(5) << std::scientific; Kokkos::InitArguments args(-1, -1, 0); Kokkos::initialize(args); } - static void TearDownTestCase() - { - Kokkos::finalize(); - } + static void TearDownTestCase() { Kokkos::finalize(); } }; -TEST_F( cuda, dynrankview_perf ) -{ +TEST_F(cuda, dynrankview_perf) { std::cout << "Cuda" << std::endl; std::cout << " DynRankView vs View: Initialization Only " << std::endl; - test_dynrankview_op_perf( 40960 ); + test_dynrankview_op_perf(40960); } -TEST_F( cuda, global_2_local) -{ +TEST_F(cuda, global_2_local) { std::cout << "Cuda" << std::endl; std::cout << "size, create, generate, fill, find" << std::endl; - for (unsigned i=Performance::begin_id_size; i<=Performance::end_id_size; i *= Performance::id_step) + for (unsigned i = Performance::begin_id_size; i <= Performance::end_id_size; + i *= Performance::id_step) test_global_to_local_ids(i); } -TEST_F( cuda, unordered_map_performance_near) -{ - Perf::run_performance_tests("cuda-near"); +TEST_F(cuda, unordered_map_performance_near) { + Perf::run_performance_tests("cuda-near"); } -TEST_F( cuda, unordered_map_performance_far) -{ - Perf::run_performance_tests("cuda-far"); +TEST_F(cuda, unordered_map_performance_far) { + Perf::run_performance_tests("cuda-far"); } -} +} // namespace Performance #else void KOKKOS_CONTAINERS_PERFORMANCE_TESTS_TESTCUDA_PREVENT_EMPTY_LINK_ERROR() {} -#endif /* #if defined( KOKKOS_ENABLE_CUDA ) */ +#endif /* #if defined( KOKKOS_ENABLE_CUDA ) */ diff --git a/lib/kokkos/containers/performance_tests/TestDynRankView.hpp b/lib/kokkos/containers/performance_tests/TestDynRankView.hpp index db6274e057..ee13f7e58b 100644 --- a/lib/kokkos/containers/performance_tests/TestDynRankView.hpp +++ b/lib/kokkos/containers/performance_tests/TestDynRankView.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -49,109 +50,102 @@ #include -// Compare performance of DynRankView to View, specific focus on the parenthesis operators +// Compare performance of DynRankView to View, specific focus on the parenthesis +// operators namespace Performance { -//View functor +// View functor template struct InitViewFunctor { - typedef Kokkos::View inviewtype; + typedef Kokkos::View inviewtype; inviewtype _inview; - InitViewFunctor( inviewtype &inview_ ) : _inview(inview_) - {} + InitViewFunctor(inviewtype &inview_) : _inview(inview_) {} KOKKOS_INLINE_FUNCTION void operator()(const int i) const { for (unsigned j = 0; j < _inview.extent(1); ++j) { for (unsigned k = 0; k < _inview.extent(2); ++k) { - _inview(i,j,k) = i/2 -j*j + k/3; + _inview(i, j, k) = i / 2 - j * j + k / 3; } } } - struct SumComputationTest - { - typedef Kokkos::View inviewtype; + struct SumComputationTest { + typedef Kokkos::View inviewtype; inviewtype _inview; - typedef Kokkos::View outviewtype; + typedef Kokkos::View outviewtype; outviewtype _outview; KOKKOS_INLINE_FUNCTION - SumComputationTest(inviewtype &inview_ , outviewtype &outview_) : _inview(inview_), _outview(outview_) {} + SumComputationTest(inviewtype &inview_, outviewtype &outview_) + : _inview(inview_), _outview(outview_) {} KOKKOS_INLINE_FUNCTION void operator()(const int i) const { for (unsigned j = 0; j < _inview.extent(1); ++j) { for (unsigned k = 0; k < _inview.extent(2); ++k) { - _outview(i) += _inview(i,j,k) ; + _outview(i) += _inview(i, j, k); } } } }; - }; template struct InitStrideViewFunctor { - typedef Kokkos::View inviewtype; + typedef Kokkos::View inviewtype; inviewtype _inview; - InitStrideViewFunctor( inviewtype &inview_ ) : _inview(inview_) - {} + InitStrideViewFunctor(inviewtype &inview_) : _inview(inview_) {} KOKKOS_INLINE_FUNCTION void operator()(const int i) const { for (unsigned j = 0; j < _inview.extent(1); ++j) { for (unsigned k = 0; k < _inview.extent(2); ++k) { - _inview(i,j,k) = i/2 -j*j + k/3; + _inview(i, j, k) = i / 2 - j * j + k / 3; } } } - }; template struct InitViewRank7Functor { - typedef Kokkos::View inviewtype; + typedef Kokkos::View inviewtype; inviewtype _inview; - InitViewRank7Functor( inviewtype &inview_ ) : _inview(inview_) - {} + InitViewRank7Functor(inviewtype &inview_) : _inview(inview_) {} KOKKOS_INLINE_FUNCTION void operator()(const int i) const { for (unsigned j = 0; j < _inview.extent(1); ++j) { for (unsigned k = 0; k < _inview.extent(2); ++k) { - _inview(i,j,k,0,0,0,0) = i/2 -j*j + k/3; + _inview(i, j, k, 0, 0, 0, 0) = i / 2 - j * j + k / 3; } } } - }; -//DynRankView functor +// DynRankView functor template struct InitDynRankViewFunctor { typedef Kokkos::DynRankView inviewtype; inviewtype _inview; - InitDynRankViewFunctor( inviewtype &inview_ ) : _inview(inview_) - {} + InitDynRankViewFunctor(inviewtype &inview_) : _inview(inview_) {} KOKKOS_INLINE_FUNCTION void operator()(const int i) const { for (unsigned j = 0; j < _inview.extent(1); ++j) { for (unsigned k = 0; k < _inview.extent(2); ++k) { - _inview(i,j,k) = i/2 -j*j + k/3; + _inview(i, j, k) = i / 2 - j * j + k / 3; } } } - struct SumComputationTest - { + struct SumComputationTest { typedef Kokkos::DynRankView inviewtype; inviewtype _inview; @@ -159,108 +153,121 @@ struct InitDynRankViewFunctor { outviewtype _outview; KOKKOS_INLINE_FUNCTION - SumComputationTest(inviewtype &inview_ , outviewtype &outview_) : _inview(inview_), _outview(outview_) {} + SumComputationTest(inviewtype &inview_, outviewtype &outview_) + : _inview(inview_), _outview(outview_) {} KOKKOS_INLINE_FUNCTION void operator()(const int i) const { for (unsigned j = 0; j < _inview.extent(1); ++j) { for (unsigned k = 0; k < _inview.extent(2); ++k) { - _outview(i) += _inview(i,j,k) ; + _outview(i) += _inview(i, j, k); } } } }; - }; - template -void test_dynrankview_op_perf( const int par_size ) -{ - +void test_dynrankview_op_perf(const int par_size) { typedef DeviceType execution_space; typedef typename execution_space::size_type size_type; const size_type dim_2 = 90; const size_type dim_3 = 30; - double elapsed_time_view = 0; - double elapsed_time_compview = 0; + double elapsed_time_view = 0; + double elapsed_time_compview = 0; double elapsed_time_strideview = 0; double elapsed_time_view_rank7 = 0; - double elapsed_time_drview = 0; + double elapsed_time_drview = 0; double elapsed_time_compdrview = 0; Kokkos::Timer timer; { - Kokkos::View testview("testview",par_size,dim_2,dim_3); + Kokkos::View testview("testview", par_size, dim_2, + dim_3); typedef InitViewFunctor FunctorType; timer.reset(); - Kokkos::RangePolicy policy(0,par_size); - Kokkos::parallel_for( policy , FunctorType(testview) ); + Kokkos::RangePolicy policy(0, par_size); + Kokkos::parallel_for(policy, FunctorType(testview)); DeviceType().fence(); elapsed_time_view = timer.seconds(); std::cout << " View time (init only): " << elapsed_time_view << std::endl; - timer.reset(); - Kokkos::View sumview("sumview",par_size); - Kokkos::parallel_for( policy , typename FunctorType::SumComputationTest(testview, sumview) ); + Kokkos::View sumview("sumview", par_size); + Kokkos::parallel_for( + policy, typename FunctorType::SumComputationTest(testview, sumview)); DeviceType().fence(); elapsed_time_compview = timer.seconds(); - std::cout << " View sum computation time: " << elapsed_time_view << std::endl; - + std::cout << " View sum computation time: " << elapsed_time_view + << std::endl; - Kokkos::View teststrideview = Kokkos::subview(testview, Kokkos::ALL, Kokkos::ALL,Kokkos::ALL); + Kokkos::View teststrideview = + Kokkos::subview(testview, Kokkos::ALL, Kokkos::ALL, Kokkos::ALL); typedef InitStrideViewFunctor FunctorStrideType; timer.reset(); - Kokkos::parallel_for( policy , FunctorStrideType(teststrideview) ); + Kokkos::parallel_for(policy, FunctorStrideType(teststrideview)); DeviceType().fence(); elapsed_time_strideview = timer.seconds(); - std::cout << " Strided View time (init only): " << elapsed_time_strideview << std::endl; + std::cout << " Strided View time (init only): " << elapsed_time_strideview + << std::endl; } { - Kokkos::View testview("testview",par_size,dim_2,dim_3,1,1,1,1); + Kokkos::View testview("testview", par_size, + dim_2, dim_3, 1, 1, 1, 1); typedef InitViewRank7Functor FunctorType; timer.reset(); - Kokkos::RangePolicy policy(0,par_size); - Kokkos::parallel_for( policy , FunctorType(testview) ); + Kokkos::RangePolicy policy(0, par_size); + Kokkos::parallel_for(policy, FunctorType(testview)); DeviceType().fence(); elapsed_time_view_rank7 = timer.seconds(); - std::cout << " View Rank7 time (init only): " << elapsed_time_view_rank7 << std::endl; + std::cout << " View Rank7 time (init only): " << elapsed_time_view_rank7 + << std::endl; } { - Kokkos::DynRankView testdrview("testdrview",par_size,dim_2,dim_3); + Kokkos::DynRankView testdrview("testdrview", par_size, + dim_2, dim_3); typedef InitDynRankViewFunctor FunctorType; timer.reset(); - Kokkos::RangePolicy policy(0,par_size); - Kokkos::parallel_for( policy , FunctorType(testdrview) ); + Kokkos::RangePolicy policy(0, par_size); + Kokkos::parallel_for(policy, FunctorType(testdrview)); DeviceType().fence(); elapsed_time_drview = timer.seconds(); - std::cout << " DynRankView time (init only): " << elapsed_time_drview << std::endl; + std::cout << " DynRankView time (init only): " << elapsed_time_drview + << std::endl; timer.reset(); - Kokkos::DynRankView sumview("sumview",par_size); - Kokkos::parallel_for( policy , typename FunctorType::SumComputationTest(testdrview, sumview) ); + Kokkos::DynRankView sumview("sumview", par_size); + Kokkos::parallel_for( + policy, typename FunctorType::SumComputationTest(testdrview, sumview)); DeviceType().fence(); elapsed_time_compdrview = timer.seconds(); - std::cout << " DynRankView sum computation time: " << elapsed_time_compdrview << std::endl; - + std::cout << " DynRankView sum computation time: " + << elapsed_time_compdrview << std::endl; } - std::cout << " Ratio of View to DynRankView time: " << elapsed_time_view / elapsed_time_drview << std::endl; //expect < 1 - std::cout << " Ratio of View to DynRankView sum computation time: " << elapsed_time_compview / elapsed_time_compdrview << std::endl; //expect < 1 - std::cout << " Ratio of View to View Rank7 time: " << elapsed_time_view / elapsed_time_view_rank7 << std::endl; //expect < 1 - std::cout << " Ratio of StrideView to DynRankView time: " << elapsed_time_strideview / elapsed_time_drview << std::endl; //expect < 1 - std::cout << " Ratio of DynRankView to View Rank7 time: " << elapsed_time_drview / elapsed_time_view_rank7 << std::endl; //expect ? + std::cout << " Ratio of View to DynRankView time: " + << elapsed_time_view / elapsed_time_drview + << std::endl; // expect < 1 + std::cout << " Ratio of View to DynRankView sum computation time: " + << elapsed_time_compview / elapsed_time_compdrview + << std::endl; // expect < 1 + std::cout << " Ratio of View to View Rank7 time: " + << elapsed_time_view / elapsed_time_view_rank7 + << std::endl; // expect < 1 + std::cout << " Ratio of StrideView to DynRankView time: " + << elapsed_time_strideview / elapsed_time_drview + << std::endl; // expect < 1 + std::cout << " Ratio of DynRankView to View Rank7 time: " + << elapsed_time_drview / elapsed_time_view_rank7 + << std::endl; // expect ? timer.reset(); -} //end test_dynrankview - +} // end test_dynrankview -} //end Performance +} // namespace Performance #endif - diff --git a/lib/kokkos/containers/performance_tests/TestGlobal2LocalIds.hpp b/lib/kokkos/containers/performance_tests/TestGlobal2LocalIds.hpp index 98997b3239..0d2ee4bc8d 100644 --- a/lib/kokkos/containers/performance_tests/TestGlobal2LocalIds.hpp +++ b/lib/kokkos/containers/performance_tests/TestGlobal2LocalIds.hpp @@ -1,12 +1,13 @@ //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -22,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -35,7 +36,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER @@ -54,153 +55,137 @@ namespace Performance { static const unsigned begin_id_size = 256u; -static const unsigned end_id_size = 1u << 22; -static const unsigned id_step = 2u; +static const unsigned end_id_size = 1u << 22; +static const unsigned id_step = 2u; -union helper -{ +union helper { uint32_t word; uint8_t byte[4]; }; - template -struct generate_ids -{ +struct generate_ids { typedef Device execution_space; typedef typename execution_space::size_type size_type; - typedef Kokkos::View local_id_view; + typedef Kokkos::View local_id_view; local_id_view local_2_global; - generate_ids( local_id_view & ids) - : local_2_global(ids) - { + generate_ids(local_id_view& ids) : local_2_global(ids) { Kokkos::parallel_for(local_2_global.extent(0), *this); } - KOKKOS_INLINE_FUNCTION - void operator()(size_type i) const - { - + void operator()(size_type i) const { helper x = {static_cast(i)}; // shuffle the bytes of i to create a unique, semi-random global_id x.word = ~x.word; uint8_t tmp = x.byte[3]; - x.byte[3] = x.byte[1]; - x.byte[1] = tmp; + x.byte[3] = x.byte[1]; + x.byte[1] = tmp; - tmp = x.byte[2]; + tmp = x.byte[2]; x.byte[2] = x.byte[0]; x.byte[0] = tmp; local_2_global[i] = x.word; } - }; template -struct fill_map -{ +struct fill_map { typedef Device execution_space; typedef typename execution_space::size_type size_type; - typedef Kokkos::View local_id_view; - typedef Kokkos::UnorderedMap global_id_view; + typedef Kokkos::View + local_id_view; + typedef Kokkos::UnorderedMap + global_id_view; global_id_view global_2_local; local_id_view local_2_global; - fill_map( global_id_view gIds, local_id_view lIds) - : global_2_local(gIds) , local_2_global(lIds) - { + fill_map(global_id_view gIds, local_id_view lIds) + : global_2_local(gIds), local_2_global(lIds) { Kokkos::parallel_for(local_2_global.extent(0), *this); } KOKKOS_INLINE_FUNCTION - void operator()(size_type i) const - { - global_2_local.insert( local_2_global[i], i); + void operator()(size_type i) const { + global_2_local.insert(local_2_global[i], i); } - }; template -struct find_test -{ +struct find_test { typedef Device execution_space; typedef typename execution_space::size_type size_type; - typedef Kokkos::View local_id_view; - typedef Kokkos::UnorderedMap global_id_view; + typedef Kokkos::View + local_id_view; + typedef Kokkos::UnorderedMap + global_id_view; global_id_view global_2_local; local_id_view local_2_global; typedef size_t value_type; - find_test( global_id_view gIds, local_id_view lIds, value_type & num_errors) - : global_2_local(gIds) , local_2_global(lIds) - { + find_test(global_id_view gIds, local_id_view lIds, value_type& num_errors) + : global_2_local(gIds), local_2_global(lIds) { Kokkos::parallel_reduce(local_2_global.extent(0), *this, num_errors); } KOKKOS_INLINE_FUNCTION - void init(value_type & v) const - { v = 0; } + void init(value_type& v) const { v = 0; } KOKKOS_INLINE_FUNCTION - void join(volatile value_type & dst, volatile value_type const & src) const - { dst += src; } + void join(volatile value_type& dst, volatile value_type const& src) const { + dst += src; + } KOKKOS_INLINE_FUNCTION - void operator()(size_type i, value_type & num_errors) const - { - uint32_t index = global_2_local.find( local_2_global[i] ); + void operator()(size_type i, value_type& num_errors) const { + uint32_t index = global_2_local.find(local_2_global[i]); - if ( global_2_local.value_at(index) != i) ++num_errors; + if (global_2_local.value_at(index) != i) ++num_errors; } - }; template -void test_global_to_local_ids(unsigned num_ids) -{ - +void test_global_to_local_ids(unsigned num_ids) { typedef Device execution_space; typedef typename execution_space::size_type size_type; - typedef Kokkos::View local_id_view; - typedef Kokkos::UnorderedMap global_id_view; + typedef Kokkos::View local_id_view; + typedef Kokkos::UnorderedMap + global_id_view; - //size + // size std::cout << num_ids << ", "; double elasped_time = 0; Kokkos::Timer timer; local_id_view local_2_global("local_ids", num_ids); - global_id_view global_2_local((3u*num_ids)/2u); + global_id_view global_2_local((3u * num_ids) / 2u); - //create + // create elasped_time = timer.seconds(); std::cout << elasped_time << ", "; timer.reset(); // generate unique ids - { - generate_ids gen(local_2_global); - } + { generate_ids gen(local_2_global); } Device().fence(); // generate elasped_time = timer.seconds(); std::cout << elasped_time << ", "; timer.reset(); - { - fill_map fill(global_2_local, local_2_global); - } + { fill_map fill(global_2_local, local_2_global); } Device().fence(); // fill @@ -208,11 +193,9 @@ void test_global_to_local_ids(unsigned num_ids) std::cout << elasped_time << ", "; timer.reset(); - size_t num_errors = 0; - for (int i=0; i<100; ++i) - { - find_test find(global_2_local, local_2_global,num_errors); + for (int i = 0; i < 100; ++i) { + find_test find(global_2_local, local_2_global, num_errors); } Device().fence(); @@ -220,12 +203,9 @@ void test_global_to_local_ids(unsigned num_ids) elasped_time = timer.seconds(); std::cout << elasped_time << std::endl; - ASSERT_EQ( num_errors, 0u); + ASSERT_EQ(num_errors, 0u); } +} // namespace Performance -} // namespace Performance - - -#endif //KOKKOS_TEST_GLOBAL_TO_LOCAL_IDS_HPP - +#endif // KOKKOS_TEST_GLOBAL_TO_LOCAL_IDS_HPP diff --git a/lib/kokkos/containers/performance_tests/TestHPX.cpp b/lib/kokkos/containers/performance_tests/TestHPX.cpp index 0f43377cee..48be466bfa 100644 --- a/lib/kokkos/containers/performance_tests/TestHPX.cpp +++ b/lib/kokkos/containers/performance_tests/TestHPX.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,7 +43,7 @@ */ #include -#if defined( KOKKOS_ENABLE_HPX ) +#if defined(KOKKOS_ENABLE_HPX) #include @@ -61,70 +62,63 @@ #include #include - namespace Performance { class hpx : public ::testing::Test { -protected: - static void SetUpTestCase() - { + protected: + static void SetUpTestCase() { std::cout << std::setprecision(5) << std::scientific; Kokkos::initialize(); - Kokkos::print_configuration( std::cout ); + Kokkos::print_configuration(std::cout); } - static void TearDownTestCase() - { - Kokkos::finalize(); - } + static void TearDownTestCase() { Kokkos::finalize(); } }; -TEST_F( hpx, dynrankview_perf ) -{ +TEST_F(hpx, dynrankview_perf) { std::cout << "HPX" << std::endl; std::cout << " DynRankView vs View: Initialization Only " << std::endl; - test_dynrankview_op_perf( 8192 ); + test_dynrankview_op_perf(8192); } -TEST_F( hpx, global_2_local) -{ +TEST_F(hpx, global_2_local) { std::cout << "HPX" << std::endl; std::cout << "size, create, generate, fill, find" << std::endl; - for (unsigned i=Performance::begin_id_size; i<=Performance::end_id_size; i *= Performance::id_step) + for (unsigned i = Performance::begin_id_size; i <= Performance::end_id_size; + i *= Performance::id_step) test_global_to_local_ids(i); } -TEST_F( hpx, unordered_map_performance_near) -{ +TEST_F(hpx, unordered_map_performance_near) { unsigned num_hpx = 4; std::ostringstream base_file_name; base_file_name << "hpx-" << num_hpx << "-near"; - Perf::run_performance_tests(base_file_name.str()); + Perf::run_performance_tests( + base_file_name.str()); } -TEST_F( hpx, unordered_map_performance_far) -{ +TEST_F(hpx, unordered_map_performance_far) { unsigned num_hpx = 4; std::ostringstream base_file_name; base_file_name << "hpx-" << num_hpx << "-far"; - Perf::run_performance_tests(base_file_name.str()); + Perf::run_performance_tests( + base_file_name.str()); } -TEST_F( hpx, scatter_view) -{ +TEST_F(hpx, scatter_view) { std::cout << "ScatterView data-duplicated test:\n"; Perf::test_scatter_view(10, 1000 * 1000); -//std::cout << "ScatterView atomics test:\n"; -//Perf::test_scatter_view(10, 1000 * 1000); + Kokkos::Experimental::ScatterDuplicated, + Kokkos::Experimental::ScatterNonAtomic>(10, + 1000 * 1000); + // std::cout << "ScatterView atomics test:\n"; + // Perf::test_scatter_view(10, 1000 * 1000); } -} // namespace test +} // namespace Performance #else void KOKKOS_CONTAINERS_PERFORMANCE_TESTS_TESTHPX_PREVENT_EMPTY_LINK_ERROR() {} #endif - diff --git a/lib/kokkos/containers/performance_tests/TestMain.cpp b/lib/kokkos/containers/performance_tests/TestMain.cpp index 217b01a57a..e3c8edb045 100644 --- a/lib/kokkos/containers/performance_tests/TestMain.cpp +++ b/lib/kokkos/containers/performance_tests/TestMain.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -47,7 +48,6 @@ #include int main(int argc, char *argv[]) { - ::testing::InitGoogleTest(&argc,argv); + ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } - diff --git a/lib/kokkos/containers/performance_tests/TestOpenMP.cpp b/lib/kokkos/containers/performance_tests/TestOpenMP.cpp index e6218074ea..a9c8639ed4 100644 --- a/lib/kokkos/containers/performance_tests/TestOpenMP.cpp +++ b/lib/kokkos/containers/performance_tests/TestOpenMP.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,7 +43,7 @@ */ #include -#if defined( KOKKOS_ENABLE_OPENMP ) +#if defined(KOKKOS_ENABLE_OPENMP) #include @@ -61,82 +62,72 @@ #include #include - namespace Performance { class openmp : public ::testing::Test { -protected: - static void SetUpTestCase() - { + protected: + static void SetUpTestCase() { std::cout << std::setprecision(5) << std::scientific; Kokkos::initialize(); - Kokkos::OpenMP::print_configuration( std::cout ); + Kokkos::OpenMP::print_configuration(std::cout); } - static void TearDownTestCase() - { - Kokkos::finalize(); - } + static void TearDownTestCase() { Kokkos::finalize(); } }; -TEST_F( openmp, dynrankview_perf ) -{ +TEST_F(openmp, dynrankview_perf) { std::cout << "OpenMP" << std::endl; std::cout << " DynRankView vs View: Initialization Only " << std::endl; - test_dynrankview_op_perf( 8192 ); + test_dynrankview_op_perf(8192); } -TEST_F( openmp, global_2_local) -{ +TEST_F(openmp, global_2_local) { std::cout << "OpenMP" << std::endl; std::cout << "size, create, generate, fill, find" << std::endl; - for (unsigned i=Performance::begin_id_size; i<=Performance::end_id_size; i *= Performance::id_step) + for (unsigned i = Performance::begin_id_size; i <= Performance::end_id_size; + i *= Performance::id_step) test_global_to_local_ids(i); } -TEST_F( openmp, unordered_map_performance_near) -{ +TEST_F(openmp, unordered_map_performance_near) { unsigned num_openmp = 4; if (Kokkos::hwloc::available()) { num_openmp = Kokkos::hwloc::get_available_numa_count() * - Kokkos::hwloc::get_available_cores_per_numa() * - Kokkos::hwloc::get_available_threads_per_core(); - + Kokkos::hwloc::get_available_cores_per_numa() * + Kokkos::hwloc::get_available_threads_per_core(); } std::ostringstream base_file_name; base_file_name << "openmp-" << num_openmp << "-near"; - Perf::run_performance_tests(base_file_name.str()); + Perf::run_performance_tests(base_file_name.str()); } -TEST_F( openmp, unordered_map_performance_far) -{ +TEST_F(openmp, unordered_map_performance_far) { unsigned num_openmp = 4; if (Kokkos::hwloc::available()) { num_openmp = Kokkos::hwloc::get_available_numa_count() * - Kokkos::hwloc::get_available_cores_per_numa() * - Kokkos::hwloc::get_available_threads_per_core(); - + Kokkos::hwloc::get_available_cores_per_numa() * + Kokkos::hwloc::get_available_threads_per_core(); } std::ostringstream base_file_name; base_file_name << "openmp-" << num_openmp << "-far"; - Perf::run_performance_tests(base_file_name.str()); + Perf::run_performance_tests(base_file_name.str()); } -TEST_F( openmp, scatter_view) -{ +TEST_F(openmp, scatter_view) { std::cout << "ScatterView data-duplicated test:\n"; Perf::test_scatter_view(10, 1000 * 1000); -//std::cout << "ScatterView atomics test:\n"; -//Perf::test_scatter_view(10, 1000 * 1000); + Kokkos::Experimental::ScatterDuplicated, + Kokkos::Experimental::ScatterNonAtomic>(10, + 1000 * 1000); + // std::cout << "ScatterView atomics test:\n"; + // Perf::test_scatter_view(10, 1000 * 1000); } -} // namespace test +} // namespace Performance #else -void KOKKOS_CONTAINERS_PERFORMANCE_TESTS_TESTOPENMP_PREVENT_EMPTY_LINK_ERROR() {} +void KOKKOS_CONTAINERS_PERFORMANCE_TESTS_TESTOPENMP_PREVENT_EMPTY_LINK_ERROR() { +} #endif - diff --git a/lib/kokkos/containers/performance_tests/TestROCm.cpp b/lib/kokkos/containers/performance_tests/TestROCm.cpp index 3cf9f3bd14..55b770b49c 100644 --- a/lib/kokkos/containers/performance_tests/TestROCm.cpp +++ b/lib/kokkos/containers/performance_tests/TestROCm.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,7 +43,7 @@ */ #include -#if defined( KOKKOS_ENABLE_ROCM ) +#if defined(KOKKOS_ENABLE_ROCM) #include #include @@ -66,15 +67,14 @@ namespace Performance { class rocm : public ::testing::Test { -protected: - static void SetUpTestCase() - { + protected: + static void SetUpTestCase() { std::cout << std::setprecision(5) << std::scientific; Kokkos::HostSpace::execution_space::initialize(); - Kokkos::Experimental::ROCm::initialize( Kokkos::Experimental::ROCm::SelectDevice(0) ); + Kokkos::Experimental::ROCm::initialize( + Kokkos::Experimental::ROCm::SelectDevice(0)); } - static void TearDownTestCase() - { + static void TearDownTestCase() { Kokkos::Experimental::ROCm::finalize(); Kokkos::HostSpace::execution_space::finalize(); } @@ -97,17 +97,15 @@ TEST_F( rocm, global_2_local) } #endif -TEST_F( rocm, unordered_map_performance_near) -{ - Perf::run_performance_tests("rocm-near"); +TEST_F(rocm, unordered_map_performance_near) { + Perf::run_performance_tests("rocm-near"); } -TEST_F( rocm, unordered_map_performance_far) -{ - Perf::run_performance_tests("rocm-far"); +TEST_F(rocm, unordered_map_performance_far) { + Perf::run_performance_tests("rocm-far"); } -} +} // namespace Performance #else void KOKKOS_CONTAINERS_PERFORMANCE_TESTS_TESTROCM_PREVENT_EMPTY_LINK_ERROR() {} -#endif /* #if defined( KOKKOS_ENABLE_ROCM ) */ +#endif /* #if defined( KOKKOS_ENABLE_ROCM ) */ diff --git a/lib/kokkos/containers/performance_tests/TestScatterView.hpp b/lib/kokkos/containers/performance_tests/TestScatterView.hpp index bd9121bb82..3d4c57f3e2 100644 --- a/lib/kokkos/containers/performance_tests/TestScatterView.hpp +++ b/lib/kokkos/containers/performance_tests/TestScatterView.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -49,67 +50,68 @@ namespace Perf { -template -void test_scatter_view(int m, int n) -{ - Kokkos::View original_view("original_view", n); +template +void test_scatter_view(int m, int n) { + Kokkos::View original_view("original_view", + n); { - auto scatter_view = Kokkos::Experimental::create_scatter_view - < Kokkos::Experimental::ScatterSum - , duplication - , contribution - > (original_view); + auto scatter_view = Kokkos::Experimental::create_scatter_view< + Kokkos::Experimental::ScatterSum, duplication, contribution>( + original_view); Kokkos::Experimental::UniqueToken< - ExecSpace, Kokkos::Experimental::UniqueTokenScope::Global> - unique_token{ExecSpace()}; - //auto internal_view = scatter_view.internal_view; + ExecSpace, Kokkos::Experimental::UniqueTokenScope::Global> + unique_token{ExecSpace()}; + // auto internal_view = scatter_view.internal_view; auto policy = Kokkos::RangePolicy(0, n); for (int foo = 0; foo < 5; ++foo) { - { - auto num_threads = unique_token.size(); - std::cout << "num_threads " << num_threads << '\n'; - Kokkos::View hand_coded_duplicate_view("hand_coded_duplicate", num_threads, n); - auto f2 = KOKKOS_LAMBDA(int i) { - auto thread_id = unique_token.acquire(); - for (int j = 0; j < 10; ++j) { - auto k = (i + j) % n; - hand_coded_duplicate_view(thread_id, k, 0) += 4.2; - hand_coded_duplicate_view(thread_id, k, 1) += 2.0; - hand_coded_duplicate_view(thread_id, k, 2) += 1.0; + { + auto num_threads = unique_token.size(); + std::cout << "num_threads " << num_threads << '\n'; + Kokkos::View + hand_coded_duplicate_view("hand_coded_duplicate", num_threads, n); + auto f2 = KOKKOS_LAMBDA(int i) { + auto thread_id = unique_token.acquire(); + for (int j = 0; j < 10; ++j) { + auto k = (i + j) % n; + hand_coded_duplicate_view(thread_id, k, 0) += 4.2; + hand_coded_duplicate_view(thread_id, k, 1) += 2.0; + hand_coded_duplicate_view(thread_id, k, 2) += 1.0; + } + }; + Kokkos::Timer timer; + timer.reset(); + for (int k = 0; k < m; ++k) { + Kokkos::parallel_for(policy, f2, + "hand_coded_duplicate_scatter_view_test"); } - }; - Kokkos::Timer timer; - timer.reset(); - for (int k = 0; k < m; ++k) { - Kokkos::parallel_for(policy, f2, "hand_coded_duplicate_scatter_view_test"); + Kokkos::fence(); + auto t = timer.seconds(); + std::cout << "hand-coded test took " << t << " seconds\n"; } - Kokkos::fence(); - auto t = timer.seconds(); - std::cout << "hand-coded test took " << t << " seconds\n"; - } - { - auto f = KOKKOS_LAMBDA(int i) { - auto scatter_access = scatter_view.access(); - for (int j = 0; j < 10; ++j) { - auto k = (i + j) % n; - scatter_access(k, 0) += 4.2; - scatter_access(k, 1) += 2.0; - scatter_access(k, 2) += 1.0; + { + auto f = KOKKOS_LAMBDA(int i) { + auto scatter_access = scatter_view.access(); + for (int j = 0; j < 10; ++j) { + auto k = (i + j) % n; + scatter_access(k, 0) += 4.2; + scatter_access(k, 1) += 2.0; + scatter_access(k, 2) += 1.0; + } + }; + Kokkos::Timer timer; + timer.reset(); + for (int k = 0; k < m; ++k) { + Kokkos::parallel_for(policy, f, "scatter_view_test"); } - }; - Kokkos::Timer timer; - timer.reset(); - for (int k = 0; k < m; ++k) { - Kokkos::parallel_for(policy, f, "scatter_view_test"); + Kokkos::fence(); + auto t = timer.seconds(); + std::cout << "test took " << t << " seconds\n"; } - Kokkos::fence(); - auto t = timer.seconds(); - std::cout << "test took " << t << " seconds\n"; } } - } } -} +} // namespace Perf #endif diff --git a/lib/kokkos/containers/performance_tests/TestThreads.cpp b/lib/kokkos/containers/performance_tests/TestThreads.cpp index 6a02e67b25..2f37404539 100644 --- a/lib/kokkos/containers/performance_tests/TestThreads.cpp +++ b/lib/kokkos/containers/performance_tests/TestThreads.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,7 +43,7 @@ */ #include -#if defined( KOKKOS_ENABLE_THREADS ) +#if defined(KOKKOS_ENABLE_THREADS) #include @@ -65,9 +66,8 @@ namespace Performance { class threads : public ::testing::Test { -protected: - static void SetUpTestCase() - { + protected: + static void SetUpTestCase() { std::cout << std::setprecision(5) << std::scientific; unsigned num_threads = 4; @@ -76,66 +76,57 @@ protected: num_threads = Kokkos::hwloc::get_available_numa_count() * Kokkos::hwloc::get_available_cores_per_numa() * Kokkos::hwloc::get_available_threads_per_core(); - } std::cout << "Threads: " << num_threads << std::endl; - Kokkos::initialize( Kokkos::InitArguments(num_threads) ); + Kokkos::initialize(Kokkos::InitArguments(num_threads)); } - static void TearDownTestCase() - { - Kokkos::finalize(); - } + static void TearDownTestCase() { Kokkos::finalize(); } }; -TEST_F( threads, dynrankview_perf ) -{ +TEST_F(threads, dynrankview_perf) { std::cout << "Threads" << std::endl; std::cout << " DynRankView vs View: Initialization Only " << std::endl; - test_dynrankview_op_perf( 8192 ); + test_dynrankview_op_perf(8192); } -TEST_F( threads, global_2_local) -{ +TEST_F(threads, global_2_local) { std::cout << "Threads" << std::endl; std::cout << "size, create, generate, fill, find" << std::endl; - for (unsigned i=Performance::begin_id_size; i<=Performance::end_id_size; i *= Performance::id_step) + for (unsigned i = Performance::begin_id_size; i <= Performance::end_id_size; + i *= Performance::id_step) test_global_to_local_ids(i); } -TEST_F( threads, unordered_map_performance_near) -{ +TEST_F(threads, unordered_map_performance_near) { unsigned num_threads = 4; if (Kokkos::hwloc::available()) { num_threads = Kokkos::hwloc::get_available_numa_count() * Kokkos::hwloc::get_available_cores_per_numa() * Kokkos::hwloc::get_available_threads_per_core(); - } std::ostringstream base_file_name; base_file_name << "threads-" << num_threads << "-near"; - Perf::run_performance_tests(base_file_name.str()); + Perf::run_performance_tests(base_file_name.str()); } -TEST_F( threads, unordered_map_performance_far) -{ +TEST_F(threads, unordered_map_performance_far) { unsigned num_threads = 4; if (Kokkos::hwloc::available()) { num_threads = Kokkos::hwloc::get_available_numa_count() * Kokkos::hwloc::get_available_cores_per_numa() * Kokkos::hwloc::get_available_threads_per_core(); - } std::ostringstream base_file_name; base_file_name << "threads-" << num_threads << "-far"; - Perf::run_performance_tests(base_file_name.str()); + Perf::run_performance_tests(base_file_name.str()); } -} // namespace Performance +} // namespace Performance #else -void KOKKOS_CONTAINERS_PERFORMANCE_TESTS_TESTTHREADS_PREVENT_EMPTY_LINK_ERROR() {} +void KOKKOS_CONTAINERS_PERFORMANCE_TESTS_TESTTHREADS_PREVENT_EMPTY_LINK_ERROR() { +} #endif - diff --git a/lib/kokkos/containers/performance_tests/TestUnorderedMapPerformance.hpp b/lib/kokkos/containers/performance_tests/TestUnorderedMapPerformance.hpp index 8d09281ed3..9057842340 100644 --- a/lib/kokkos/containers/performance_tests/TestUnorderedMapPerformance.hpp +++ b/lib/kokkos/containers/performance_tests/TestUnorderedMapPerformance.hpp @@ -1,10 +1,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -22,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -50,12 +51,10 @@ #include #include - namespace Perf { template -struct UnorderedMapTest -{ +struct UnorderedMapTest { typedef Device execution_space; typedef Kokkos::UnorderedMap map_type; typedef typename map_type::histogram_type histogram_type; @@ -68,22 +67,22 @@ struct UnorderedMapTest uint32_t capacity; uint32_t inserts; uint32_t collisions; - double seconds; + double seconds; map_type map; histogram_type histogram; - UnorderedMapTest( uint32_t arg_capacity, uint32_t arg_inserts, uint32_t arg_collisions) - : capacity(arg_capacity) - , inserts(arg_inserts) - , collisions(arg_collisions) - , seconds(0) - , map(capacity) - , histogram(map.get_histogram()) - { - Kokkos::Timer wall_clock ; + UnorderedMapTest(uint32_t arg_capacity, uint32_t arg_inserts, + uint32_t arg_collisions) + : capacity(arg_capacity), + inserts(arg_inserts), + collisions(arg_collisions), + seconds(0), + map(capacity), + histogram(map.get_histogram()) { + Kokkos::Timer wall_clock; wall_clock.reset(); - value_type v = {}; + value_type v = {}; int loop_count = 0; do { ++loop_count; @@ -92,81 +91,79 @@ struct UnorderedMapTest Kokkos::parallel_reduce(inserts, *this, v); if (v.failed_count > 0u) { - const uint32_t new_capacity = map.capacity() + ((map.capacity()*3ull)/20u) + v.failed_count/collisions ; - map.rehash( new_capacity ); + const uint32_t new_capacity = map.capacity() + + ((map.capacity() * 3ull) / 20u) + + v.failed_count / collisions; + map.rehash(new_capacity); } } while (v.failed_count > 0u); seconds = wall_clock.seconds(); - switch (loop_count) - { - case 1u: std::cout << " \033[0;32m" << loop_count << "\033[0m "; break; - case 2u: std::cout << " \033[1;31m" << loop_count << "\033[0m "; break; - default: std::cout << " \033[0;31m" << loop_count << "\033[0m "; break; + switch (loop_count) { + case 1u: std::cout << " \033[0;32m" << loop_count << "\033[0m "; break; + case 2u: std::cout << " \033[1;31m" << loop_count << "\033[0m "; break; + default: std::cout << " \033[0;31m" << loop_count << "\033[0m "; break; } - std::cout << std::setprecision(2) << std::fixed << std::setw(5) << (1e9*(seconds/(inserts))) << "; " << std::flush; + std::cout << std::setprecision(2) << std::fixed << std::setw(5) + << (1e9 * (seconds / (inserts))) << "; " << std::flush; histogram.calculate(); Device().fence(); } - void print(std::ostream & metrics_out, std::ostream & length_out, std::ostream & distance_out, std::ostream & block_distance_out) - { + void print(std::ostream& metrics_out, std::ostream& length_out, + std::ostream& distance_out, std::ostream& block_distance_out) { metrics_out << map.capacity() << " , "; - metrics_out << inserts/collisions << " , "; - metrics_out << (100.0 * inserts/collisions) / map.capacity() << " , "; + metrics_out << inserts / collisions << " , "; + metrics_out << (100.0 * inserts / collisions) / map.capacity() << " , "; metrics_out << inserts << " , "; metrics_out << (map.failed_insert() ? "true" : "false") << " , "; metrics_out << collisions << " , "; - metrics_out << 1e9*(seconds/inserts) << " , "; + metrics_out << 1e9 * (seconds / inserts) << " , "; metrics_out << seconds << std::endl; length_out << map.capacity() << " , "; - length_out << ((100.0 *inserts/collisions) / map.capacity()) << " , "; + length_out << ((100.0 * inserts / collisions) / map.capacity()) << " , "; length_out << collisions << " , "; histogram.print_length(length_out); distance_out << map.capacity() << " , "; - distance_out << ((100.0 *inserts/collisions) / map.capacity()) << " , "; + distance_out << ((100.0 * inserts / collisions) / map.capacity()) << " , "; distance_out << collisions << " , "; histogram.print_distance(distance_out); block_distance_out << map.capacity() << " , "; - block_distance_out << ((100.0 *inserts/collisions) / map.capacity()) << " , "; + block_distance_out << ((100.0 * inserts / collisions) / map.capacity()) + << " , "; block_distance_out << collisions << " , "; histogram.print_block_distance(block_distance_out); } - KOKKOS_INLINE_FUNCTION - void init( value_type & v ) const - { + void init(value_type& v) const { v.failed_count = 0; - v.max_list = 0; + v.max_list = 0; } KOKKOS_INLINE_FUNCTION - void join( volatile value_type & dst, const volatile value_type & src ) const - { + void join(volatile value_type& dst, const volatile value_type& src) const { dst.failed_count += src.failed_count; dst.max_list = src.max_list < dst.max_list ? dst.max_list : src.max_list; } KOKKOS_INLINE_FUNCTION - void operator()(uint32_t i, value_type & v) const - { - const uint32_t key = Near ? i/collisions : i%(inserts/collisions); - typename map_type::insert_result result = map.insert(key,i); + void operator()(uint32_t i, value_type& v) const { + const uint32_t key = Near ? i / collisions : i % (inserts / collisions); + typename map_type::insert_result result = map.insert(key, i); v.failed_count += !result.failed() ? 0 : 1; - v.max_list = result.list_position() < v.max_list ? v.max_list : result.list_position(); + v.max_list = result.list_position() < v.max_list ? v.max_list + : result.list_position(); } - }; template -void run_performance_tests(std::string const & base_file_name) -{ +void run_performance_tests(std::string const& base_file_name) { #if 0 std::string metrics_file_name = base_file_name + std::string("-metrics.csv"); std::string length_file_name = base_file_name + std::string("-length.csv"); @@ -254,7 +251,6 @@ void run_performance_tests(std::string const & base_file_name) #endif } +} // namespace Perf -} // namespace Perf - -#endif //KOKKOS_TEST_UNORDERED_MAP_PERFORMANCE_HPP +#endif // KOKKOS_TEST_UNORDERED_MAP_PERFORMANCE_HPP diff --git a/lib/kokkos/containers/src/CMakeLists.txt b/lib/kokkos/containers/src/CMakeLists.txt index e68fcad5e9..0c9d24d641 100644 --- a/lib/kokkos/containers/src/CMakeLists.txt +++ b/lib/kokkos/containers/src/CMakeLists.txt @@ -1,47 +1,34 @@ - -TRIBITS_CONFIGURE_FILE(${PACKAGE_NAME}_config.h) - -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) - -#----------------------------------------------------------------------------- - -SET(TRILINOS_INCDIR ${CMAKE_INSTALL_PREFIX}/${${PROJECT_NAME}_INSTALL_INCLUDE_DIR}) - -if(KOKKOS_LEGACY_TRIBITS) - - SET(HEADERS "") - SET(SOURCES "") - - SET(HEADERS_IMPL "") - - FILE(GLOB HEADERS *.hpp) - FILE(GLOB HEADERS_IMPL impl/*.hpp) - FILE(GLOB SOURCES impl/*.cpp) - - INSTALL(FILES ${HEADERS_IMPL} DESTINATION ${TRILINOS_INCDIR}/impl/) - - TRIBITS_ADD_LIBRARY( - kokkoscontainers - HEADERS ${HEADERS} - NOINSTALLHEADERS ${HEADERS_IMPL} - SOURCES ${SOURCES} - DEPLIBS - ) - -else() - - INSTALL ( - DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" - DESTINATION ${TRILINOS_INCDIR} - FILES_MATCHING PATTERN "*.hpp" - ) - - TRIBITS_ADD_LIBRARY( - kokkoscontainers - SOURCES ${KOKKOS_CONTAINERS_SRCS} - DEPLIBS - ) - -endif() -#----------------------------------------------------------------------------- + +KOKKOS_CONFIGURE_FILE(${PACKAGE_NAME}_config.h) + +#need these here for now +KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +#----------------------------------------------------------------------------- + +SET(KOKKOS_CONTAINERS_SRCS) +APPEND_GLOB(KOKKOS_CONTAINERS_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/impl/*.cpp) + +INSTALL ( + DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" + DESTINATION ${KOKKOS_HEADER_DIR} + FILES_MATCHING PATTERN "*.hpp" +) + +KOKKOS_ADD_LIBRARY( + kokkoscontainers + SOURCES ${KOKKOS_CONTAINERS_SRCS} +) + +SET_TARGET_PROPERTIES(kokkoscontainers PROPERTIES VERSION ${Kokkos_VERSION}) + +KOKKOS_LIB_INCLUDE_DIRECTORIES(kokkoscontainers + ${KOKKOS_TOP_BUILD_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} +) +KOKKOS_LINK_INTERNAL_LIBRARY(kokkoscontainers kokkoscore) + +#----------------------------------------------------------------------------- + diff --git a/lib/kokkos/containers/src/Kokkos_Bitset.hpp b/lib/kokkos/containers/src/Kokkos_Bitset.hpp index 4d78430fc6..3596c7653a 100644 --- a/lib/kokkos/containers/src/Kokkos_Bitset.hpp +++ b/lib/kokkos/containers/src/Kokkos_Bitset.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -53,27 +54,25 @@ namespace Kokkos { -template +template class Bitset; -template +template class ConstBitset; template -void deep_copy( Bitset & dst, Bitset const& src); +void deep_copy(Bitset& dst, Bitset const& src); template -void deep_copy( Bitset & dst, ConstBitset const& src); +void deep_copy(Bitset& dst, ConstBitset const& src); template -void deep_copy( ConstBitset & dst, ConstBitset const& src); - +void deep_copy(ConstBitset& dst, ConstBitset const& src); /// A thread safe view to a bitset template -class Bitset -{ -public: +class Bitset { + public: typedef Device execution_space; typedef unsigned size_type; @@ -81,98 +80,88 @@ public: enum { MOVE_HINT_BACKWARD = 2u }; enum { - BIT_SCAN_FORWARD_MOVE_HINT_FORWARD = 0u - , BIT_SCAN_REVERSE_MOVE_HINT_FORWARD = BIT_SCAN_REVERSE - , BIT_SCAN_FORWARD_MOVE_HINT_BACKWARD = MOVE_HINT_BACKWARD - , BIT_SCAN_REVERSE_MOVE_HINT_BACKWARD = BIT_SCAN_REVERSE | MOVE_HINT_BACKWARD + BIT_SCAN_FORWARD_MOVE_HINT_FORWARD = 0u, + BIT_SCAN_REVERSE_MOVE_HINT_FORWARD = BIT_SCAN_REVERSE, + BIT_SCAN_FORWARD_MOVE_HINT_BACKWARD = MOVE_HINT_BACKWARD, + BIT_SCAN_REVERSE_MOVE_HINT_BACKWARD = BIT_SCAN_REVERSE | MOVE_HINT_BACKWARD }; -private: - enum { block_size = static_cast(sizeof(unsigned)*CHAR_BIT) }; - enum { block_mask = block_size-1u }; + private: + enum { block_size = static_cast(sizeof(unsigned) * CHAR_BIT) }; + enum { block_mask = block_size - 1u }; enum { block_shift = Kokkos::Impl::integral_power_of_two(block_size) }; -public: - - + public: /// constructor /// arg_size := number of bit in set Bitset(unsigned arg_size = 0u) - : m_size(arg_size) - , m_last_block_mask(0u) - , m_blocks("Bitset", ((m_size + block_mask) >> block_shift) ) - { - for (int i=0, end = static_cast(m_size & block_mask); i < end; ++i) { + : m_size(arg_size), + m_last_block_mask(0u), + m_blocks("Bitset", ((m_size + block_mask) >> block_shift)) { + for (int i = 0, end = static_cast(m_size & block_mask); i < end; ++i) { m_last_block_mask |= 1u << i; } } KOKKOS_INLINE_FUNCTION - Bitset (const Bitset&) = default; + Bitset(const Bitset&) = default; KOKKOS_INLINE_FUNCTION - Bitset& operator= (const Bitset&) = default; + Bitset& operator=(const Bitset&) = default; KOKKOS_INLINE_FUNCTION - Bitset (Bitset&&) = default; + Bitset(Bitset&&) = default; KOKKOS_INLINE_FUNCTION - Bitset& operator= (Bitset&&) = default; - + Bitset& operator=(Bitset&&) = default; + KOKKOS_INLINE_FUNCTION - ~Bitset () = default; + ~Bitset() = default; /// number of bits in the set /// can be call from the host or the device KOKKOS_FORCEINLINE_FUNCTION - unsigned size() const - { return m_size; } + unsigned size() const { return m_size; } /// number of bits which are set to 1 /// can only be called from the host - unsigned count() const - { - Impl::BitsetCount< Bitset > f(*this); + unsigned count() const { + Impl::BitsetCount > f(*this); return f.apply(); } /// set all bits to 1 /// can only be called from the host - void set() - { - Kokkos::deep_copy(m_blocks, ~0u ); + void set() { + Kokkos::deep_copy(m_blocks, ~0u); if (m_last_block_mask) { - //clear the unused bits in the last block - typedef Kokkos::Impl::DeepCopy< typename execution_space::memory_space, Kokkos::HostSpace > raw_deep_copy; - raw_deep_copy( m_blocks.data() + (m_blocks.extent(0) -1u), &m_last_block_mask, sizeof(unsigned)); + // clear the unused bits in the last block + typedef Kokkos::Impl::DeepCopy + raw_deep_copy; + raw_deep_copy(m_blocks.data() + (m_blocks.extent(0) - 1u), + &m_last_block_mask, sizeof(unsigned)); } } /// set all bits to 0 /// can only be called from the host - void reset() - { - Kokkos::deep_copy(m_blocks, 0u ); - } + void reset() { Kokkos::deep_copy(m_blocks, 0u); } /// set all bits to 0 /// can only be called from the host - void clear() - { - Kokkos::deep_copy(m_blocks, 0u ); - } + void clear() { Kokkos::deep_copy(m_blocks, 0u); } /// set i'th bit to 1 /// can only be called from the device KOKKOS_FORCEINLINE_FUNCTION - bool set( unsigned i ) const - { - if ( i < m_size ) { - unsigned * block_ptr = &m_blocks[ i >> block_shift ]; - const unsigned mask = 1u << static_cast( i & block_mask ); + bool set(unsigned i) const { + if (i < m_size) { + unsigned* block_ptr = &m_blocks[i >> block_shift]; + const unsigned mask = 1u << static_cast(i & block_mask); - return !( atomic_fetch_or( block_ptr, mask ) & mask ); + return !(atomic_fetch_or(block_ptr, mask) & mask); } return false; } @@ -180,13 +169,12 @@ public: /// set i'th bit to 0 /// can only be called from the device KOKKOS_FORCEINLINE_FUNCTION - bool reset( unsigned i ) const - { - if ( i < m_size ) { - unsigned * block_ptr = &m_blocks[ i >> block_shift ]; - const unsigned mask = 1u << static_cast( i & block_mask ); + bool reset(unsigned i) const { + if (i < m_size) { + unsigned* block_ptr = &m_blocks[i >> block_shift]; + const unsigned mask = 1u << static_cast(i & block_mask); - return atomic_fetch_and( block_ptr, ~mask ) & mask; + return atomic_fetch_and(block_ptr, ~mask) & mask; } return false; } @@ -194,11 +182,10 @@ public: /// return true if the i'th bit set to 1 /// can only be called from the device KOKKOS_FORCEINLINE_FUNCTION - bool test( unsigned i ) const - { - if ( i < m_size ) { - const unsigned block = volatile_load(&m_blocks[ i >> block_shift ]); - const unsigned mask = 1u << static_cast( i & block_mask ); + bool test(unsigned i) const { + if (i < m_size) { + const unsigned block = volatile_load(&m_blocks[i >> block_shift]); + const unsigned mask = 1u << static_cast(i & block_mask); return block & mask; } return false; @@ -208,90 +195,93 @@ public: /// returns the max number of times those functions should be call /// when searching for an available bit KOKKOS_FORCEINLINE_FUNCTION - unsigned max_hint() const - { - return m_blocks.extent(0); - } + unsigned max_hint() const { return m_blocks.extent(0); } /// find a bit set to 1 near the hint - /// returns a pair< bool, unsigned> where if result.first is true then result.second is the bit found - /// and if result.first is false the result.second is a new hint + /// returns a pair< bool, unsigned> where if result.first is true then + /// result.second is the bit found and if result.first is false the + /// result.second is a new hint KOKKOS_INLINE_FUNCTION - Kokkos::pair find_any_set_near( unsigned hint , unsigned scan_direction = BIT_SCAN_FORWARD_MOVE_HINT_FORWARD ) const - { - const unsigned block_idx = (hint >> block_shift) < m_blocks.extent(0) ? (hint >> block_shift) : 0; + Kokkos::pair find_any_set_near( + unsigned hint, + unsigned scan_direction = BIT_SCAN_FORWARD_MOVE_HINT_FORWARD) const { + const unsigned block_idx = + (hint >> block_shift) < m_blocks.extent(0) ? (hint >> block_shift) : 0; const unsigned offset = hint & block_mask; - unsigned block = volatile_load(&m_blocks[ block_idx ]); - block = !m_last_block_mask || (block_idx < (m_blocks.extent(0)-1)) ? block : block & m_last_block_mask ; + unsigned block = volatile_load(&m_blocks[block_idx]); + block = !m_last_block_mask || (block_idx < (m_blocks.extent(0) - 1)) + ? block + : block & m_last_block_mask; return find_any_helper(block_idx, offset, block, scan_direction); } /// find a bit set to 0 near the hint - /// returns a pair< bool, unsigned> where if result.first is true then result.second is the bit found - /// and if result.first is false the result.second is a new hint + /// returns a pair< bool, unsigned> where if result.first is true then + /// result.second is the bit found and if result.first is false the + /// result.second is a new hint KOKKOS_INLINE_FUNCTION - Kokkos::pair find_any_unset_near( unsigned hint , unsigned scan_direction = BIT_SCAN_FORWARD_MOVE_HINT_FORWARD ) const - { + Kokkos::pair find_any_unset_near( + unsigned hint, + unsigned scan_direction = BIT_SCAN_FORWARD_MOVE_HINT_FORWARD) const { const unsigned block_idx = hint >> block_shift; - const unsigned offset = hint & block_mask; - unsigned block = volatile_load(&m_blocks[ block_idx ]); - block = !m_last_block_mask || (block_idx < (m_blocks.extent(0)-1) ) ? ~block : ~block & m_last_block_mask ; + const unsigned offset = hint & block_mask; + unsigned block = volatile_load(&m_blocks[block_idx]); + block = !m_last_block_mask || (block_idx < (m_blocks.extent(0) - 1)) + ? ~block + : ~block & m_last_block_mask; return find_any_helper(block_idx, offset, block, scan_direction); } -private: - + private: KOKKOS_FORCEINLINE_FUNCTION - Kokkos::pair find_any_helper(unsigned block_idx, unsigned offset, unsigned block, unsigned scan_direction) const - { - Kokkos::pair result( block > 0u, 0); + Kokkos::pair find_any_helper(unsigned block_idx, + unsigned offset, unsigned block, + unsigned scan_direction) const { + Kokkos::pair result(block > 0u, 0); if (!result.first) { - result.second = update_hint( block_idx, offset, scan_direction ); - } - else { - result.second = scan_block( (block_idx << block_shift) - , offset - , block - , scan_direction - ); + result.second = update_hint(block_idx, offset, scan_direction); + } else { + result.second = + scan_block((block_idx << block_shift), offset, block, scan_direction); } return result; } - KOKKOS_FORCEINLINE_FUNCTION - unsigned scan_block(unsigned block_start, int offset, unsigned block, unsigned scan_direction ) const - { - offset = !(scan_direction & BIT_SCAN_REVERSE) ? offset : (offset + block_mask) & block_mask; + unsigned scan_block(unsigned block_start, int offset, unsigned block, + unsigned scan_direction) const { + offset = !(scan_direction & BIT_SCAN_REVERSE) + ? offset + : (offset + block_mask) & block_mask; block = Impl::rotate_right(block, offset); - return ((( !(scan_direction & BIT_SCAN_REVERSE) ? - Impl::bit_scan_forward(block) : - ::Kokkos::log2(block) - ) + offset - ) & block_mask - ) + block_start; + return (((!(scan_direction & BIT_SCAN_REVERSE) + ? Impl::bit_scan_forward(block) + : ::Kokkos::log2(block)) + + offset) & + block_mask) + + block_start; } KOKKOS_FORCEINLINE_FUNCTION - unsigned update_hint( long long block_idx, unsigned offset, unsigned scan_direction ) const - { + unsigned update_hint(long long block_idx, unsigned offset, + unsigned scan_direction) const { block_idx += scan_direction & MOVE_HINT_BACKWARD ? -1 : 1; block_idx = block_idx >= 0 ? block_idx : m_blocks.extent(0) - 1; - block_idx = block_idx < static_cast(m_blocks.extent(0)) ? block_idx : 0; + block_idx = + block_idx < static_cast(m_blocks.extent(0)) ? block_idx : 0; - return static_cast(block_idx)*block_size + offset; + return static_cast(block_idx) * block_size + offset; } -private: - + private: unsigned m_size; unsigned m_last_block_mask; - View< unsigned *, execution_space, MemoryTraits > m_blocks; + View > m_blocks; -private: + private: template friend class Bitset; @@ -302,87 +292,72 @@ private: friend struct Impl::BitsetCount; template - friend void deep_copy( Bitset & dst, Bitset const& src); + friend void deep_copy(Bitset& dst, Bitset const& src); template - friend void deep_copy( Bitset & dst, ConstBitset const& src); + friend void deep_copy(Bitset& dst, + ConstBitset const& src); }; /// a thread-safe view to a const bitset /// i.e. can only test bits template -class ConstBitset -{ -public: +class ConstBitset { + public: typedef Device execution_space; typedef unsigned size_type; -private: - enum { block_size = static_cast(sizeof(unsigned)*CHAR_BIT) }; - enum { block_mask = block_size -1u }; + private: + enum { block_size = static_cast(sizeof(unsigned) * CHAR_BIT) }; + enum { block_mask = block_size - 1u }; enum { block_shift = Kokkos::Impl::integral_power_of_two(block_size) }; -public: - ConstBitset() - : m_size (0) - {} + public: + ConstBitset() : m_size(0) {} ConstBitset(Bitset const& rhs) - : m_size(rhs.m_size) - , m_blocks(rhs.m_blocks) - {} + : m_size(rhs.m_size), m_blocks(rhs.m_blocks) {} ConstBitset(ConstBitset const& rhs) - : m_size( rhs.m_size ) - , m_blocks( rhs.m_blocks ) - {} + : m_size(rhs.m_size), m_blocks(rhs.m_blocks) {} - ConstBitset & operator = (Bitset const & rhs) - { - this->m_size = rhs.m_size; + ConstBitset& operator=(Bitset const& rhs) { + this->m_size = rhs.m_size; this->m_blocks = rhs.m_blocks; return *this; } - ConstBitset & operator = (ConstBitset const & rhs) - { - this->m_size = rhs.m_size; + ConstBitset& operator=(ConstBitset const& rhs) { + this->m_size = rhs.m_size; this->m_blocks = rhs.m_blocks; return *this; } - KOKKOS_FORCEINLINE_FUNCTION - unsigned size() const - { - return m_size; - } + unsigned size() const { return m_size; } - unsigned count() const - { - Impl::BitsetCount< ConstBitset > f(*this); + unsigned count() const { + Impl::BitsetCount > f(*this); return f.apply(); } KOKKOS_FORCEINLINE_FUNCTION - bool test( unsigned i ) const - { - if ( i < m_size ) { - const unsigned block = m_blocks[ i >> block_shift ]; - const unsigned mask = 1u << static_cast( i & block_mask ); + bool test(unsigned i) const { + if (i < m_size) { + const unsigned block = m_blocks[i >> block_shift]; + const unsigned mask = 1u << static_cast(i & block_mask); return block & mask; } return false; } -private: - + private: unsigned m_size; - View< const unsigned *, execution_space, MemoryTraits > m_blocks; + View > m_blocks; -private: + private: template friend class ConstBitset; @@ -390,47 +365,56 @@ private: friend struct Impl::BitsetCount; template - friend void deep_copy( Bitset & dst, ConstBitset const& src); + friend void deep_copy(Bitset& dst, + ConstBitset const& src); template - friend void deep_copy( ConstBitset & dst, ConstBitset const& src); + friend void deep_copy(ConstBitset& dst, + ConstBitset const& src); }; - template -void deep_copy( Bitset & dst, Bitset const& src) -{ +void deep_copy(Bitset& dst, Bitset const& src) { if (dst.size() != src.size()) { - throw std::runtime_error("Error: Cannot deep_copy bitsets of different sizes!"); + throw std::runtime_error( + "Error: Cannot deep_copy bitsets of different sizes!"); } - typedef Kokkos::Impl::DeepCopy< typename DstDevice::memory_space, typename SrcDevice::memory_space > raw_deep_copy; - raw_deep_copy(dst.m_blocks.data(), src.m_blocks.data(), sizeof(unsigned)*src.m_blocks.extent(0)); + typedef Kokkos::Impl::DeepCopy + raw_deep_copy; + raw_deep_copy(dst.m_blocks.data(), src.m_blocks.data(), + sizeof(unsigned) * src.m_blocks.extent(0)); } template -void deep_copy( Bitset & dst, ConstBitset const& src) -{ +void deep_copy(Bitset& dst, ConstBitset const& src) { if (dst.size() != src.size()) { - throw std::runtime_error("Error: Cannot deep_copy bitsets of different sizes!"); + throw std::runtime_error( + "Error: Cannot deep_copy bitsets of different sizes!"); } - typedef Kokkos::Impl::DeepCopy< typename DstDevice::memory_space, typename SrcDevice::memory_space > raw_deep_copy; - raw_deep_copy(dst.m_blocks.data(), src.m_blocks.data(), sizeof(unsigned)*src.m_blocks.extent(0)); + typedef Kokkos::Impl::DeepCopy + raw_deep_copy; + raw_deep_copy(dst.m_blocks.data(), src.m_blocks.data(), + sizeof(unsigned) * src.m_blocks.extent(0)); } template -void deep_copy( ConstBitset & dst, ConstBitset const& src) -{ +void deep_copy(ConstBitset& dst, ConstBitset const& src) { if (dst.size() != src.size()) { - throw std::runtime_error("Error: Cannot deep_copy bitsets of different sizes!"); + throw std::runtime_error( + "Error: Cannot deep_copy bitsets of different sizes!"); } - typedef Kokkos::Impl::DeepCopy< typename DstDevice::memory_space, typename SrcDevice::memory_space > raw_deep_copy; - raw_deep_copy(dst.m_blocks.data(), src.m_blocks.data(), sizeof(unsigned)*src.m_blocks.extent(0)); + typedef Kokkos::Impl::DeepCopy + raw_deep_copy; + raw_deep_copy(dst.m_blocks.data(), src.m_blocks.data(), + sizeof(unsigned) * src.m_blocks.extent(0)); } -} // namespace Kokkos - -#endif //KOKKOS_BITSET_HPP +} // namespace Kokkos +#endif // KOKKOS_BITSET_HPP diff --git a/lib/kokkos/containers/src/Kokkos_DualView.hpp b/lib/kokkos/containers/src/Kokkos_DualView.hpp index d9b14d67a2..d8a3ebc1ae 100644 --- a/lib/kokkos/containers/src/Kokkos_DualView.hpp +++ b/lib/kokkos/containers/src/Kokkos_DualView.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -90,47 +91,41 @@ namespace Kokkos { * behavior. Please see the documentation of Kokkos::View for * examples. The default suffices for most users. */ -template< class DataType , - class Arg1Type = void , - class Arg2Type = void , +template -class DualView : public ViewTraits< DataType , Arg1Type , Arg2Type, Arg3Type > -{ -template< class , class , class , class > friend class DualView ; -public: +class DualView : public ViewTraits { + template + friend class DualView; + + public: //! \name Typedefs for device types and various Kokkos::View specializations. //@{ - typedef ViewTraits< DataType , Arg1Type , Arg2Type, Arg3Type > traits ; + typedef ViewTraits traits; //! The Kokkos Host Device type; - typedef typename traits::host_mirror_space host_mirror_space ; + typedef typename traits::host_mirror_space host_mirror_space; //! The type of a Kokkos::View on the device. - typedef View< typename traits::data_type , - Arg1Type , - Arg2Type , - Arg3Type > t_dev ; + typedef View t_dev; /// \typedef t_host /// \brief The type of a Kokkos::View host mirror of \c t_dev. - typedef typename t_dev::HostMirror t_host ; + typedef typename t_dev::HostMirror t_host; //! The type of a const View on the device. //! The type of a Kokkos::View on the device. - typedef View< typename traits::const_data_type , - Arg1Type , - Arg2Type , - Arg3Type > t_dev_const ; + typedef View + t_dev_const; /// \typedef t_host_const /// \brief The type of a const View host mirror of \c t_dev_const. typedef typename t_dev_const::HostMirror t_host_const; //! The type of a const, random-access View on the device. - typedef View< typename traits::const_data_type , - typename traits::array_layout , - typename traits::device_type , - Kokkos::MemoryTraits > t_dev_const_randomread ; + typedef View > + t_dev_const_randomread; /// \typedef t_host_const_randomread /// \brief The type of a const, random-access View host mirror of @@ -138,39 +133,36 @@ public: typedef typename t_dev_const_randomread::HostMirror t_host_const_randomread; //! The type of an unmanaged View on the device. - typedef View< typename traits::data_type , - typename traits::array_layout , - typename traits::device_type , - MemoryUnmanaged> t_dev_um; + typedef View + t_dev_um; //! The type of an unmanaged View host mirror of \c t_dev_um. - typedef View< typename t_host::data_type , - typename t_host::array_layout , - typename t_host::device_type , - MemoryUnmanaged> t_host_um; + typedef View + t_host_um; //! The type of a const unmanaged View on the device. - typedef View< typename traits::const_data_type , - typename traits::array_layout , - typename traits::device_type , - MemoryUnmanaged> t_dev_const_um; + typedef View + t_dev_const_um; //! The type of a const unmanaged View host mirror of \c t_dev_const_um. - typedef View t_host_const_um; + typedef View + t_host_const_um; //! The type of a const, random-access View on the device. - typedef View< typename t_host::const_data_type , - typename t_host::array_layout , - typename t_host::device_type , - Kokkos::MemoryTraits > t_dev_const_randomread_um ; + typedef View > + t_dev_const_randomread_um; /// \typedef t_host_const_randomread /// \brief The type of a const, random-access View host mirror of /// \c t_dev_const_randomread. - typedef typename t_dev_const_randomread::HostMirror t_host_const_randomread_um; + typedef + typename t_dev_const_randomread::HostMirror t_host_const_randomread_um; //@} //! \name The two View instances. @@ -184,18 +176,20 @@ public: //@{ #ifndef KOKKOS_ENABLE_DEPRECATED_CODE -protected: + protected: // modified_flags[0] -> host // modified_flags[1] -> device - typedef View t_modified_flags; + typedef View t_modified_flags; t_modified_flags modified_flags; -public: + public: #else - typedef View t_modified_flags; - typedef View t_modified_flag; + typedef View + t_modified_flags; + typedef View + t_modified_flag; t_modified_flags modified_flags; - t_modified_flag modified_host,modified_device; + t_modified_flag modified_host, modified_device; #endif //@} @@ -208,11 +202,11 @@ public: /// default constructors. The "modified" flags are both initialized /// to "unmodified." #ifndef KOKKOS_ENABLE_DEPRECATED_CODE - DualView () = default; + DualView() = default; #else - DualView ():modified_flags (t_modified_flags("DualView::modified_flags")) { - modified_host = t_modified_flag(modified_flags,0); - modified_device = t_modified_flag(modified_flags,1); + DualView() : modified_flags(t_modified_flags("DualView::modified_flags")) { + modified_host = t_modified_flag(modified_flags, 0); + modified_device = t_modified_flag(modified_flags, 1); } #endif @@ -225,52 +219,52 @@ public: /// View objects. For example, if the View has three dimensions, /// the first three integer arguments will be nonzero, and you may /// omit the integer arguments that follow. - DualView (const std::string& label, - const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, - const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, - const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, - const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, - const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, - const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, - const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, - const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) - : d_view (label, n0, n1, n2, n3, n4, n5, n6, n7) - , h_view (create_mirror_view (d_view)) // without UVM, host View mirrors - , modified_flags (t_modified_flags("DualView::modified_flags")) - { + DualView(const std::string& label, + const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) + : d_view(label, n0, n1, n2, n3, n4, n5, n6, n7), + h_view(create_mirror_view(d_view)) // without UVM, host View mirrors + , + modified_flags(t_modified_flags("DualView::modified_flags")) { #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - modified_host = t_modified_flag(modified_flags,0); - modified_device = t_modified_flag(modified_flags,1); + modified_host = t_modified_flag(modified_flags, 0); + modified_device = t_modified_flag(modified_flags, 1); #endif } //! Copy constructor (shallow copy) - template - DualView (const DualView& src) : - d_view (src.d_view), - h_view (src.h_view), - modified_flags (src.modified_flags) + template + DualView(const DualView& src) + : d_view(src.d_view), + h_view(src.h_view), + modified_flags(src.modified_flags) #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - , modified_host(src.modified_host) - , modified_device(src.modified_device) + , + modified_host(src.modified_host), + modified_device(src.modified_device) #endif - {} + { + } //! Subview constructor - template< class SD, class S1 , class S2 , class S3 - , class Arg0 , class ... Args > - DualView( const DualView & src - , const Arg0 & arg0 - , Args ... args - ) - : d_view( Kokkos::subview( src.d_view , arg0 , args ... ) ) - , h_view( Kokkos::subview( src.h_view , arg0 , args ... ) ) - , modified_flags (src.modified_flags) + template + DualView(const DualView& src, const Arg0& arg0, Args... args) + : d_view(Kokkos::subview(src.d_view, arg0, args...)), + h_view(Kokkos::subview(src.h_view, arg0, args...)), + modified_flags(src.modified_flags) #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - , modified_host(src.modified_host) - , modified_device(src.modified_device) + , + modified_host(src.modified_host), + modified_device(src.modified_device) #endif - {} + { + } /// \brief Create DualView from existing device and host View objects. /// @@ -282,34 +276,34 @@ public: /// /// \param d_view_ Device View /// \param h_view_ Host View (must have type t_host = t_dev::HostMirror) - DualView (const t_dev& d_view_, const t_host& h_view_) : - d_view (d_view_), - h_view (h_view_), - modified_flags (t_modified_flags("DualView::modified_flags")) - { - if ( int(d_view.rank) != int(h_view.rank) || - d_view.extent(0) != h_view.extent(0) || - d_view.extent(1) != h_view.extent(1) || - d_view.extent(2) != h_view.extent(2) || - d_view.extent(3) != h_view.extent(3) || - d_view.extent(4) != h_view.extent(4) || - d_view.extent(5) != h_view.extent(5) || - d_view.extent(6) != h_view.extent(6) || - d_view.extent(7) != h_view.extent(7) || - d_view.stride_0() != h_view.stride_0() || - d_view.stride_1() != h_view.stride_1() || - d_view.stride_2() != h_view.stride_2() || - d_view.stride_3() != h_view.stride_3() || - d_view.stride_4() != h_view.stride_4() || - d_view.stride_5() != h_view.stride_5() || - d_view.stride_6() != h_view.stride_6() || - d_view.stride_7() != h_view.stride_7() || - d_view.span() != h_view.span() ) { - Kokkos::Impl::throw_runtime_exception("DualView constructed with incompatible views"); + DualView(const t_dev& d_view_, const t_host& h_view_) + : d_view(d_view_), + h_view(h_view_), + modified_flags(t_modified_flags("DualView::modified_flags")) { + if (int(d_view.rank) != int(h_view.rank) || + d_view.extent(0) != h_view.extent(0) || + d_view.extent(1) != h_view.extent(1) || + d_view.extent(2) != h_view.extent(2) || + d_view.extent(3) != h_view.extent(3) || + d_view.extent(4) != h_view.extent(4) || + d_view.extent(5) != h_view.extent(5) || + d_view.extent(6) != h_view.extent(6) || + d_view.extent(7) != h_view.extent(7) || + d_view.stride_0() != h_view.stride_0() || + d_view.stride_1() != h_view.stride_1() || + d_view.stride_2() != h_view.stride_2() || + d_view.stride_3() != h_view.stride_3() || + d_view.stride_4() != h_view.stride_4() || + d_view.stride_5() != h_view.stride_5() || + d_view.stride_6() != h_view.stride_6() || + d_view.stride_7() != h_view.stride_7() || + d_view.span() != h_view.span()) { + Kokkos::Impl::throw_runtime_exception( + "DualView constructed with incompatible views"); } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - modified_host = t_modified_flag(modified_flags,0); - modified_device = t_modified_flag(modified_flags,1); + modified_host = t_modified_flag(modified_flags, 0); + modified_device = t_modified_flag(modified_flags, 1); #endif } @@ -326,119 +320,133 @@ public: /// /// For example, suppose you create a DualView on Cuda, like this: /// \code - /// typedef Kokkos::DualView dual_view_type; - /// dual_view_type DV ("my dual view", 100); - /// \endcode - /// If you want to get the CUDA device View, do this: - /// \code - /// typename dual_view_type::t_dev cudaView = DV.view (); - /// \endcode - /// and if you want to get the host mirror of that View, do this: - /// \code - /// typedef typename Kokkos::HostSpace::execution_space host_device_type; - /// typename dual_view_type::t_host hostView = DV.view (); - /// \endcode - template< class Device > - KOKKOS_INLINE_FUNCTION - const typename Impl::if_c< - std::is_same::value, - t_dev, - t_host>::type& view () const - { - #ifndef KOKKOS_ENABLE_DEPRECATED_CODE - constexpr bool device_is_memspace = std::is_same::value; - constexpr bool device_is_execspace = std::is_same::value; - constexpr bool device_exec_is_t_dev_exec = std::is_same::value; - constexpr bool device_mem_is_t_dev_mem = std::is_same::value; - constexpr bool device_exec_is_t_host_exec = std::is_same::value; - constexpr bool device_mem_is_t_host_mem = std::is_same::value; - constexpr bool device_is_t_host_device = std::is_same::value; - constexpr bool device_is_t_dev_device = std::is_same::value; + /// typedef Kokkos::DualView + /// dual_view_type; dual_view_type DV ("my dual view", 100); \endcode If you + /// want to get the CUDA device View, do this: \code typename + /// dual_view_type::t_dev cudaView = DV.view (); \endcode and if + /// you want to get the host mirror of that View, do this: \code typedef + /// typename Kokkos::HostSpace::execution_space host_device_type; typename + /// dual_view_type::t_host hostView = DV.view (); \endcode + template + KOKKOS_INLINE_FUNCTION const typename Impl::if_c< + std::is_same::value, + t_dev, t_host>::type& + view() const { +#ifndef KOKKOS_ENABLE_DEPRECATED_CODE + constexpr bool device_is_memspace = + std::is_same::value; + constexpr bool device_is_execspace = + std::is_same::value; + constexpr bool device_exec_is_t_dev_exec = + std::is_same::value; + constexpr bool device_mem_is_t_dev_mem = + std::is_same::value; + constexpr bool device_exec_is_t_host_exec = + std::is_same::value; + constexpr bool device_mem_is_t_host_mem = + std::is_same::value; + constexpr bool device_is_t_host_device = + std::is_same::value; + constexpr bool device_is_t_dev_device = + std::is_same::value; static_assert( device_is_t_dev_device || device_is_t_host_device || - (device_is_memspace && (device_mem_is_t_dev_mem || device_mem_is_t_host_mem) ) || - (device_is_execspace && (device_exec_is_t_dev_exec || device_exec_is_t_host_exec) ) || - ( - (!device_is_execspace && !device_is_memspace) && ( - (device_mem_is_t_dev_mem || device_mem_is_t_host_mem) || - (device_exec_is_t_dev_exec || device_exec_is_t_host_exec) - ) - ) - , - "Template parameter to .view() must exactly match one of the DualView's device types or one of the execution or memory spaces"); - #endif - - return Impl::if_c< - std::is_same< - typename t_dev::memory_space, - typename Device::memory_space>::value, - t_dev, - t_host >::select (d_view , h_view); + (device_is_memspace && + (device_mem_is_t_dev_mem || device_mem_is_t_host_mem)) || + (device_is_execspace && + (device_exec_is_t_dev_exec || device_exec_is_t_host_exec)) || + ((!device_is_execspace && !device_is_memspace) && + ((device_mem_is_t_dev_mem || device_mem_is_t_host_mem) || + (device_exec_is_t_dev_exec || device_exec_is_t_host_exec))), + "Template parameter to .view() must exactly match one of the " + "DualView's device types or one of the execution or memory spaces"); +#endif + + return Impl::if_c::value, + t_dev, t_host>::select(d_view, h_view); } KOKKOS_INLINE_FUNCTION - t_host view_host() const { - return h_view; - } + t_host view_host() const { return h_view; } KOKKOS_INLINE_FUNCTION - t_dev view_device() const { - return d_view; - } + t_dev view_device() const { return d_view; } - template + template static int get_device_side() { - constexpr bool device_is_memspace = std::is_same::value; - constexpr bool device_is_execspace = std::is_same::value; - constexpr bool device_exec_is_t_dev_exec = std::is_same::value; - constexpr bool device_mem_is_t_dev_mem = std::is_same::value; - constexpr bool device_exec_is_t_host_exec = std::is_same::value; - constexpr bool device_mem_is_t_host_mem = std::is_same::value; - constexpr bool device_is_t_host_device = std::is_same::value; - constexpr bool device_is_t_dev_device = std::is_same::value; - - #ifndef KOKKOS_ENABLE_DEPRECATED_CODE + constexpr bool device_is_memspace = + std::is_same::value; + constexpr bool device_is_execspace = + std::is_same::value; + constexpr bool device_exec_is_t_dev_exec = + std::is_same::value; + constexpr bool device_mem_is_t_dev_mem = + std::is_same::value; + constexpr bool device_exec_is_t_host_exec = + std::is_same::value; + constexpr bool device_mem_is_t_host_mem = + std::is_same::value; + constexpr bool device_is_t_host_device = + std::is_same::value; + constexpr bool device_is_t_dev_device = + std::is_same::value; + +#ifndef KOKKOS_ENABLE_DEPRECATED_CODE static_assert( device_is_t_dev_device || device_is_t_host_device || - (device_is_memspace && (device_mem_is_t_dev_mem || device_mem_is_t_host_mem) ) || - (device_is_execspace && (device_exec_is_t_dev_exec || device_exec_is_t_host_exec) ) || - ( - (!device_is_execspace && !device_is_memspace) && ( - (device_mem_is_t_dev_mem || device_mem_is_t_host_mem) || - (device_exec_is_t_dev_exec || device_exec_is_t_host_exec) - ) - ) - , - "Template parameter to .sync() must exactly match one of the DualView's device types or one of the execution or memory spaces"); - #endif + (device_is_memspace && + (device_mem_is_t_dev_mem || device_mem_is_t_host_mem)) || + (device_is_execspace && + (device_exec_is_t_dev_exec || device_exec_is_t_host_exec)) || + ((!device_is_execspace && !device_is_memspace) && + ((device_mem_is_t_dev_mem || device_mem_is_t_host_mem) || + (device_exec_is_t_dev_exec || device_exec_is_t_host_exec))), + "Template parameter to .sync() must exactly match one of the " + "DualView's device types or one of the execution or memory spaces"); +#endif - #ifndef KOKKOS_ENABLE_DEPRECATED_CODE +#ifndef KOKKOS_ENABLE_DEPRECATED_CODE int dev = -1; - #else +#else int dev = 0; - #endif - if(device_is_t_dev_device) dev = 1; - else if(device_is_t_host_device) dev = 0; +#endif + if (device_is_t_dev_device) + dev = 1; + else if (device_is_t_host_device) + dev = 0; else { - if(device_is_memspace) { - if(device_mem_is_t_dev_mem) dev = 1; - if(device_mem_is_t_host_mem) dev = 0; - if(device_mem_is_t_host_mem && device_mem_is_t_dev_mem) dev = -1; + if (device_is_memspace) { + if (device_mem_is_t_dev_mem) dev = 1; + if (device_mem_is_t_host_mem) dev = 0; + if (device_mem_is_t_host_mem && device_mem_is_t_dev_mem) dev = -1; } - if(device_is_execspace) { - if(device_exec_is_t_dev_exec) dev = 1; - if(device_exec_is_t_host_exec) dev = 0; - if(device_exec_is_t_host_exec && device_exec_is_t_dev_exec) dev = -1; + if (device_is_execspace) { + if (device_exec_is_t_dev_exec) dev = 1; + if (device_exec_is_t_host_exec) dev = 0; + if (device_exec_is_t_host_exec && device_exec_is_t_dev_exec) dev = -1; } - if(!device_is_execspace && !device_is_memspace) { - if(device_mem_is_t_dev_mem) dev = 1; - if(device_mem_is_t_host_mem) dev = 0; - if(device_mem_is_t_host_mem && device_mem_is_t_dev_mem) dev = -1; - if(device_exec_is_t_dev_exec) dev = 1; - if(device_exec_is_t_host_exec) dev = 0; - if(device_exec_is_t_host_exec && device_exec_is_t_dev_exec) dev = -1; + if (!device_is_execspace && !device_is_memspace) { + if (device_mem_is_t_dev_mem) dev = 1; + if (device_mem_is_t_host_mem) dev = 0; + if (device_mem_is_t_host_mem && device_mem_is_t_dev_mem) dev = -1; + if (device_exec_is_t_dev_exec) dev = 1; + if (device_exec_is_t_host_exec) dev = 0; + if (device_exec_is_t_host_exec && device_exec_is_t_dev_exec) dev = -1; } } return dev; @@ -461,88 +469,94 @@ public: /// the data in either View. You must manually mark modified data /// as modified, by calling the modify() method with the /// appropriate template parameter. - template - void sync( const typename Impl::enable_if< - ( std::is_same< typename traits::data_type , typename traits::non_const_data_type>::value) || - ( std::is_same< Device , int>::value) - , int >::type& = 0) - { - if(modified_flags.data()==NULL) return; + template + void sync(const typename Impl::enable_if< + (std::is_same::value) || + (std::is_same::value), + int>::type& = 0) { + if (modified_flags.data() == NULL) return; int dev = get_device_side(); - if (dev == 1) { // if Device is the same as DualView's device type + if (dev == 1) { // if Device is the same as DualView's device type if ((modified_flags(0) > 0) && (modified_flags(0) >= modified_flags(1))) { - deep_copy (d_view, h_view); + deep_copy(d_view, h_view); modified_flags(0) = modified_flags(1) = 0; } } - if (dev == 0) { // hopefully Device is the same as DualView's host type + if (dev == 0) { // hopefully Device is the same as DualView's host type if ((modified_flags(1) > 0) && (modified_flags(1) >= modified_flags(0))) { - deep_copy (h_view, d_view); + deep_copy(h_view, d_view); modified_flags(0) = modified_flags(1) = 0; } } - if(std::is_same::value) { + if (std::is_same::value) { typename t_dev::execution_space().fence(); typename t_host::execution_space().fence(); } } - template - void sync ( const typename Impl::enable_if< - ( ! std::is_same< typename traits::data_type , typename traits::non_const_data_type>::value ) || - ( std::is_same< Device , int>::value) - , int >::type& = 0 ) - { - if(modified_flags.data()==NULL) return; + template + void sync(const typename Impl::enable_if< + (!std::is_same::value) || + (std::is_same::value), + int>::type& = 0) { + if (modified_flags.data() == NULL) return; int dev = get_device_side(); - if (dev == 1) { // if Device is the same as DualView's device type + if (dev == 1) { // if Device is the same as DualView's device type if ((modified_flags(0) > 0) && (modified_flags(0) >= modified_flags(1))) { - Impl::throw_runtime_exception("Calling sync on a DualView with a const datatype."); + Impl::throw_runtime_exception( + "Calling sync on a DualView with a const datatype."); } } - if (dev == 0){ // hopefully Device is the same as DualView's host type + if (dev == 0) { // hopefully Device is the same as DualView's host type if ((modified_flags(1) > 0) && (modified_flags(1) >= modified_flags(0))) { - Impl::throw_runtime_exception("Calling sync on a DualView with a const datatype."); + Impl::throw_runtime_exception( + "Calling sync on a DualView with a const datatype."); } } } void sync_host() { - if( ! std::is_same< typename traits::data_type , typename traits::non_const_data_type>::value ) - Impl::throw_runtime_exception("Calling sync_host on a DualView with a const datatype."); - if(modified_flags.data()==NULL) return; - if(modified_flags(1) > modified_flags(0)) { - deep_copy (h_view, d_view); + if (!std::is_same::value) + Impl::throw_runtime_exception( + "Calling sync_host on a DualView with a const datatype."); + if (modified_flags.data() == NULL) return; + if (modified_flags(1) > modified_flags(0)) { + deep_copy(h_view, d_view); modified_flags(1) = modified_flags(0) = 0; } } void sync_device() { - if( ! std::is_same< typename traits::data_type , typename traits::non_const_data_type>::value ) - Impl::throw_runtime_exception("Calling sync_device on a DualView with a const datatype."); - if(modified_flags.data()==NULL) return; - if(modified_flags(0) > modified_flags(1)) { - deep_copy (d_view, h_view); + if (!std::is_same::value) + Impl::throw_runtime_exception( + "Calling sync_device on a DualView with a const datatype."); + if (modified_flags.data() == NULL) return; + if (modified_flags(0) > modified_flags(1)) { + deep_copy(d_view, h_view); modified_flags(1) = modified_flags(0) = 0; } } - template - bool need_sync() const - { - if(modified_flags.data()==NULL) return false; + template + bool need_sync() const { + if (modified_flags.data() == NULL) return false; int dev = get_device_side(); - if (dev == 1) { // if Device is the same as DualView's device type + if (dev == 1) { // if Device is the same as DualView's device type if ((modified_flags(0) > 0) && (modified_flags(0) >= modified_flags(1))) { return true; } } - if (dev == 0){ // hopefully Device is the same as DualView's host type + if (dev == 0) { // hopefully Device is the same as DualView's host type if ((modified_flags(1) > 0) && (modified_flags(1) >= modified_flags(0))) { return true; } @@ -551,13 +565,13 @@ public: } inline bool need_sync_host() const { - if(modified_flags.data()==NULL) return false; - return modified_flags(0) - void modify () { - if(modified_flags.data()==NULL) return; + template + void modify() { + if (modified_flags.data() == NULL) return; int dev = get_device_side(); - if (dev == 1) { // if Device is the same as DualView's device type + if (dev == 1) { // if Device is the same as DualView's device type // Increment the device's modified count. - modified_flags(1) = (modified_flags(1) > modified_flags(0) ? - modified_flags(1) : modified_flags(0)) + 1; + modified_flags(1) = + (modified_flags(1) > modified_flags(0) ? modified_flags(1) + : modified_flags(0)) + + 1; } - if (dev == 0) { // hopefully Device is the same as DualView's host type + if (dev == 0) { // hopefully Device is the same as DualView's host type // Increment the host's modified count. - modified_flags(0) = (modified_flags(1) > modified_flags(0) ? - modified_flags(1) : modified_flags(0)) + 1; + modified_flags(0) = + (modified_flags(1) > modified_flags(0) ? modified_flags(1) + : modified_flags(0)) + + 1; } #ifdef KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK @@ -594,10 +612,12 @@ public: } inline void modify_host() { - if(modified_flags.data()!=NULL) { - modified_flags(0) = (modified_flags(1) > modified_flags(0) ? - modified_flags(1) : modified_flags(0)) + 1; - #ifdef KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK + if (modified_flags.data() != NULL) { + modified_flags(0) = + (modified_flags(1) > modified_flags(0) ? modified_flags(1) + : modified_flags(0)) + + 1; +#ifdef KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK if (modified_flags(0) && modified_flags(1)) { std::string msg = "Kokkos::DualView::modify_host ERROR: "; msg += "Concurrent modification of host and device views "; @@ -606,15 +626,17 @@ public: msg += "\"\n"; Kokkos::abort(msg.c_str()); } - #endif +#endif } } inline void modify_device() { - if(modified_flags.data()!=NULL) { - modified_flags(1) = (modified_flags(1) > modified_flags(0) ? - modified_flags(1) : modified_flags(0)) + 1; - #ifdef KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK + if (modified_flags.data() != NULL) { + modified_flags(1) = + (modified_flags(1) > modified_flags(0) ? modified_flags(1) + : modified_flags(0)) + + 1; +#ifdef KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK if (modified_flags(0) && modified_flags(1)) { std::string msg = "Kokkos::DualView::modify_device ERROR: "; msg += "Concurrent modification of host and device views "; @@ -623,12 +645,12 @@ public: msg += "\"\n"; Kokkos::abort(msg.c_str()); } - #endif +#endif } } inline void clear_sync_state() { - if(modified_flags.data()!=NULL) + if (modified_flags.data() != NULL) modified_flags(1) = modified_flags(0) = 0; } @@ -641,75 +663,72 @@ public: /// This discards any existing contents of the objects, and resets /// their modified flags. It does not copy the old contents /// of either View into the new View objects. - void realloc( const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG ) { - ::Kokkos::realloc(d_view,n0,n1,n2,n3,n4,n5,n6,n7); - h_view = create_mirror_view( d_view ); - - /* Reset dirty flags */ - if(modified_flags.data()==NULL) { - modified_flags = t_modified_flags("DualView::modified_flags"); - } else - modified_flags(1) = modified_flags(0) = 0; + void realloc(const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) { + ::Kokkos::realloc(d_view, n0, n1, n2, n3, n4, n5, n6, n7); + h_view = create_mirror_view(d_view); + + /* Reset dirty flags */ + if (modified_flags.data() == NULL) { + modified_flags = t_modified_flags("DualView::modified_flags"); + } else + modified_flags(1) = modified_flags(0) = 0; } /// \brief Resize both views, copying old contents into new if necessary. /// /// This method only copies the old contents into the new View /// objects for the device which was last marked as modified. - void resize( const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG ) { - if(modified_flags.data()==NULL) { - modified_flags = t_modified_flags("DualView::modified_flags"); - } - if(modified_flags(1) >= modified_flags(0)) { - /* Resize on Device */ - ::Kokkos::resize(d_view,n0,n1,n2,n3,n4,n5,n6,n7); - h_view = create_mirror_view( d_view ); - - /* Mark Device copy as modified */ - modified_flags(1) = modified_flags(1)+1; - - } else { - /* Realloc on Device */ - - ::Kokkos::realloc(d_view,n0,n1,n2,n3,n4,n5,n6,n7); - - const bool sizeMismatch = ( h_view.extent(0) != n0 ) || - ( h_view.extent(1) != n1 ) || - ( h_view.extent(2) != n2 ) || - ( h_view.extent(3) != n3 ) || - ( h_view.extent(4) != n4 ) || - ( h_view.extent(5) != n5 ) || - ( h_view.extent(6) != n6 ) || - ( h_view.extent(7) != n7 ); - if ( sizeMismatch ) - ::Kokkos::resize(h_view,n0,n1,n2,n3,n4,n5,n6,n7); - - t_host temp_view = create_mirror_view( d_view ); - - /* Remap on Host */ - Kokkos::deep_copy( temp_view , h_view ); - - h_view = temp_view; - - d_view = create_mirror_view( typename t_dev::execution_space(), h_view ); - - /* Mark Host copy as modified */ - modified_flags(0) = modified_flags(0)+1; - } + void resize(const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) { + if (modified_flags.data() == NULL) { + modified_flags = t_modified_flags("DualView::modified_flags"); + } + if (modified_flags(1) >= modified_flags(0)) { + /* Resize on Device */ + ::Kokkos::resize(d_view, n0, n1, n2, n3, n4, n5, n6, n7); + h_view = create_mirror_view(d_view); + + /* Mark Device copy as modified */ + modified_flags(1) = modified_flags(1) + 1; + + } else { + /* Realloc on Device */ + + ::Kokkos::realloc(d_view, n0, n1, n2, n3, n4, n5, n6, n7); + + const bool sizeMismatch = + (h_view.extent(0) != n0) || (h_view.extent(1) != n1) || + (h_view.extent(2) != n2) || (h_view.extent(3) != n3) || + (h_view.extent(4) != n4) || (h_view.extent(5) != n5) || + (h_view.extent(6) != n6) || (h_view.extent(7) != n7); + if (sizeMismatch) + ::Kokkos::resize(h_view, n0, n1, n2, n3, n4, n5, n6, n7); + + t_host temp_view = create_mirror_view(d_view); + + /* Remap on Host */ + Kokkos::deep_copy(temp_view, h_view); + + h_view = temp_view; + + d_view = create_mirror_view(typename t_dev::execution_space(), h_view); + + /* Mark Host copy as modified */ + modified_flags(0) = modified_flags(0) + 1; + } } //@} @@ -718,37 +737,35 @@ public: #ifdef KOKKOS_ENABLE_DEPRECATED_CODE //! The allocation size (same as Kokkos::View::capacity). - size_t capacity() const { - return d_view.span(); - } + size_t capacity() const { return d_view.span(); } #endif //! The allocation size (same as Kokkos::View::span). - KOKKOS_INLINE_FUNCTION constexpr size_t span() const { - return d_view.span(); - } + KOKKOS_INLINE_FUNCTION constexpr size_t span() const { return d_view.span(); } - KOKKOS_INLINE_FUNCTION bool span_is_contiguous() const { - return d_view.span_is_contiguous(); + KOKKOS_INLINE_FUNCTION bool span_is_contiguous() const { + return d_view.span_is_contiguous(); } //! Get stride(s) for each dimension. - template< typename iType> + template void stride(iType* stride_) const { d_view.stride(stride_); } - template< typename iType > - KOKKOS_INLINE_FUNCTION constexpr - typename std::enable_if< std::is_integral::value , size_t >::type - extent( const iType & r ) const - { return d_view.extent(r); } + template + KOKKOS_INLINE_FUNCTION constexpr + typename std::enable_if::value, size_t>::type + extent(const iType& r) const { + return d_view.extent(r); + } - template< typename iType > - KOKKOS_INLINE_FUNCTION constexpr - typename std::enable_if< std::is_integral::value , int >::type - extent_int( const iType & r ) const - { return static_cast(d_view.extent(r)); } + template + KOKKOS_INLINE_FUNCTION constexpr + typename std::enable_if::value, int>::type + extent_int(const iType& r) const { + return static_cast(d_view.extent(r)); + } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE /* Deprecate all 'dimension' functions in favor of @@ -756,27 +773,27 @@ public: */ /* \brief return size of dimension 0 */ - size_t dimension_0() const {return d_view.extent(0);} + size_t dimension_0() const { return d_view.extent(0); } /* \brief return size of dimension 1 */ - size_t dimension_1() const {return d_view.extent(1);} + size_t dimension_1() const { return d_view.extent(1); } /* \brief return size of dimension 2 */ - size_t dimension_2() const {return d_view.extent(2);} + size_t dimension_2() const { return d_view.extent(2); } /* \brief return size of dimension 3 */ - size_t dimension_3() const {return d_view.extent(3);} + size_t dimension_3() const { return d_view.extent(3); } /* \brief return size of dimension 4 */ - size_t dimension_4() const {return d_view.extent(4);} + size_t dimension_4() const { return d_view.extent(4); } /* \brief return size of dimension 5 */ - size_t dimension_5() const {return d_view.extent(5);} + size_t dimension_5() const { return d_view.extent(5); } /* \brief return size of dimension 6 */ - size_t dimension_6() const {return d_view.extent(6);} + size_t dimension_6() const { return d_view.extent(6); } /* \brief return size of dimension 7 */ - size_t dimension_7() const {return d_view.extent(7);} + size_t dimension_7() const { return d_view.extent(7); } #endif //@} }; -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -787,32 +804,24 @@ public: namespace Kokkos { namespace Impl { -template< class D, class A1, class A2, class A3, class ... Args > +template struct DualViewSubview { + typedef typename Kokkos::Impl::ViewMapping< + void, Kokkos::ViewTraits, Args...>::traits_type dst_traits; - typedef typename Kokkos::Impl::ViewMapping - < void - , Kokkos::ViewTraits< D, A1, A2, A3 > - , Args ... - >::traits_type dst_traits ; - - typedef Kokkos::DualView - < typename dst_traits::data_type - , typename dst_traits::array_layout - , typename dst_traits::device_type - , typename dst_traits::memory_traits - > type ; + typedef Kokkos::DualView< + typename dst_traits::data_type, typename dst_traits::array_layout, + typename dst_traits::device_type, typename dst_traits::memory_traits> + type; }; } /* namespace Impl */ - -template< class D , class A1 , class A2 , class A3 , class ... Args > -typename Impl::DualViewSubview::type -subview( const DualView & src , Args ... args ) -{ - return typename - Impl::DualViewSubview::type( src , args ... ); +template +typename Impl::DualViewSubview::type subview( + const DualView& src, Args... args) { + return typename Impl::DualViewSubview::type(src, + args...); } } /* namespace Kokkos */ @@ -826,40 +835,35 @@ namespace Kokkos { // Partial specialization of Kokkos::deep_copy() for DualView objects. // -template< class DT , class DL , class DD , class DM , - class ST , class SL , class SD , class SM > -void -deep_copy (DualView dst, // trust me, this must not be a reference - const DualView& src ) -{ - if ( src.need_sync_device() ) { - deep_copy (dst.h_view, src.h_view); +template +void deep_copy( + DualView dst, // trust me, this must not be a reference + const DualView& src) { + if (src.need_sync_device()) { + deep_copy(dst.h_view, src.h_view); dst.modify_host(); - } - else { - deep_copy (dst.d_view, src.d_view); + } else { + deep_copy(dst.d_view, src.d_view); dst.modify_device(); - } + } } -template< class ExecutionSpace , - class DT , class DL , class DD , class DM , - class ST , class SL , class SD , class SM > -void -deep_copy (const ExecutionSpace& exec , - DualView dst, // trust me, this must not be a reference - const DualView& src ) -{ - if ( src.need_sync_device() ) { - deep_copy (exec, dst.h_view, src.h_view); +template +void deep_copy( + const ExecutionSpace& exec, + DualView dst, // trust me, this must not be a reference + const DualView& src) { + if (src.need_sync_device()) { + deep_copy(exec, dst.h_view, src.h_view); dst.modify_host(); } else { - deep_copy (exec, dst.d_view, src.d_view); + deep_copy(exec, dst.d_view, src.d_view); dst.modify_device(); } } -} // namespace Kokkos +} // namespace Kokkos #endif - diff --git a/lib/kokkos/containers/src/Kokkos_DynRankView.hpp b/lib/kokkos/containers/src/Kokkos_DynRankView.hpp index d1e6704a57..0ceb9d5d39 100644 --- a/lib/kokkos/containers/src/Kokkos_DynRankView.hpp +++ b/lib/kokkos/containers/src/Kokkos_DynRankView.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -56,255 +57,240 @@ namespace Kokkos { -template< typename DataType , class ... Properties > -class DynRankView; //forward declare +template +class DynRankView; // forward declare namespace Impl { template struct DynRankDimTraits { - - enum : size_t{unspecified = KOKKOS_INVALID_INDEX}; + enum : size_t { unspecified = KOKKOS_INVALID_INDEX }; // Compute the rank of the view from the nonzero dimension arguments. KOKKOS_INLINE_FUNCTION - static size_t computeRank( const size_t N0 - , const size_t N1 - , const size_t N2 - , const size_t N3 - , const size_t N4 - , const size_t N5 - , const size_t N6 - , const size_t /* N7 */) - { - return - ( (N6 == unspecified && N5 == unspecified && N4 == unspecified && N3 == unspecified && N2 == unspecified && N1 == unspecified && N0 == unspecified) ? 0 - : ( (N6 == unspecified && N5 == unspecified && N4 == unspecified && N3 == unspecified && N2 == unspecified && N1 == unspecified) ? 1 - : ( (N6 == unspecified && N5 == unspecified && N4 == unspecified && N3 == unspecified && N2 == unspecified) ? 2 - : ( (N6 == unspecified && N5 == unspecified && N4 == unspecified && N3 == unspecified) ? 3 - : ( (N6 == unspecified && N5 == unspecified && N4 == unspecified) ? 4 - : ( (N6 == unspecified && N5 == unspecified) ? 5 - : ( (N6 == unspecified) ? 6 - : 7 ) ) ) ) ) ) ); + static size_t computeRank(const size_t N0, const size_t N1, const size_t N2, + const size_t N3, const size_t N4, const size_t N5, + const size_t N6, const size_t /* N7 */) { + return ( + (N6 == unspecified && N5 == unspecified && N4 == unspecified && + N3 == unspecified && N2 == unspecified && N1 == unspecified && + N0 == unspecified) + ? 0 + : ((N6 == unspecified && N5 == unspecified && N4 == unspecified && + N3 == unspecified && N2 == unspecified && N1 == unspecified) + ? 1 + : ((N6 == unspecified && N5 == unspecified && + N4 == unspecified && N3 == unspecified && + N2 == unspecified) + ? 2 + : ((N6 == unspecified && N5 == unspecified && + N4 == unspecified && N3 == unspecified) + ? 3 + : ((N6 == unspecified && N5 == unspecified && + N4 == unspecified) + ? 4 + : ((N6 == unspecified && + N5 == unspecified) + ? 5 + : ((N6 == unspecified) + ? 6 + : 7))))))); } // Compute the rank of the view from the nonzero layout arguments. template - KOKKOS_INLINE_FUNCTION - static size_t computeRank( const Layout& layout ) - { - return computeRank( layout.dimension[0] - , layout.dimension[1] - , layout.dimension[2] - , layout.dimension[3] - , layout.dimension[4] - , layout.dimension[5] - , layout.dimension[6] - , layout.dimension[7] ); + KOKKOS_INLINE_FUNCTION static size_t computeRank(const Layout& layout) { + return computeRank(layout.dimension[0], layout.dimension[1], + layout.dimension[2], layout.dimension[3], + layout.dimension[4], layout.dimension[5], + layout.dimension[6], layout.dimension[7]); } // Extra overload to match that for specialize types v2 - template - KOKKOS_INLINE_FUNCTION - static size_t computeRank( const Kokkos::Impl::ViewCtorProp& /* prop */, const Layout& layout ) - { + template + KOKKOS_INLINE_FUNCTION static size_t computeRank( + const Kokkos::Impl::ViewCtorProp& /* prop */, + const Layout& layout) { return computeRank(layout); } // Create the layout for the rank-7 view. // Non-strided Layout template - KOKKOS_INLINE_FUNCTION - static typename std::enable_if< (std::is_same::value || std::is_same::value) , Layout >::type createLayout( const Layout& layout ) - { - return Layout( layout.dimension[0] != unspecified ? layout.dimension[0] : 1 - , layout.dimension[1] != unspecified ? layout.dimension[1] : 1 - , layout.dimension[2] != unspecified ? layout.dimension[2] : 1 - , layout.dimension[3] != unspecified ? layout.dimension[3] : 1 - , layout.dimension[4] != unspecified ? layout.dimension[4] : 1 - , layout.dimension[5] != unspecified ? layout.dimension[5] : 1 - , layout.dimension[6] != unspecified ? layout.dimension[6] : 1 - , layout.dimension[7] != unspecified ? layout.dimension[7] : 1 - ); + KOKKOS_INLINE_FUNCTION static typename std::enable_if< + (std::is_same::value || + std::is_same::value), + Layout>::type + createLayout(const Layout& layout) { + return Layout(layout.dimension[0] != unspecified ? layout.dimension[0] : 1, + layout.dimension[1] != unspecified ? layout.dimension[1] : 1, + layout.dimension[2] != unspecified ? layout.dimension[2] : 1, + layout.dimension[3] != unspecified ? layout.dimension[3] : 1, + layout.dimension[4] != unspecified ? layout.dimension[4] : 1, + layout.dimension[5] != unspecified ? layout.dimension[5] : 1, + layout.dimension[6] != unspecified ? layout.dimension[6] : 1, + layout.dimension[7] != unspecified ? layout.dimension[7] : 1); } // LayoutStride template - KOKKOS_INLINE_FUNCTION - static typename std::enable_if< (std::is_same::value) , Layout>::type createLayout( const Layout& layout ) - { - return Layout( layout.dimension[0] != unspecified ? layout.dimension[0] : 1 - , layout.stride[0] - , layout.dimension[1] != unspecified ? layout.dimension[1] : 1 - , layout.stride[1] - , layout.dimension[2] != unspecified ? layout.dimension[2] : 1 - , layout.stride[2] - , layout.dimension[3] != unspecified ? layout.dimension[3] : 1 - , layout.stride[3] - , layout.dimension[4] != unspecified ? layout.dimension[4] : 1 - , layout.stride[4] - , layout.dimension[5] != unspecified ? layout.dimension[5] : 1 - , layout.stride[5] - , layout.dimension[6] != unspecified ? layout.dimension[6] : 1 - , layout.stride[6] - , layout.dimension[7] != unspecified ? layout.dimension[7] : 1 - , layout.stride[7] - ); + KOKKOS_INLINE_FUNCTION static typename std::enable_if< + (std::is_same::value), Layout>::type + createLayout(const Layout& layout) { + return Layout(layout.dimension[0] != unspecified ? layout.dimension[0] : 1, + layout.stride[0], + layout.dimension[1] != unspecified ? layout.dimension[1] : 1, + layout.stride[1], + layout.dimension[2] != unspecified ? layout.dimension[2] : 1, + layout.stride[2], + layout.dimension[3] != unspecified ? layout.dimension[3] : 1, + layout.stride[3], + layout.dimension[4] != unspecified ? layout.dimension[4] : 1, + layout.stride[4], + layout.dimension[5] != unspecified ? layout.dimension[5] : 1, + layout.stride[5], + layout.dimension[6] != unspecified ? layout.dimension[6] : 1, + layout.stride[6], + layout.dimension[7] != unspecified ? layout.dimension[7] : 1, + layout.stride[7]); } // Extra overload to match that for specialize types - template - KOKKOS_INLINE_FUNCTION - static typename std::enable_if< (std::is_same::value || std::is_same::value || std::is_same::value) , typename Traits::array_layout >::type createLayout( const Kokkos::Impl::ViewCtorProp& /* prop */, const typename Traits::array_layout& layout ) - { - return createLayout( layout ); + template + KOKKOS_INLINE_FUNCTION static typename std::enable_if< + (std::is_same::value || + std::is_same::value || + std::is_same::value), + typename Traits::array_layout>::type + createLayout(const Kokkos::Impl::ViewCtorProp& /* prop */, + const typename Traits::array_layout& layout) { + return createLayout(layout); } // Create a view from the given dimension arguments. // This is only necessary because the shmem constructor doesn't take a layout. - // NDE shmem View's are not compatible with the added view_alloc value_type / fad_dim deduction functionality + // NDE shmem View's are not compatible with the added view_alloc value_type + // / fad_dim deduction functionality template - static ViewType createView( const ViewArg& arg - , const size_t N0 - , const size_t N1 - , const size_t N2 - , const size_t N3 - , const size_t N4 - , const size_t N5 - , const size_t N6 - , const size_t N7 ) - { - return ViewType( arg - , N0 != unspecified ? N0 : 1 - , N1 != unspecified ? N1 : 1 - , N2 != unspecified ? N2 : 1 - , N3 != unspecified ? N3 : 1 - , N4 != unspecified ? N4 : 1 - , N5 != unspecified ? N5 : 1 - , N6 != unspecified ? N6 : 1 - , N7 != unspecified ? N7 : 1 ); + static ViewType createView(const ViewArg& arg, const size_t N0, + const size_t N1, const size_t N2, const size_t N3, + const size_t N4, const size_t N5, const size_t N6, + const size_t N7) { + return ViewType(arg, N0 != unspecified ? N0 : 1, N1 != unspecified ? N1 : 1, + N2 != unspecified ? N2 : 1, N3 != unspecified ? N3 : 1, + N4 != unspecified ? N4 : 1, N5 != unspecified ? N5 : 1, + N6 != unspecified ? N6 : 1, N7 != unspecified ? N7 : 1); } }; - // Non-strided Layout - template - KOKKOS_INLINE_FUNCTION - static typename std::enable_if< (std::is_same::value || std::is_same::value) && std::is_integral::value , Layout >::type - reconstructLayout( const Layout& layout , iType dynrank ) - { - return Layout( dynrank > 0 ? layout.dimension[0] :KOKKOS_INVALID_INDEX - , dynrank > 1 ? layout.dimension[1] :KOKKOS_INVALID_INDEX - , dynrank > 2 ? layout.dimension[2] :KOKKOS_INVALID_INDEX - , dynrank > 3 ? layout.dimension[3] :KOKKOS_INVALID_INDEX - , dynrank > 4 ? layout.dimension[4] :KOKKOS_INVALID_INDEX - , dynrank > 5 ? layout.dimension[5] :KOKKOS_INVALID_INDEX - , dynrank > 6 ? layout.dimension[6] :KOKKOS_INVALID_INDEX - , dynrank > 7 ? layout.dimension[7] :KOKKOS_INVALID_INDEX - ); - } - - // LayoutStride - template - KOKKOS_INLINE_FUNCTION - static typename std::enable_if< (std::is_same::value) && std::is_integral::value , Layout >::type - reconstructLayout( const Layout& layout , iType dynrank ) - { - return Layout( dynrank > 0 ? layout.dimension[0] :KOKKOS_INVALID_INDEX - , dynrank > 0 ? layout.stride[0] : (0) - , dynrank > 1 ? layout.dimension[1] :KOKKOS_INVALID_INDEX - , dynrank > 1 ? layout.stride[1] : (0) - , dynrank > 2 ? layout.dimension[2] :KOKKOS_INVALID_INDEX - , dynrank > 2 ? layout.stride[2] : (0) - , dynrank > 3 ? layout.dimension[3] :KOKKOS_INVALID_INDEX - , dynrank > 3 ? layout.stride[3] : (0) - , dynrank > 4 ? layout.dimension[4] :KOKKOS_INVALID_INDEX - , dynrank > 4 ? layout.stride[4] : (0) - , dynrank > 5 ? layout.dimension[5] :KOKKOS_INVALID_INDEX - , dynrank > 5 ? layout.stride[5] : (0) - , dynrank > 6 ? layout.dimension[6] :KOKKOS_INVALID_INDEX - , dynrank > 6 ? layout.stride[6] : (0) - , dynrank > 7 ? layout.dimension[7] :KOKKOS_INVALID_INDEX - , dynrank > 7 ? layout.stride[7] : (0) - ); - } +// Non-strided Layout +template +KOKKOS_INLINE_FUNCTION static + typename std::enable_if<(std::is_same::value || + std::is_same::value) && + std::is_integral::value, + Layout>::type + reconstructLayout(const Layout& layout, iType dynrank) { + return Layout(dynrank > 0 ? layout.dimension[0] : KOKKOS_INVALID_INDEX, + dynrank > 1 ? layout.dimension[1] : KOKKOS_INVALID_INDEX, + dynrank > 2 ? layout.dimension[2] : KOKKOS_INVALID_INDEX, + dynrank > 3 ? layout.dimension[3] : KOKKOS_INVALID_INDEX, + dynrank > 4 ? layout.dimension[4] : KOKKOS_INVALID_INDEX, + dynrank > 5 ? layout.dimension[5] : KOKKOS_INVALID_INDEX, + dynrank > 6 ? layout.dimension[6] : KOKKOS_INVALID_INDEX, + dynrank > 7 ? layout.dimension[7] : KOKKOS_INVALID_INDEX); +} +// LayoutStride +template +KOKKOS_INLINE_FUNCTION static typename std::enable_if< + (std::is_same::value) && + std::is_integral::value, + Layout>::type +reconstructLayout(const Layout& layout, iType dynrank) { + return Layout(dynrank > 0 ? layout.dimension[0] : KOKKOS_INVALID_INDEX, + dynrank > 0 ? layout.stride[0] : (0), + dynrank > 1 ? layout.dimension[1] : KOKKOS_INVALID_INDEX, + dynrank > 1 ? layout.stride[1] : (0), + dynrank > 2 ? layout.dimension[2] : KOKKOS_INVALID_INDEX, + dynrank > 2 ? layout.stride[2] : (0), + dynrank > 3 ? layout.dimension[3] : KOKKOS_INVALID_INDEX, + dynrank > 3 ? layout.stride[3] : (0), + dynrank > 4 ? layout.dimension[4] : KOKKOS_INVALID_INDEX, + dynrank > 4 ? layout.stride[4] : (0), + dynrank > 5 ? layout.dimension[5] : KOKKOS_INVALID_INDEX, + dynrank > 5 ? layout.stride[5] : (0), + dynrank > 6 ? layout.dimension[6] : KOKKOS_INVALID_INDEX, + dynrank > 6 ? layout.stride[6] : (0), + dynrank > 7 ? layout.dimension[7] : KOKKOS_INVALID_INDEX, + dynrank > 7 ? layout.stride[7] : (0)); +} /** \brief Debug bounds-checking routines */ // Enhanced debug checking - most infrastructure matches that of functions in // Kokkos_ViewMapping; additional checks for extra arguments beyond rank are 0 -template< unsigned , typename iType0 , class MapType > -KOKKOS_INLINE_FUNCTION -bool dyn_rank_view_verify_operator_bounds( const iType0 & , const MapType & ) -{ return true ; } - -template< unsigned R , typename iType0 , class MapType , typename iType1 , class ... Args > -KOKKOS_INLINE_FUNCTION -bool dyn_rank_view_verify_operator_bounds - ( const iType0 & rank - , const MapType & map - , const iType1 & i - , Args ... args - ) -{ - if ( static_cast(R) < rank ) { - return ( size_t(i) < map.extent(R) ) - && dyn_rank_view_verify_operator_bounds( rank , map , args ... ); - } - else if ( i != 0 ) { - printf("DynRankView Debug Bounds Checking Error: at rank %u\n Extra arguments beyond the rank must be zero \n",R); - return ( false ) - && dyn_rank_view_verify_operator_bounds( rank , map , args ... ); - } - else { - return ( true ) - && dyn_rank_view_verify_operator_bounds( rank , map , args ... ); +template +KOKKOS_INLINE_FUNCTION bool dyn_rank_view_verify_operator_bounds( + const iType0&, const MapType&) { + return true; +} + +template +KOKKOS_INLINE_FUNCTION bool dyn_rank_view_verify_operator_bounds( + const iType0& rank, const MapType& map, const iType1& i, Args... args) { + if (static_cast(R) < rank) { + return (size_t(i) < map.extent(R)) && + dyn_rank_view_verify_operator_bounds(rank, map, args...); + } else if (i != 0) { + printf( + "DynRankView Debug Bounds Checking Error: at rank %u\n Extra " + "arguments beyond the rank must be zero \n", + R); + return (false) && + dyn_rank_view_verify_operator_bounds(rank, map, args...); + } else { + return (true) && + dyn_rank_view_verify_operator_bounds(rank, map, args...); } } -template< unsigned , class MapType > -inline -void dyn_rank_view_error_operator_bounds( char * , int , const MapType & ) -{} - -template< unsigned R , class MapType , class iType , class ... Args > -inline -void dyn_rank_view_error_operator_bounds - ( char * buf - , int len - , const MapType & map - , const iType & i - , Args ... args - ) -{ - const int n = - snprintf(buf,len," %ld < %ld %c" - , static_cast(i) - , static_cast( map.extent(R) ) - , ( sizeof...(Args) ? ',' : ')' ) - ); - dyn_rank_view_error_operator_bounds(buf+n,len-n,map,args...); +template +inline void dyn_rank_view_error_operator_bounds(char*, int, const MapType&) {} + +template +inline void dyn_rank_view_error_operator_bounds(char* buf, int len, + const MapType& map, + const iType& i, Args... args) { + const int n = snprintf( + buf, len, " %ld < %ld %c", static_cast(i), + static_cast(map.extent(R)), (sizeof...(Args) ? ',' : ')')); + dyn_rank_view_error_operator_bounds(buf + n, len - n, map, args...); } // op_rank = rank of the operator version that was called -template< typename MemorySpace - , typename iType0 , typename iType1 , class MapType , class ... Args > -KOKKOS_INLINE_FUNCTION -void dyn_rank_view_verify_operator_bounds - ( const iType0 & op_rank , const iType1 & rank - , const Kokkos::Impl::SharedAllocationTracker & tracker - , const MapType & map , Args ... args ) -{ - if ( static_cast(rank) > op_rank ) { - Kokkos::abort( "DynRankView Bounds Checking Error: Need at least rank arguments to the operator()" ); - } - - if ( ! dyn_rank_view_verify_operator_bounds<0>( rank , map , args ... ) ) { -#if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) +template +KOKKOS_INLINE_FUNCTION void dyn_rank_view_verify_operator_bounds( + const iType0& op_rank, const iType1& rank, + const Kokkos::Impl::SharedAllocationTracker& tracker, const MapType& map, + Args... args) { + if (static_cast(rank) > op_rank) { + Kokkos::abort( + "DynRankView Bounds Checking Error: Need at least rank arguments to " + "the operator()"); + } + + if (!dyn_rank_view_verify_operator_bounds<0>(rank, map, args...)) { +#if defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST) enum { LEN = 1024 }; - char buffer[ LEN ]; + char buffer[LEN]; const std::string label = tracker.template get_label(); - int n = snprintf(buffer,LEN,"DynRankView bounds error of view %s (", label.c_str()); - dyn_rank_view_error_operator_bounds<0>( buffer + n , LEN - n , map , args ... ); + int n = snprintf(buffer, LEN, "DynRankView bounds error of view %s (", + label.c_str()); + dyn_rank_view_error_operator_bounds<0>(buffer + n, LEN - n, map, args...); Kokkos::Impl::throw_runtime_exception(std::string(buffer)); #else Kokkos::abort("DynRankView bounds error"); @@ -312,86 +298,84 @@ void dyn_rank_view_verify_operator_bounds } } - /** \brief Assign compatible default mappings */ struct ViewToDynRankViewTag {}; -} // namespace Impl +} // namespace Impl namespace Impl { -template< class DstTraits , class SrcTraits > -class ViewMapping< DstTraits , SrcTraits , - typename std::enable_if<( - std::is_same< typename DstTraits::memory_space , typename SrcTraits::memory_space >::value - && - std::is_same< typename DstTraits::specialize , void >::value - && - std::is_same< typename SrcTraits::specialize , void >::value - && - ( - std::is_same< typename DstTraits::array_layout , typename SrcTraits::array_layout >::value - || - ( - ( - std::is_same< typename DstTraits::array_layout , Kokkos::LayoutLeft >::value || - std::is_same< typename DstTraits::array_layout , Kokkos::LayoutRight >::value || - std::is_same< typename DstTraits::array_layout , Kokkos::LayoutStride >::value - ) - && - ( - std::is_same< typename SrcTraits::array_layout , Kokkos::LayoutLeft >::value || - std::is_same< typename SrcTraits::array_layout , Kokkos::LayoutRight >::value || - std::is_same< typename SrcTraits::array_layout , Kokkos::LayoutStride >::value - ) - ) - ) - ) , Kokkos::Impl::ViewToDynRankViewTag >::type > -{ -private: - - enum { is_assignable_value_type = - std::is_same< typename DstTraits::value_type - , typename SrcTraits::value_type >::value || - std::is_same< typename DstTraits::value_type - , typename SrcTraits::const_value_type >::value }; - - enum { is_assignable_layout = - std::is_same< typename DstTraits::array_layout - , typename SrcTraits::array_layout >::value || - std::is_same< typename DstTraits::array_layout - , Kokkos::LayoutStride >::value - }; +template +class ViewMapping< + DstTraits, SrcTraits, + typename std::enable_if< + (std::is_same::value && + std::is_same::value && + std::is_same::value && + (std::is_same::value || + ((std::is_same::value || + std::is_same::value || + std::is_same::value) && + (std::is_same::value || + std::is_same::value || + std::is_same::value)))), + Kokkos::Impl::ViewToDynRankViewTag>::type> { + private: + enum { + is_assignable_value_type = + std::is_same::value || + std::is_same::value + }; -public: + enum { + is_assignable_layout = + std::is_same::value || + std::is_same::value + }; - enum { is_assignable = is_assignable_value_type && - is_assignable_layout }; + public: + enum { is_assignable = is_assignable_value_type && is_assignable_layout }; - typedef ViewMapping< DstTraits , typename DstTraits::specialize > DstType ; - typedef ViewMapping< SrcTraits , typename SrcTraits::specialize > SrcType ; + typedef ViewMapping DstType; + typedef ViewMapping SrcType; - template < typename DT , typename ... DP , typename ST , typename ... SP > - KOKKOS_INLINE_FUNCTION - static void assign( Kokkos::DynRankView< DT , DP...> & dst , const Kokkos::View< ST , SP... > & src ) - { - static_assert( is_assignable_value_type - , "View assignment must have same value type or const = non-const" ); + template + KOKKOS_INLINE_FUNCTION static void assign( + Kokkos::DynRankView& dst, const Kokkos::View& src) { + static_assert( + is_assignable_value_type, + "View assignment must have same value type or const = non-const"); - static_assert( is_assignable_layout - , "View assignment must have compatible layout or have rank <= 1" ); + static_assert( + is_assignable_layout, + "View assignment must have compatible layout or have rank <= 1"); // Removed dimension checks... - typedef typename DstType::offset_type dst_offset_type ; - dst.m_map.m_impl_offset = dst_offset_type(std::integral_constant() , src.layout() ); //Check this for integer input1 for padding, etc - dst.m_map.m_impl_handle = Kokkos::Impl::ViewDataHandle< DstTraits >::assign( src.m_map.m_impl_handle , src.m_track ); - dst.m_track.assign( src.m_track , DstTraits::is_managed ); - dst.m_rank = src.Rank ; - } + typedef typename DstType::offset_type dst_offset_type; + dst.m_map.m_impl_offset = dst_offset_type( + std::integral_constant(), + src.layout()); // Check this for integer input1 for padding, etc + dst.m_map.m_impl_handle = Kokkos::Impl::ViewDataHandle::assign( + src.m_map.m_impl_handle, src.m_track); + dst.m_track.assign(src.m_track, DstTraits::is_managed); + dst.m_rank = src.Rank; + } }; -} //end Impl +} // namespace Impl /* \class DynRankView * \brief Container that creates a Kokkos view with rank determined at runtime. @@ -400,7 +384,8 @@ public: * Changes from View * 1. The rank of the DynRankView is returned by the method rank() * 2. Max rank of a DynRankView is 7 - * 3. subview called with 'subview(...)' or 'subdynrankview(...)' (backward compatibility) + * 3. subview called with 'subview(...)' or 'subdynrankview(...)' (backward + * compatibility) * 4. Every subview is returned with LayoutStride * 5. Copy and Copy-Assign View to DynRankView * 6. deep_copy between Views and DynRankViews @@ -408,93 +393,99 @@ public: * */ -template< class > struct is_dyn_rank_view : public std::false_type {}; - -template< class D, class ... P > -struct is_dyn_rank_view< Kokkos::DynRankView > : public std::true_type {}; +template +struct is_dyn_rank_view : public std::false_type {}; +template +struct is_dyn_rank_view > : public std::true_type { +}; -template< typename DataType , class ... Properties > -class DynRankView : public ViewTraits< DataType , Properties ... > -{ - static_assert( !std::is_array::value && !std::is_pointer::value , "Cannot template DynRankView with array or pointer datatype - must be pod" ); - -private: - template < class , class ... > friend class DynRankView ; - template < class , class ... > friend class Kokkos::Impl::ViewMapping ; +template +class DynRankView : public ViewTraits { + static_assert(!std::is_array::value && + !std::is_pointer::value, + "Cannot template DynRankView with array or pointer datatype - " + "must be pod"); -public: - typedef ViewTraits< DataType , Properties ... > drvtraits ; + private: + template + friend class DynRankView; + template + friend class Kokkos::Impl::ViewMapping; - typedef View< DataType******* , Properties...> view_type ; + public: + typedef ViewTraits drvtraits; - typedef ViewTraits< DataType******* , Properties ... > traits ; + typedef View view_type; + typedef ViewTraits traits; -private: - typedef Kokkos::Impl::ViewMapping< traits , typename traits::specialize > map_type ; - typedef Kokkos::Impl::SharedAllocationTracker track_type ; + private: + typedef Kokkos::Impl::ViewMapping + map_type; + typedef Kokkos::Impl::SharedAllocationTracker track_type; - track_type m_track ; - map_type m_map ; + track_type m_track; + map_type m_map; unsigned m_rank; -public: + public: KOKKOS_INLINE_FUNCTION - view_type & DownCast() const { return ( view_type & ) (*this); } + view_type& DownCast() const { return (view_type&)(*this); } KOKKOS_INLINE_FUNCTION - const view_type & ConstDownCast() const { return (const view_type & ) (*this); } + const view_type& ConstDownCast() const { return (const view_type&)(*this); } - //Types below - at least the HostMirror requires the value_type, NOT the rank 7 data_type of the traits + // Types below - at least the HostMirror requires the value_type, NOT the rank + // 7 data_type of the traits /** \brief Compatible view of array of scalar types */ - typedef DynRankView< typename drvtraits::scalar_array_type , - typename drvtraits::array_layout , - typename drvtraits::device_type , - typename drvtraits::memory_traits > - array_type ; + typedef DynRankView< + typename drvtraits::scalar_array_type, typename drvtraits::array_layout, + typename drvtraits::device_type, typename drvtraits::memory_traits> + array_type; /** \brief Compatible view of const data type */ - typedef DynRankView< typename drvtraits::const_data_type , - typename drvtraits::array_layout , - typename drvtraits::device_type , - typename drvtraits::memory_traits > - const_type ; + typedef DynRankView< + typename drvtraits::const_data_type, typename drvtraits::array_layout, + typename drvtraits::device_type, typename drvtraits::memory_traits> + const_type; /** \brief Compatible view of non-const data type */ - typedef DynRankView< typename drvtraits::non_const_data_type , - typename drvtraits::array_layout , - typename drvtraits::device_type , - typename drvtraits::memory_traits > - non_const_type ; + typedef DynRankView< + typename drvtraits::non_const_data_type, typename drvtraits::array_layout, + typename drvtraits::device_type, typename drvtraits::memory_traits> + non_const_type; /** \brief Compatible HostMirror view */ - typedef DynRankView< typename drvtraits::non_const_data_type , - typename drvtraits::array_layout , - typename drvtraits::host_mirror_space > - HostMirror ; - + typedef DynRankView + HostMirror; //---------------------------------------- // Domain rank and extents -// enum { Rank = map_type::Rank }; //Will be dyn rank of 7 always, keep the enum? + // enum { Rank = map_type::Rank }; //Will be dyn rank of 7 always, keep the + // enum? - template< typename iType > + template KOKKOS_INLINE_FUNCTION constexpr - typename std::enable_if< std::is_integral::value , size_t >::type - extent( const iType & r ) const - { return m_map.extent(r); } + typename std::enable_if::value, size_t>::type + extent(const iType& r) const { + return m_map.extent(r); + } - template< typename iType > + template KOKKOS_INLINE_FUNCTION constexpr - typename std::enable_if< std::is_integral::value , int >::type - extent_int( const iType & r ) const - { return static_cast(m_map.extent(r)); } + typename std::enable_if::value, int>::type + extent_int(const iType& r) const { + return static_cast(m_map.extent(r)); + } - KOKKOS_INLINE_FUNCTION constexpr - typename traits::array_layout layout() const - { return m_map.layout(); } + KOKKOS_INLINE_FUNCTION constexpr typename traits::array_layout layout() + const { + return m_map.layout(); + } //---------------------------------------- /* Deprecate all 'dimension' functions in favor of @@ -502,421 +493,572 @@ public: */ #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - template< typename iType > + template KOKKOS_INLINE_FUNCTION constexpr - typename std::enable_if< std::is_integral::value , size_t >::type - dimension( const iType & r ) const { return extent( r ); } - - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_0() const { return m_map.dimension_0(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_1() const { return m_map.dimension_1(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_2() const { return m_map.dimension_2(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_3() const { return m_map.dimension_3(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_4() const { return m_map.dimension_4(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_5() const { return m_map.dimension_5(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_6() const { return m_map.dimension_6(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_7() const { return m_map.dimension_7(); } + typename std::enable_if::value, size_t>::type + dimension(const iType& r) const { + return extent(r); + } + + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_0() const { + return m_map.dimension_0(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_1() const { + return m_map.dimension_1(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_2() const { + return m_map.dimension_2(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_3() const { + return m_map.dimension_3(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_4() const { + return m_map.dimension_4(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_5() const { + return m_map.dimension_5(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_6() const { + return m_map.dimension_6(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_7() const { + return m_map.dimension_7(); + } #endif //---------------------------------------- - KOKKOS_INLINE_FUNCTION constexpr size_t size() const { return m_map.extent(0) * - m_map.extent(1) * - m_map.extent(2) * - m_map.extent(3) * - m_map.extent(4) * - m_map.extent(5) * - m_map.extent(6) * - m_map.extent(7); } - - KOKKOS_INLINE_FUNCTION constexpr size_t stride_0() const { return m_map.stride_0(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_1() const { return m_map.stride_1(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_2() const { return m_map.stride_2(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_3() const { return m_map.stride_3(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_4() const { return m_map.stride_4(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_5() const { return m_map.stride_5(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_6() const { return m_map.stride_6(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_7() const { return m_map.stride_7(); } - - template< typename iType > - KOKKOS_INLINE_FUNCTION void stride( iType * const s ) const { m_map.stride(s); } + KOKKOS_INLINE_FUNCTION constexpr size_t size() const { + return m_map.extent(0) * m_map.extent(1) * m_map.extent(2) * + m_map.extent(3) * m_map.extent(4) * m_map.extent(5) * + m_map.extent(6) * m_map.extent(7); + } + + KOKKOS_INLINE_FUNCTION constexpr size_t stride_0() const { + return m_map.stride_0(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_1() const { + return m_map.stride_1(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_2() const { + return m_map.stride_2(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_3() const { + return m_map.stride_3(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_4() const { + return m_map.stride_4(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_5() const { + return m_map.stride_5(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_6() const { + return m_map.stride_6(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_7() const { + return m_map.stride_7(); + } + + template + KOKKOS_INLINE_FUNCTION void stride(iType* const s) const { + m_map.stride(s); + } //---------------------------------------- // Range span is the span which contains all members. - typedef typename map_type::reference_type reference_type ; - typedef typename map_type::pointer_type pointer_type ; + typedef typename map_type::reference_type reference_type; + typedef typename map_type::pointer_type pointer_type; - enum { reference_type_is_lvalue_reference = std::is_lvalue_reference< reference_type >::value }; + enum { + reference_type_is_lvalue_reference = + std::is_lvalue_reference::value + }; KOKKOS_INLINE_FUNCTION constexpr size_t span() const { return m_map.span(); } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE // Deprecated, use 'span()' instead - KOKKOS_INLINE_FUNCTION constexpr size_t capacity() const { return m_map.span(); } + KOKKOS_INLINE_FUNCTION constexpr size_t capacity() const { + return m_map.span(); + } #endif - KOKKOS_INLINE_FUNCTION constexpr bool span_is_contiguous() const { return m_map.span_is_contiguous(); } - KOKKOS_INLINE_FUNCTION constexpr pointer_type data() const { return m_map.data(); } + KOKKOS_INLINE_FUNCTION constexpr bool span_is_contiguous() const { + return m_map.span_is_contiguous(); + } + KOKKOS_INLINE_FUNCTION constexpr pointer_type data() const { + return m_map.data(); + } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE // Deprecated, use 'span_is_contigous()' instead - KOKKOS_INLINE_FUNCTION constexpr bool is_contiguous() const { return m_map.span_is_contiguous(); } + KOKKOS_INLINE_FUNCTION constexpr bool is_contiguous() const { + return m_map.span_is_contiguous(); + } // Deprecated, use 'data()' instead - KOKKOS_INLINE_FUNCTION constexpr pointer_type ptr_on_device() const { return m_map.data(); } + KOKKOS_INLINE_FUNCTION constexpr pointer_type ptr_on_device() const { + return m_map.data(); + } #endif //---------------------------------------- // Allow specializations to query their specialized map #ifdef KOKKOS_ENABLE_DEPRECATED_CODE KOKKOS_INLINE_FUNCTION - const Kokkos::Impl::ViewMapping< traits , typename traits::specialize > & - implementation_map() const { return m_map ; } + const Kokkos::Impl::ViewMapping& + implementation_map() const { + return m_map; + } #endif KOKKOS_INLINE_FUNCTION - const Kokkos::Impl::ViewMapping< traits , typename traits::specialize > & - impl_map() const { return m_map ; } + const Kokkos::Impl::ViewMapping& + impl_map() const { + return m_map; + } //---------------------------------------- -private: - + private: enum { - is_layout_left = std::is_same< typename traits::array_layout - , Kokkos::LayoutLeft >::value , + is_layout_left = + std::is_same::value, - is_layout_right = std::is_same< typename traits::array_layout - , Kokkos::LayoutRight >::value , + is_layout_right = + std::is_same::value, - is_layout_stride = std::is_same< typename traits::array_layout - , Kokkos::LayoutStride >::value , + is_layout_stride = std::is_same::value, - is_default_map = - std::is_same< typename traits::specialize , void >::value && - ( is_layout_left || is_layout_right || is_layout_stride ) + is_default_map = std::is_same::value && + (is_layout_left || is_layout_right || is_layout_stride) }; - template< class Space , bool = Kokkos::Impl::MemorySpaceAccess< Space , typename traits::memory_space >::accessible > struct verify_space - { KOKKOS_FORCEINLINE_FUNCTION static void check() {} }; + template ::accessible> + struct verify_space { + KOKKOS_FORCEINLINE_FUNCTION static void check() {} + }; - template< class Space > struct verify_space - { KOKKOS_FORCEINLINE_FUNCTION static void check() - { Kokkos::abort("Kokkos::DynRankView ERROR: attempt to access inaccessible memory space"); }; + template + struct verify_space { + KOKKOS_FORCEINLINE_FUNCTION static void check() { + Kokkos::abort( + "Kokkos::DynRankView ERROR: attempt to access inaccessible memory " + "space"); }; + }; // Bounds checking macros -#if defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK ) +#if defined(KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK) // rank of the calling operator - included as first argument in ARG -#define KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( ARG ) \ - DynRankView::template verify_space< Kokkos::Impl::ActiveExecutionMemorySpace >::check(); \ - Kokkos::Impl::dyn_rank_view_verify_operator_bounds< typename traits::memory_space > ARG ; +#define KOKKOS_IMPL_VIEW_OPERATOR_VERIFY(ARG) \ + DynRankView::template verify_space< \ + Kokkos::Impl::ActiveExecutionMemorySpace>::check(); \ + Kokkos::Impl::dyn_rank_view_verify_operator_bounds< \ + typename traits::memory_space> \ + ARG; #else -#define KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( ARG ) \ - DynRankView::template verify_space< Kokkos::Impl::ActiveExecutionMemorySpace >::check(); +#define KOKKOS_IMPL_VIEW_OPERATOR_VERIFY(ARG) \ + DynRankView::template verify_space< \ + Kokkos::Impl::ActiveExecutionMemorySpace>::check(); #endif -public: - + public: KOKKOS_INLINE_FUNCTION constexpr unsigned rank() const { return m_rank; } - - //operators () + // operators () // Rank 0 KOKKOS_INLINE_FUNCTION - reference_type operator()() const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (0 , this->rank(), m_track, m_map) ) - return impl_map().reference(); - //return m_map.reference(0,0,0,0,0,0,0); - } + reference_type operator()() const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((0, this->rank(), m_track, m_map)) + return impl_map().reference(); + // return m_map.reference(0,0,0,0,0,0,0); + } // Rank 1 - // This assumes a contiguous underlying memory (i.e. no padding, no striding...) - template< typename iType > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< std::is_same::value && std::is_integral::value, reference_type>::type - operator[](const iType & i0) const - { - //Phalanx is violating this, since they use the operator to access ALL elements in the allocation - //KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (1 , this->rank(), m_track, m_map) ) - return data()[i0]; - } + // This assumes a contiguous underlying memory (i.e. no padding, no + // striding...) + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + std::is_same::value && + std::is_integral::value, + reference_type>::type + operator[](const iType& i0) const { + // Phalanx is violating this, since they use the operator to access ALL + // elements in the allocation KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (1 , + // this->rank(), m_track, m_map) ) + return data()[i0]; + } - // This assumes a contiguous underlying memory (i.e. no padding, no striding... - // AND a Trilinos/Sacado scalar type ) - template< typename iType > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !std::is_same::value && std::is_integral::value, reference_type>::type - operator[](const iType & i0) const - { -// auto map = impl_map(); - const size_t dim_scalar = m_map.dimension_scalar(); - const size_t bytes = this->span() / dim_scalar; - - typedef Kokkos::View > tmp_view_type; - tmp_view_type rankone_view(this->data(), bytes, dim_scalar); - return rankone_view(i0); - } + // This assumes a contiguous underlying memory (i.e. no padding, no + // striding... AND a Trilinos/Sacado scalar type ) + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !std::is_same::value && + std::is_integral::value, + reference_type>::type + operator[](const iType& i0) const { + // auto map = impl_map(); + const size_t dim_scalar = m_map.dimension_scalar(); + const size_t bytes = this->span() / dim_scalar; + + typedef Kokkos::View< + DataType*, typename traits::array_layout, typename traits::device_type, + Kokkos::MemoryTraits > + tmp_view_type; + tmp_view_type rankone_view(this->data(), bytes, dim_scalar); + return rankone_view(i0); + } // Rank 1 parenthesis - template< typename iType > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value), reference_type>::type - operator()(const iType & i0 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (1 , this->rank(), m_track, m_map, i0) ) - return m_map.reference(i0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value), + reference_type>::type + operator()(const iType& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((1, this->rank(), m_track, m_map, i0)) + return m_map.reference(i0); + } - template< typename iType > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - operator()(const iType & i0 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (1 , this->rank(), m_track, m_map, i0) ) - return m_map.reference(i0,0,0,0,0,0,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + operator()(const iType& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((1, this->rank(), m_track, m_map, i0)) + return m_map.reference(i0, 0, 0, 0, 0, 0, 0); + } // Rank 2 - template< typename iType0 , typename iType1 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value && std::is_integral::value), reference_type>::type - operator()(const iType0 & i0 , const iType1 & i1 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (2 , this->rank(), m_track, m_map, i0, i1) ) - return m_map.reference(i0,i1); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value && std::is_integral::value), + reference_type>::type + operator()(const iType0& i0, const iType1& i1) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((2, this->rank(), m_track, m_map, i0, i1)) + return m_map.reference(i0, i1); + } - template< typename iType0 , typename iType1 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - operator()(const iType0 & i0 , const iType1 & i1 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (2 , this->rank(), m_track, m_map, i0, i1) ) - return m_map.reference(i0,i1,0,0,0,0,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + operator()(const iType0& i0, const iType1& i1) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((2, this->rank(), m_track, m_map, i0, i1)) + return m_map.reference(i0, i1, 0, 0, 0, 0, 0); + } // Rank 3 - template< typename iType0 , typename iType1 , typename iType2 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value && std::is_integral::value && std::is_integral::value), reference_type>::type - operator()(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (3 , this->rank(), m_track, m_map, i0, i1, i2) ) - return m_map.reference(i0,i1,i2); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value), + reference_type>::type + operator()(const iType0& i0, const iType1& i1, const iType2& i2) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (3, this->rank(), m_track, m_map, i0, i1, i2)) + return m_map.reference(i0, i1, i2); + } - template< typename iType0 , typename iType1 , typename iType2 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - operator()(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (3 , this->rank(), m_track, m_map, i0, i1, i2) ) - return m_map.reference(i0,i1,i2,0,0,0,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + operator()(const iType0& i0, const iType1& i1, const iType2& i2) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (3, this->rank(), m_track, m_map, i0, i1, i2)) + return m_map.reference(i0, i1, i2, 0, 0, 0, 0); + } // Rank 4 - template< typename iType0 , typename iType1 , typename iType2 , typename iType3 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value), reference_type>::type - operator()(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (4 , this->rank(), m_track, m_map, i0, i1, i2, i3) ) - return m_map.reference(i0,i1,i2,i3); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value), + reference_type>::type + operator()(const iType0& i0, const iType1& i1, const iType2& i2, + const iType3& i3) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (4, this->rank(), m_track, m_map, i0, i1, i2, i3)) + return m_map.reference(i0, i1, i2, i3); + } - template< typename iType0 , typename iType1 , typename iType2 , typename iType3 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - operator()(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (4 , this->rank(), m_track, m_map, i0, i1, i2, i3) ) - return m_map.reference(i0,i1,i2,i3,0,0,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + operator()(const iType0& i0, const iType1& i1, const iType2& i2, + const iType3& i3) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (4, this->rank(), m_track, m_map, i0, i1, i2, i3)) + return m_map.reference(i0, i1, i2, i3, 0, 0, 0); + } // Rank 5 - template< typename iType0 , typename iType1 , typename iType2 , typename iType3, typename iType4 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value), reference_type>::type - operator()(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 , const iType4 & i4 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (5 , this->rank(), m_track, m_map, i0, i1, i2, i3, i4) ) - return m_map.reference(i0,i1,i2,i3,i4); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value), + reference_type>::type + operator()(const iType0& i0, const iType1& i1, const iType2& i2, + const iType3& i3, const iType4& i4) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (5, this->rank(), m_track, m_map, i0, i1, i2, i3, i4)) + return m_map.reference(i0, i1, i2, i3, i4); + } - template< typename iType0 , typename iType1 , typename iType2 , typename iType3, typename iType4 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - operator()(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 , const iType4 & i4 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (5 , this->rank(), m_track, m_map, i0, i1, i2, i3, i4) ) - return m_map.reference(i0,i1,i2,i3,i4,0,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + operator()(const iType0& i0, const iType1& i1, const iType2& i2, + const iType3& i3, const iType4& i4) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (5, this->rank(), m_track, m_map, i0, i1, i2, i3, i4)) + return m_map.reference(i0, i1, i2, i3, i4, 0, 0); + } // Rank 6 - template< typename iType0 , typename iType1 , typename iType2 , typename iType3, typename iType4 , typename iType5 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value), reference_type>::type - operator()(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 , const iType4 & i4 , const iType5 & i5 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (6 , this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5) ) - return m_map.reference(i0,i1,i2,i3,i4,i5); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value), + reference_type>::type + operator()(const iType0& i0, const iType1& i1, const iType2& i2, + const iType3& i3, const iType4& i4, const iType5& i5) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (6, this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5)) + return m_map.reference(i0, i1, i2, i3, i4, i5); + } - template< typename iType0 , typename iType1 , typename iType2 , typename iType3, typename iType4 , typename iType5 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - operator()(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 , const iType4 & i4 , const iType5 & i5 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (6 , this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5) ) - return m_map.reference(i0,i1,i2,i3,i4,i5,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + operator()(const iType0& i0, const iType1& i1, const iType2& i2, + const iType3& i3, const iType4& i4, const iType5& i5) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (6, this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5)) + return m_map.reference(i0, i1, i2, i3, i4, i5, 0); + } // Rank 7 - template< typename iType0 , typename iType1 , typename iType2 , typename iType3, typename iType4 , typename iType5 , typename iType6 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value), reference_type>::type - operator()(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 , const iType4 & i4 , const iType5 & i5 , const iType6 & i6 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (7 , this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5, i6) ) - return m_map.reference(i0,i1,i2,i3,i4,i5,i6); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value), + reference_type>::type + operator()(const iType0& i0, const iType1& i1, const iType2& i2, + const iType3& i3, const iType4& i4, const iType5& i5, + const iType6& i6) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (7, this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5, i6)) + return m_map.reference(i0, i1, i2, i3, i4, i5, i6); + } // Rank 0 KOKKOS_INLINE_FUNCTION - reference_type access() const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (0 , this->rank(), m_track, m_map) ) - return impl_map().reference(); - //return m_map.reference(0,0,0,0,0,0,0); - } + reference_type access() const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((0, this->rank(), m_track, m_map)) + return impl_map().reference(); + // return m_map.reference(0,0,0,0,0,0,0); + } // Rank 1 - // Rank 1 parenthesis - template< typename iType > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value), reference_type>::type - access(const iType & i0 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (1 , this->rank(), m_track, m_map, i0) ) - return m_map.reference(i0); - } + // Rank 1 parenthesis + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value), + reference_type>::type + access(const iType& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((1, this->rank(), m_track, m_map, i0)) + return m_map.reference(i0); + } - template< typename iType > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - access(const iType & i0 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (1 , this->rank(), m_track, m_map, i0) ) - return m_map.reference(i0,0,0,0,0,0,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + access(const iType& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((1, this->rank(), m_track, m_map, i0)) + return m_map.reference(i0, 0, 0, 0, 0, 0, 0); + } // Rank 2 - template< typename iType0 , typename iType1 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value && std::is_integral::value), reference_type>::type - access(const iType0 & i0 , const iType1 & i1 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (2 , this->rank(), m_track, m_map, i0, i1) ) - return m_map.reference(i0,i1); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value && std::is_integral::value), + reference_type>::type + access(const iType0& i0, const iType1& i1) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((2, this->rank(), m_track, m_map, i0, i1)) + return m_map.reference(i0, i1); + } - template< typename iType0 , typename iType1 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - access(const iType0 & i0 , const iType1 & i1 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (2 , this->rank(), m_track, m_map, i0, i1) ) - return m_map.reference(i0,i1,0,0,0,0,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + access(const iType0& i0, const iType1& i1) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((2, this->rank(), m_track, m_map, i0, i1)) + return m_map.reference(i0, i1, 0, 0, 0, 0, 0); + } // Rank 3 - template< typename iType0 , typename iType1 , typename iType2 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value && std::is_integral::value && std::is_integral::value), reference_type>::type - access(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (3 , this->rank(), m_track, m_map, i0, i1, i2) ) - return m_map.reference(i0,i1,i2); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value), + reference_type>::type + access(const iType0& i0, const iType1& i1, const iType2& i2) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (3, this->rank(), m_track, m_map, i0, i1, i2)) + return m_map.reference(i0, i1, i2); + } - template< typename iType0 , typename iType1 , typename iType2 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - access(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (3 , this->rank(), m_track, m_map, i0, i1, i2) ) - return m_map.reference(i0,i1,i2,0,0,0,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + access(const iType0& i0, const iType1& i1, const iType2& i2) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (3, this->rank(), m_track, m_map, i0, i1, i2)) + return m_map.reference(i0, i1, i2, 0, 0, 0, 0); + } // Rank 4 - template< typename iType0 , typename iType1 , typename iType2 , typename iType3 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value), reference_type>::type - access(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (4 , this->rank(), m_track, m_map, i0, i1, i2, i3) ) - return m_map.reference(i0,i1,i2,i3); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value), + reference_type>::type + access(const iType0& i0, const iType1& i1, const iType2& i2, + const iType3& i3) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (4, this->rank(), m_track, m_map, i0, i1, i2, i3)) + return m_map.reference(i0, i1, i2, i3); + } - template< typename iType0 , typename iType1 , typename iType2 , typename iType3 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - access(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (4 , this->rank(), m_track, m_map, i0, i1, i2, i3) ) - return m_map.reference(i0,i1,i2,i3,0,0,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + access(const iType0& i0, const iType1& i1, const iType2& i2, + const iType3& i3) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (4, this->rank(), m_track, m_map, i0, i1, i2, i3)) + return m_map.reference(i0, i1, i2, i3, 0, 0, 0); + } // Rank 5 - template< typename iType0 , typename iType1 , typename iType2 , typename iType3, typename iType4 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value), reference_type>::type - access(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 , const iType4 & i4 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (5 , this->rank(), m_track, m_map, i0, i1, i2, i3, i4) ) - return m_map.reference(i0,i1,i2,i3,i4); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value), + reference_type>::type + access(const iType0& i0, const iType1& i1, const iType2& i2, const iType3& i3, + const iType4& i4) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (5, this->rank(), m_track, m_map, i0, i1, i2, i3, i4)) + return m_map.reference(i0, i1, i2, i3, i4); + } - template< typename iType0 , typename iType1 , typename iType2 , typename iType3, typename iType4 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - access(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 , const iType4 & i4 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (5 , this->rank(), m_track, m_map, i0, i1, i2, i3, i4) ) - return m_map.reference(i0,i1,i2,i3,i4,0,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + access(const iType0& i0, const iType1& i1, const iType2& i2, const iType3& i3, + const iType4& i4) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (5, this->rank(), m_track, m_map, i0, i1, i2, i3, i4)) + return m_map.reference(i0, i1, i2, i3, i4, 0, 0); + } // Rank 6 - template< typename iType0 , typename iType1 , typename iType2 , typename iType3, typename iType4 , typename iType5 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value), reference_type>::type - access(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 , const iType4 & i4 , const iType5 & i5 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (6 , this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5) ) - return m_map.reference(i0,i1,i2,i3,i4,i5); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value), + reference_type>::type + access(const iType0& i0, const iType1& i1, const iType2& i2, const iType3& i3, + const iType4& i4, const iType5& i5) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (6, this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5)) + return m_map.reference(i0, i1, i2, i3, i4, i5); + } - template< typename iType0 , typename iType1 , typename iType2 , typename iType3, typename iType4 , typename iType5 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - access(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 , const iType4 & i4 , const iType5 & i5 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (6 , this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5) ) - return m_map.reference(i0,i1,i2,i3,i4,i5,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + access(const iType0& i0, const iType1& i1, const iType2& i2, const iType3& i3, + const iType4& i4, const iType5& i5) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (6, this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5)) + return m_map.reference(i0, i1, i2, i3, i4, i5, 0); + } // Rank 7 - template< typename iType0 , typename iType1 , typename iType2 , typename iType3, typename iType4 , typename iType5 , typename iType6 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value), reference_type>::type - access(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 , const iType4 & i4 , const iType5 & i5 , const iType6 & i6 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (7 , this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5, i6) ) - return m_map.reference(i0,i1,i2,i3,i4,i5,i6); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value), + reference_type>::type + access(const iType0& i0, const iType1& i1, const iType2& i2, const iType3& i3, + const iType4& i4, const iType5& i5, const iType6& i6) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (7, this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5, i6)) + return m_map.reference(i0, i1, i2, i3, i4, i5, i6); + } #undef KOKKOS_IMPL_VIEW_OPERATOR_VERIFY @@ -927,405 +1069,393 @@ public: ~DynRankView() {} KOKKOS_INLINE_FUNCTION - DynRankView() : m_track(), m_map(), m_rank() {} //Default ctor + DynRankView() : m_track(), m_map(), m_rank() {} // Default ctor KOKKOS_INLINE_FUNCTION - DynRankView( const DynRankView & rhs ) : m_track( rhs.m_track ), m_map( rhs.m_map ), m_rank(rhs.m_rank) {} + DynRankView(const DynRankView& rhs) + : m_track(rhs.m_track), m_map(rhs.m_map), m_rank(rhs.m_rank) {} KOKKOS_INLINE_FUNCTION - DynRankView( DynRankView && rhs ) : m_track( rhs.m_track ), m_map( rhs.m_map ), m_rank(rhs.m_rank) {} + DynRankView(DynRankView&& rhs) + : m_track(rhs.m_track), m_map(rhs.m_map), m_rank(rhs.m_rank) {} KOKKOS_INLINE_FUNCTION - DynRankView & operator = ( const DynRankView & rhs ) { m_track = rhs.m_track; m_map = rhs.m_map; m_rank = rhs.m_rank; return *this; } + DynRankView& operator=(const DynRankView& rhs) { + m_track = rhs.m_track; + m_map = rhs.m_map; + m_rank = rhs.m_rank; + return *this; + } KOKKOS_INLINE_FUNCTION - DynRankView & operator = ( DynRankView && rhs ) { m_track = rhs.m_track; m_map = rhs.m_map; m_rank = rhs.m_rank; return *this; } + DynRankView& operator=(DynRankView&& rhs) { + m_track = rhs.m_track; + m_map = rhs.m_map; + m_rank = rhs.m_rank; + return *this; + } //---------------------------------------- // Compatible view copy constructor and assignment // may assign unmanaged from managed. - template< class RT , class ... RP > - KOKKOS_INLINE_FUNCTION - DynRankView( const DynRankView & rhs ) - : m_track( rhs.m_track , traits::is_managed ) - , m_map() - , m_rank(rhs.m_rank) - { - typedef typename DynRankView ::traits SrcTraits ; - typedef Kokkos::Impl::ViewMapping< traits , SrcTraits , typename traits::specialize > Mapping ; - static_assert( Mapping::is_assignable , "Incompatible DynRankView copy construction" ); - Mapping::assign( m_map , rhs.m_map , rhs.m_track ); - } + template + KOKKOS_INLINE_FUNCTION DynRankView(const DynRankView& rhs) + : m_track(rhs.m_track, traits::is_managed), m_map(), m_rank(rhs.m_rank) { + typedef typename DynRankView::traits SrcTraits; + typedef Kokkos::Impl::ViewMapping + Mapping; + static_assert(Mapping::is_assignable, + "Incompatible DynRankView copy construction"); + Mapping::assign(m_map, rhs.m_map, rhs.m_track); + } - template< class RT , class ... RP > - KOKKOS_INLINE_FUNCTION - DynRankView & operator = (const DynRankView & rhs ) - { - typedef typename DynRankView ::traits SrcTraits ; - typedef Kokkos::Impl::ViewMapping< traits , SrcTraits , typename traits::specialize > Mapping ; - static_assert( Mapping::is_assignable , "Incompatible DynRankView copy construction" ); - Mapping::assign( m_map , rhs.m_map , rhs.m_track ); - m_track.assign( rhs.m_track , traits::is_managed ); - m_rank = rhs.rank(); - return *this; - } + template + KOKKOS_INLINE_FUNCTION DynRankView& operator=( + const DynRankView& rhs) { + typedef typename DynRankView::traits SrcTraits; + typedef Kokkos::Impl::ViewMapping + Mapping; + static_assert(Mapping::is_assignable, + "Incompatible DynRankView copy construction"); + Mapping::assign(m_map, rhs.m_map, rhs.m_track); + m_track.assign(rhs.m_track, traits::is_managed); + m_rank = rhs.rank(); + return *this; + } -// Copy/Assign View to DynRankView - template< class RT , class ... RP > - KOKKOS_INLINE_FUNCTION - DynRankView( const View & rhs ) - : m_track() - , m_map() - , m_rank( rhs.Rank ) - { - typedef typename View::traits SrcTraits ; - typedef Kokkos::Impl::ViewMapping< traits , SrcTraits , Kokkos::Impl::ViewToDynRankViewTag > Mapping ; - static_assert( Mapping::is_assignable , "Incompatible View to DynRankView copy construction" ); - Mapping::assign( *this , rhs ); - } + // Copy/Assign View to DynRankView + template + KOKKOS_INLINE_FUNCTION DynRankView(const View& rhs) + : m_track(), m_map(), m_rank(rhs.Rank) { + typedef typename View::traits SrcTraits; + typedef Kokkos::Impl::ViewMapping + Mapping; + static_assert(Mapping::is_assignable, + "Incompatible View to DynRankView copy construction"); + Mapping::assign(*this, rhs); + } - template< class RT , class ... RP > - KOKKOS_INLINE_FUNCTION - DynRankView & operator = ( const View & rhs ) - { - typedef typename View::traits SrcTraits ; - typedef Kokkos::Impl::ViewMapping< traits , SrcTraits , Kokkos::Impl::ViewToDynRankViewTag > Mapping ; - static_assert( Mapping::is_assignable , "Incompatible View to DynRankView copy assignment" ); - Mapping::assign( *this , rhs ); - return *this ; - } + template + KOKKOS_INLINE_FUNCTION DynRankView& operator=(const View& rhs) { + typedef typename View::traits SrcTraits; + typedef Kokkos::Impl::ViewMapping + Mapping; + static_assert(Mapping::is_assignable, + "Incompatible View to DynRankView copy assignment"); + Mapping::assign(*this, rhs); + return *this; + } //---------------------------------------- // Allocation tracking properties KOKKOS_INLINE_FUNCTION - int use_count() const - { return m_track.use_count(); } + int use_count() const { return m_track.use_count(); } - inline - const std::string label() const - { return m_track.template get_label< typename traits::memory_space >(); } + inline const std::string label() const { + return m_track.template get_label(); + } //---------------------------------------- // Allocation according to allocation properties and array layout - // unused arg_layout dimensions must be set to KOKKOS_INVALID_INDEX so that rank deduction can properly take place - template< class ... P > - explicit inline - DynRankView( const Kokkos::Impl::ViewCtorProp< P ... > & arg_prop - , typename std::enable_if< ! Kokkos::Impl::ViewCtorProp< P... >::has_pointer - , typename traits::array_layout - >::type const & arg_layout - ) - : m_track() - , m_map() - , m_rank( Impl::DynRankDimTraits::template computeRank< typename traits::array_layout, P...>(arg_prop, arg_layout) ) - { - // Append layout and spaces if not input - typedef Kokkos::Impl::ViewCtorProp< P ... > alloc_prop_input ; - - // use 'std::integral_constant' for non-types - // to avoid duplicate class error. - typedef Kokkos::Impl::ViewCtorProp - < P ... - , typename std::conditional - < alloc_prop_input::has_label - , std::integral_constant - , typename std::string - >::type - , typename std::conditional - < alloc_prop_input::has_memory_space - , std::integral_constant - , typename traits::device_type::memory_space - >::type - , typename std::conditional - < alloc_prop_input::has_execution_space - , std::integral_constant - , typename traits::device_type::execution_space - >::type - > alloc_prop ; - - static_assert( traits::is_managed - , "View allocation constructor requires managed memory" ); - - if ( alloc_prop::initialize && + // unused arg_layout dimensions must be set to KOKKOS_INVALID_INDEX so that + // rank deduction can properly take place + template + explicit inline DynRankView( + const Kokkos::Impl::ViewCtorProp& arg_prop, + typename std::enable_if::has_pointer, + typename traits::array_layout>::type const& + arg_layout) + : m_track(), + m_map(), + m_rank(Impl::DynRankDimTraits:: + template computeRank( + arg_prop, arg_layout)) { + // Append layout and spaces if not input + typedef Kokkos::Impl::ViewCtorProp alloc_prop_input; + + // use 'std::integral_constant' for non-types + // to avoid duplicate class error. + typedef Kokkos::Impl::ViewCtorProp< + P..., + typename std::conditional, + typename std::string>::type, + typename std::conditional< + alloc_prop_input::has_memory_space, + std::integral_constant, + typename traits::device_type::memory_space>::type, + typename std::conditional< + alloc_prop_input::has_execution_space, + std::integral_constant, + typename traits::device_type::execution_space>::type> + alloc_prop; + + static_assert(traits::is_managed, + "View allocation constructor requires managed memory"); + + if (alloc_prop::initialize && #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - ! alloc_prop::execution_space::is_initialized() + !alloc_prop::execution_space::is_initialized() #else - ! alloc_prop::execution_space::impl_is_initialized() + !alloc_prop::execution_space::impl_is_initialized() #endif - ) { - // If initializing view data then - // the execution space must be initialized. - Kokkos::Impl::throw_runtime_exception("Constructing DynRankView and initializing data with uninitialized execution space"); - } + ) { + // If initializing view data then + // the execution space must be initialized. + Kokkos::Impl::throw_runtime_exception( + "Constructing DynRankView and initializing data with uninitialized " + "execution space"); + } - // Copy the input allocation properties with possibly defaulted properties - alloc_prop prop_copy( arg_prop ); + // Copy the input allocation properties with possibly defaulted properties + alloc_prop prop_copy(arg_prop); //------------------------------------------------------------ -#if defined( KOKKOS_ENABLE_CUDA ) - // If allocating in CudaUVMSpace must fence before and after - // the allocation to protect against possible concurrent access - // on the CPU and the GPU. - // Fence using the trait's executon space (which will be Kokkos::Cuda) - // to avoid incomplete type errors from usng Kokkos::Cuda directly. - if ( std::is_same< Kokkos::CudaUVMSpace , typename traits::device_type::memory_space >::value ) { - typename traits::device_type::memory_space::execution_space().fence(); - } +#if defined(KOKKOS_ENABLE_CUDA) + // If allocating in CudaUVMSpace must fence before and after + // the allocation to protect against possible concurrent access + // on the CPU and the GPU. + // Fence using the trait's executon space (which will be Kokkos::Cuda) + // to avoid incomplete type errors from usng Kokkos::Cuda directly. + if (std::is_same::value) { + typename traits::device_type::memory_space::execution_space().fence(); + } #endif -//------------------------------------------------------------ + //------------------------------------------------------------ - Kokkos::Impl::SharedAllocationRecord<> * - record = m_map.allocate_shared( prop_copy, Impl::DynRankDimTraits::template createLayout(arg_prop, arg_layout) ); + Kokkos::Impl::SharedAllocationRecord<>* record = m_map.allocate_shared( + prop_copy, + Impl::DynRankDimTraits:: + template createLayout(arg_prop, arg_layout)); //------------------------------------------------------------ -#if defined( KOKKOS_ENABLE_CUDA ) - if ( std::is_same< Kokkos::CudaUVMSpace , typename traits::device_type::memory_space >::value ) { - typename traits::device_type::memory_space::execution_space().fence(); - } -#endif -//------------------------------------------------------------ - - // Setup and initialization complete, start tracking - m_track.assign_allocated_record_to_uninitialized( record ); +#if defined(KOKKOS_ENABLE_CUDA) + if (std::is_same::value) { + typename traits::device_type::memory_space::execution_space().fence(); } +#endif + //------------------------------------------------------------ + // Setup and initialization complete, start tracking + m_track.assign_allocated_record_to_uninitialized(record); + } // Wrappers - template< class ... P > - explicit KOKKOS_INLINE_FUNCTION - DynRankView( const Kokkos::Impl::ViewCtorProp< P ... > & arg_prop - , typename std::enable_if< Kokkos::Impl::ViewCtorProp< P... >::has_pointer - , typename traits::array_layout - >::type const & arg_layout - ) - : m_track() // No memory tracking - , m_map( arg_prop , Impl::DynRankDimTraits::template createLayout(arg_prop, arg_layout) ) - , m_rank( Impl::DynRankDimTraits::template computeRank< typename traits::array_layout, P...>(arg_prop, arg_layout) ) - { - static_assert( - std::is_same< pointer_type - , typename Impl::ViewCtorProp< P... >::pointer_type - >::value , - "Constructing DynRankView to wrap user memory must supply matching pointer type" ); - } + template + explicit KOKKOS_INLINE_FUNCTION DynRankView( + const Kokkos::Impl::ViewCtorProp& arg_prop, + typename std::enable_if::has_pointer, + typename traits::array_layout>::type const& + arg_layout) + : m_track() // No memory tracking + , + m_map(arg_prop, + Impl::DynRankDimTraits:: + template createLayout(arg_prop, arg_layout)), + m_rank(Impl::DynRankDimTraits:: + template computeRank( + arg_prop, arg_layout)) { + static_assert( + std::is_same::pointer_type>::value, + "Constructing DynRankView to wrap user memory must supply matching " + "pointer type"); + } //---------------------------------------- - //Constructor(s) + // Constructor(s) // Simple dimension-only layout - template< class ... P > - explicit inline - DynRankView( const Kokkos::Impl::ViewCtorProp< P ... > & arg_prop - , typename std::enable_if< ! Kokkos::Impl::ViewCtorProp< P... >::has_pointer - , size_t - >::type const arg_N0 =KOKKOS_INVALID_INDEX - , const size_t arg_N1 =KOKKOS_INVALID_INDEX - , const size_t arg_N2 =KOKKOS_INVALID_INDEX - , const size_t arg_N3 =KOKKOS_INVALID_INDEX - , const size_t arg_N4 =KOKKOS_INVALID_INDEX - , const size_t arg_N5 =KOKKOS_INVALID_INDEX - , const size_t arg_N6 =KOKKOS_INVALID_INDEX - , const size_t arg_N7 =KOKKOS_INVALID_INDEX - ) - : DynRankView( arg_prop - , typename traits::array_layout - ( arg_N0 , arg_N1 , arg_N2 , arg_N3 , arg_N4 , arg_N5 , arg_N6 , arg_N7 ) - ) - {} - - template< class ... P > - explicit KOKKOS_INLINE_FUNCTION - DynRankView( const Kokkos::Impl::ViewCtorProp< P ... > & arg_prop - , typename std::enable_if< Kokkos::Impl::ViewCtorProp< P... >::has_pointer - , size_t - >::type const arg_N0 =KOKKOS_INVALID_INDEX - , const size_t arg_N1 =KOKKOS_INVALID_INDEX - , const size_t arg_N2 =KOKKOS_INVALID_INDEX - , const size_t arg_N3 =KOKKOS_INVALID_INDEX - , const size_t arg_N4 =KOKKOS_INVALID_INDEX - , const size_t arg_N5 =KOKKOS_INVALID_INDEX - , const size_t arg_N6 =KOKKOS_INVALID_INDEX - , const size_t arg_N7 =KOKKOS_INVALID_INDEX - ) - : DynRankView( arg_prop - , typename traits::array_layout - ( arg_N0 , arg_N1 , arg_N2 , arg_N3 , arg_N4 , arg_N5 , arg_N6 , arg_N7 ) - ) - {} + template + explicit inline DynRankView( + const Kokkos::Impl::ViewCtorProp& arg_prop, + typename std::enable_if::has_pointer, + size_t>::type const arg_N0 = KOKKOS_INVALID_INDEX, + const size_t arg_N1 = KOKKOS_INVALID_INDEX, + const size_t arg_N2 = KOKKOS_INVALID_INDEX, + const size_t arg_N3 = KOKKOS_INVALID_INDEX, + const size_t arg_N4 = KOKKOS_INVALID_INDEX, + const size_t arg_N5 = KOKKOS_INVALID_INDEX, + const size_t arg_N6 = KOKKOS_INVALID_INDEX, + const size_t arg_N7 = KOKKOS_INVALID_INDEX) + : DynRankView(arg_prop, typename traits::array_layout( + arg_N0, arg_N1, arg_N2, arg_N3, arg_N4, + arg_N5, arg_N6, arg_N7)) {} + + template + explicit KOKKOS_INLINE_FUNCTION DynRankView( + const Kokkos::Impl::ViewCtorProp& arg_prop, + typename std::enable_if::has_pointer, + size_t>::type const arg_N0 = KOKKOS_INVALID_INDEX, + const size_t arg_N1 = KOKKOS_INVALID_INDEX, + const size_t arg_N2 = KOKKOS_INVALID_INDEX, + const size_t arg_N3 = KOKKOS_INVALID_INDEX, + const size_t arg_N4 = KOKKOS_INVALID_INDEX, + const size_t arg_N5 = KOKKOS_INVALID_INDEX, + const size_t arg_N6 = KOKKOS_INVALID_INDEX, + const size_t arg_N7 = KOKKOS_INVALID_INDEX) + : DynRankView(arg_prop, typename traits::array_layout( + arg_N0, arg_N1, arg_N2, arg_N3, arg_N4, + arg_N5, arg_N6, arg_N7)) {} // Allocate with label and layout - template< typename Label > - explicit inline - DynRankView( const Label & arg_label - , typename std::enable_if< - Kokkos::Impl::is_view_label
  • /// -class UnorderedMapInsertResult -{ -private: - enum Status{ - SUCCESS = 1u << 31 - , EXISTING = 1u << 30 - , FREED_EXISTING = 1u << 29 - , LIST_LENGTH_MASK = ~(SUCCESS | EXISTING | FREED_EXISTING) +class UnorderedMapInsertResult { + private: + enum Status { + SUCCESS = 1u << 31, + EXISTING = 1u << 30, + FREED_EXISTING = 1u << 29, + LIST_LENGTH_MASK = ~(SUCCESS | EXISTING | FREED_EXISTING) }; -public: + public: /// Did the map successful insert the key/value pair KOKKOS_FORCEINLINE_FUNCTION bool success() const { return (m_status & SUCCESS); } @@ -102,7 +100,7 @@ public: KOKKOS_FORCEINLINE_FUNCTION bool existing() const { return (m_status & EXISTING); } - /// Did the map fail to insert the key due to insufficient capacity + /// Did the map fail to insert the key due to insufficent capacity KOKKOS_FORCEINLINE_FUNCTION bool failed() const { return m_index == UnorderedMapInvalidIndex; } @@ -121,32 +119,27 @@ public: uint32_t index() const { return m_index; } KOKKOS_FORCEINLINE_FUNCTION - UnorderedMapInsertResult() - : m_index(UnorderedMapInvalidIndex) - , m_status(0) - {} + UnorderedMapInsertResult() : m_index(UnorderedMapInvalidIndex), m_status(0) {} KOKKOS_FORCEINLINE_FUNCTION - void increment_list_position() - { + void increment_list_position() { m_status += (list_position() < LIST_LENGTH_MASK) ? 1u : 0u; } KOKKOS_FORCEINLINE_FUNCTION - void set_existing(uint32_t i, bool arg_freed_existing) - { + void set_existing(uint32_t i, bool arg_freed_existing) { m_index = i; - m_status = EXISTING | (arg_freed_existing ? FREED_EXISTING : 0u) | list_position(); + m_status = + EXISTING | (arg_freed_existing ? FREED_EXISTING : 0u) | list_position(); } KOKKOS_FORCEINLINE_FUNCTION - void set_success(uint32_t i) - { - m_index = i; + void set_success(uint32_t i) { + m_index = i; m_status = SUCCESS | list_position(); } -private: + private: uint32_t m_index; uint32_t m_status; }; @@ -206,26 +199,26 @@ private: /// \tparam EqualTo Definition of the equality function for instances of /// Key. The default will do a bitwise equality comparison. /// -template < typename Key - , typename Value - , typename Device = Kokkos::DefaultExecutionSpace - , typename Hasher = pod_hash::type> - , typename EqualTo = pod_equal_to::type> - > -class UnorderedMap -{ -private: - typedef typename ViewTraits::host_mirror_space host_mirror_space ; -public: +template ::type>, + typename EqualTo = + pod_equal_to::type> > +class UnorderedMap { + private: + typedef typename ViewTraits::host_mirror_space + host_mirror_space; + + public: //! \name Public types and constants //@{ - //key_types + // key_types typedef Key declared_key_type; typedef typename Impl::remove_const::type key_type; typedef typename Impl::add_const::type const_key_type; - //value_types + // value_types typedef Value declared_value_type; typedef typename Impl::remove_const::type value_type; typedef typename Impl::add_const::type const_value_type; @@ -233,116 +226,126 @@ public: typedef Device device_type; typedef typename Device::execution_space execution_space; typedef Hasher hasher_type; - typedef EqualTo equal_to_type; + typedef EqualTo equal_to_type; typedef uint32_t size_type; - //map_types - typedef UnorderedMap declared_map_type; - typedef UnorderedMap insertable_map_type; - typedef UnorderedMap modifiable_map_type; - typedef UnorderedMap const_map_type; - - static const bool is_set = std::is_same::value; - static const bool has_const_key = std::is_same::value; - static const bool has_const_value = is_set || std::is_same::value; - - static const bool is_insertable_map = !has_const_key && (is_set || !has_const_value); + // map_types + typedef UnorderedMap + declared_map_type; + typedef UnorderedMap + insertable_map_type; + typedef UnorderedMap + modifiable_map_type; + typedef UnorderedMap + const_map_type; + + static const bool is_set = std::is_same::value; + static const bool has_const_key = + std::is_same::value; + static const bool has_const_value = + is_set || std::is_same::value; + + static const bool is_insertable_map = + !has_const_key && (is_set || !has_const_value); static const bool is_modifiable_map = has_const_key && !has_const_value; - static const bool is_const_map = has_const_key && has_const_value; - + static const bool is_const_map = has_const_key && has_const_value; typedef UnorderedMapInsertResult insert_result; - typedef UnorderedMap HostMirror; + typedef UnorderedMap + HostMirror; typedef Impl::UnorderedMapHistogram histogram_type; //@} -private: + private: enum { invalid_index = ~static_cast(0) }; - typedef typename Impl::if_c< is_set, int, declared_value_type>::type impl_value_type; + typedef typename Impl::if_c::type + impl_value_type; - typedef typename Impl::if_c< is_insertable_map - , View< key_type *, device_type> - , View< const key_type *, device_type, MemoryTraits > - >::type key_type_view; + typedef typename Impl::if_c< + is_insertable_map, View, + View > >::type + key_type_view; - typedef typename Impl::if_c< is_insertable_map || is_modifiable_map - , View< impl_value_type *, device_type> - , View< const impl_value_type *, device_type, MemoryTraits > - >::type value_type_view; + typedef typename Impl::if_c, + View > >::type + value_type_view; - typedef typename Impl::if_c< is_insertable_map - , View< size_type *, device_type> - , View< const size_type *, device_type, MemoryTraits > - >::type size_type_view; + typedef typename Impl::if_c< + is_insertable_map, View, + View > >::type + size_type_view; - typedef typename Impl::if_c< is_insertable_map - , Bitset< execution_space > - , ConstBitset< execution_space> - >::type bitset_type; + typedef typename Impl::if_c, + ConstBitset >::type bitset_type; enum { modified_idx = 0, erasable_idx = 1, failed_insert_idx = 2 }; enum { num_scalars = 3 }; - typedef View< int[num_scalars], LayoutLeft, device_type> scalars_view; + typedef View scalars_view; -public: + public: //! \name Public member functions //@{ UnorderedMap() - : m_bounded_insert() - , m_hasher() - , m_equal_to() - , m_size() - , m_available_indexes() - , m_hash_lists() - , m_next_index() - , m_keys() - , m_values() - , m_scalars() - {} + : m_bounded_insert(), + m_hasher(), + m_equal_to(), + m_size(), + m_available_indexes(), + m_hash_lists(), + m_next_index(), + m_keys(), + m_values(), + m_scalars() {} /// \brief Constructor /// - /// \param capacity_hint [in] Initial guess of how many unique keys will be inserted into the map - /// \param hash [in] Hasher function for \c Key instances. The + /// \param capacity_hint [in] Initial guess of how many unique keys will be + /// inserted into the map \param hash [in] Hasher function for \c Key + /// instances. The /// default value usually suffices. - UnorderedMap( size_type capacity_hint, hasher_type hasher = hasher_type(), equal_to_type equal_to = equal_to_type() ) - : m_bounded_insert(true) - , m_hasher(hasher) - , m_equal_to(equal_to) - , m_size() - , m_available_indexes(calculate_capacity(capacity_hint)) - , m_hash_lists(ViewAllocateWithoutInitializing("UnorderedMap hash list"), Impl::find_hash_size(capacity())) - , m_next_index(ViewAllocateWithoutInitializing("UnorderedMap next index"), capacity()+1) // +1 so that the *_at functions can always return a valid reference - , m_keys("UnorderedMap keys",capacity()+1) - , m_values("UnorderedMap values",(is_set? 1 : capacity()+1)) - , m_scalars("UnorderedMap scalars") - { + UnorderedMap(size_type capacity_hint, hasher_type hasher = hasher_type(), + equal_to_type equal_to = equal_to_type()) + : m_bounded_insert(true), + m_hasher(hasher), + m_equal_to(equal_to), + m_size(), + m_available_indexes(calculate_capacity(capacity_hint)), + m_hash_lists(ViewAllocateWithoutInitializing("UnorderedMap hash list"), + Impl::find_hash_size(capacity())), + m_next_index(ViewAllocateWithoutInitializing("UnorderedMap next index"), + capacity() + 1) // +1 so that the *_at functions can + // always return a valid reference + , + m_keys("UnorderedMap keys", capacity() + 1), + m_values("UnorderedMap values", (is_set ? 1 : capacity() + 1)), + m_scalars("UnorderedMap scalars") { if (!is_insertable_map) { - throw std::runtime_error("Cannot construct a non-insertable (i.e. const key_type) unordered_map"); + throw std::runtime_error( + "Cannot construct a non-insertable (i.e. const key_type) " + "unordered_map"); } Kokkos::deep_copy(m_hash_lists, invalid_index); Kokkos::deep_copy(m_next_index, invalid_index); } - void reset_failed_insert_flag() - { - reset_flag(failed_insert_idx); - } + void reset_failed_insert_flag() { reset_flag(failed_insert_idx); } - histogram_type get_histogram() - { - return histogram_type(*this); - } + histogram_type get_histogram() { return histogram_type(*this); } //! Clear all entries in the table. - void clear() - { + void clear() { m_bounded_insert = true; if (capacity() == 0) return; @@ -353,15 +356,13 @@ public: Kokkos::deep_copy(m_next_index, invalid_index); { const key_type tmp = key_type(); - Kokkos::deep_copy(m_keys,tmp); + Kokkos::deep_copy(m_keys, tmp); } - if (is_set){ + if (is_set) { const impl_value_type tmp = impl_value_type(); - Kokkos::deep_copy(m_values,tmp); - } - { - Kokkos::deep_copy(m_scalars, 0); + Kokkos::deep_copy(m_values, tmp); } + { Kokkos::deep_copy(m_scalars, 0); } } /// \brief Change the capacity of the the map @@ -374,24 +375,23 @@ public: /// /// This is not a device function; it may not be /// called in a parallel kernel. - bool rehash(size_type requested_capacity = 0) - { + bool rehash(size_type requested_capacity = 0) { const bool bounded_insert = (capacity() == 0) || (size() == 0u); - return rehash(requested_capacity, bounded_insert ); + return rehash(requested_capacity, bounded_insert); } - bool rehash(size_type requested_capacity, bool bounded_insert) - { - if(!is_insertable_map) return false; + bool rehash(size_type requested_capacity, bool bounded_insert) { + if (!is_insertable_map) return false; const size_type curr_size = size(); - requested_capacity = (requested_capacity < curr_size) ? curr_size : requested_capacity; + requested_capacity = + (requested_capacity < curr_size) ? curr_size : requested_capacity; insertable_map_type tmp(requested_capacity, m_hasher, m_equal_to); if (curr_size) { tmp.m_bounded_insert = false; - Impl::UnorderedMapRehash f(tmp,*this); + Impl::UnorderedMapRehash f(tmp, *this); f.apply(); } tmp.m_bounded_insert = bounded_insert; @@ -408,9 +408,8 @@ public: /// Note that this is not a device function; it cannot be called in /// a parallel kernel. The value is not stored as a variable; it /// must be computed. - size_type size() const - { - if( capacity() == 0u ) return 0u; + size_type size() const { + if (capacity() == 0u) return 0u; if (modified()) { m_size = m_available_indexes.count(); reset_flag(modified_idx); @@ -423,18 +422,13 @@ public: /// This is not a device function; it may not be /// called in a parallel kernel. The value is not stored as a /// variable; it must be computed. - bool failed_insert() const - { - return get_flag(failed_insert_idx); - } + bool failed_insert() const { return get_flag(failed_insert_idx); } - bool erasable() const - { + bool erasable() const { return is_insertable_map ? get_flag(erasable_idx) : false; } - bool begin_erase() - { + bool begin_erase() { bool result = !erasable(); if (is_insertable_map && result) { execution_space().fence(); @@ -444,8 +438,7 @@ public: return result; } - bool end_erase() - { + bool end_erase() { bool result = erasable(); if (is_insertable_map && result) { execution_space().fence(); @@ -462,8 +455,7 @@ public: /// This is a device function; it may be called in a parallel /// kernel. KOKKOS_FORCEINLINE_FUNCTION - size_type capacity() const - { return m_available_indexes.size(); } + size_type capacity() const { return m_available_indexes.size(); } /// \brief The number of hash table "buckets." /// @@ -476,13 +468,11 @@ public: /// This is a device function; it may be called in a parallel /// kernel. KOKKOS_INLINE_FUNCTION - size_type hash_capacity() const - { return m_hash_lists.extent(0); } + size_type hash_capacity() const { return m_hash_lists.extent(0); } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- - /// This is a device function; it may be called in a parallel /// kernel. As discussed in the class documentation, it need not /// succeed. The return value tells you if it did. @@ -492,136 +482,138 @@ public: /// using this class as a set (with Value = void), then you need not /// provide this value. KOKKOS_INLINE_FUNCTION - insert_result insert(key_type const& k, impl_value_type const&v = impl_value_type()) const - { + insert_result insert(key_type const &k, + impl_value_type const &v = impl_value_type()) const { insert_result result; - if ( !is_insertable_map || capacity() == 0u || m_scalars((int)erasable_idx) ) { + if (!is_insertable_map || capacity() == 0u || + m_scalars((int)erasable_idx)) { return result; } - if ( !m_scalars((int)modified_idx) ) { + if (!m_scalars((int)modified_idx)) { m_scalars((int)modified_idx) = true; } - int volatile & failed_insert_ref = m_scalars((int)failed_insert_idx) ; + int volatile &failed_insert_ref = m_scalars((int)failed_insert_idx); const size_type hash_value = m_hasher(k); - const size_type hash_list = hash_value % m_hash_lists.extent(0); + const size_type hash_list = hash_value % m_hash_lists.extent(0); - size_type * curr_ptr = & m_hash_lists[ hash_list ]; - size_type new_index = invalid_index ; + size_type *curr_ptr = &m_hash_lists[hash_list]; + size_type new_index = invalid_index; // Force integer multiply to long - size_type index_hint = static_cast( (static_cast(hash_list) * capacity()) / m_hash_lists.extent(0)); + size_type index_hint = static_cast( + (static_cast(hash_list) * capacity()) / m_hash_lists.extent(0)); size_type find_attempts = 0; enum : unsigned { bounded_find_attempts = 32u }; - const size_type max_attempts = (m_bounded_insert && (bounded_find_attempts < m_available_indexes.max_hint()) ) ? - bounded_find_attempts : - m_available_indexes.max_hint(); + const size_type max_attempts = + (m_bounded_insert && + (bounded_find_attempts < m_available_indexes.max_hint())) + ? bounded_find_attempts + : m_available_indexes.max_hint(); - bool not_done = true ; + bool not_done = true; -#if defined( __MIC__ ) - #pragma noprefetch +#if defined(__MIC__) +#pragma noprefetch #endif - while ( not_done ) { - + while (not_done) { // Continue searching the unordered list for this key, // list will only be appended during insert phase. // Need volatile_load as other threads may be appending. size_type curr = volatile_load(curr_ptr); - KOKKOS_NONTEMPORAL_PREFETCH_LOAD(&m_keys[curr != invalid_index ? curr : 0]); -#if defined( __MIC__ ) - #pragma noprefetch + KOKKOS_NONTEMPORAL_PREFETCH_LOAD( + &m_keys[curr != invalid_index ? curr : 0]); +#if defined(__MIC__) +#pragma noprefetch #endif - while ( curr != invalid_index && ! m_equal_to( volatile_load(&m_keys[curr]), k) ) { + while (curr != invalid_index && + !m_equal_to(volatile_load(&m_keys[curr]), k)) { result.increment_list_position(); index_hint = curr; - curr_ptr = &m_next_index[curr]; - curr = volatile_load(curr_ptr); - KOKKOS_NONTEMPORAL_PREFETCH_LOAD(&m_keys[curr != invalid_index ? curr : 0]); + curr_ptr = &m_next_index[curr]; + curr = volatile_load(curr_ptr); + KOKKOS_NONTEMPORAL_PREFETCH_LOAD( + &m_keys[curr != invalid_index ? curr : 0]); } //------------------------------------------------------------ // If key already present then return that index. - if ( curr != invalid_index ) { - + if (curr != invalid_index) { const bool free_existing = new_index != invalid_index; - if ( free_existing ) { + if (free_existing) { // Previously claimed an unused entry that was not inserted. // Release this unused entry immediately. - if (!m_available_indexes.reset(new_index) ) { + if (!m_available_indexes.reset(new_index)) { printf("Unable to free existing\n"); } - } result.set_existing(curr, free_existing); - not_done = false ; + not_done = false; } //------------------------------------------------------------ // Key is not currently in the map. // If the thread has claimed an entry try to insert now. else { - //------------------------------------------------------------ // If have not already claimed an unused entry then do so now. if (new_index == invalid_index) { - bool found = false; // use the hash_list as the flag for the search direction - Kokkos::tie(found, index_hint) = m_available_indexes.find_any_unset_near( index_hint, hash_list ); + Kokkos::tie(found, index_hint) = + m_available_indexes.find_any_unset_near(index_hint, hash_list); // found and index and this thread set it - if ( !found && ++find_attempts >= max_attempts ) { + if (!found && ++find_attempts >= max_attempts) { failed_insert_ref = true; - not_done = false ; - } - else if (m_available_indexes.set(index_hint) ) { + not_done = false; + } else if (m_available_indexes.set(index_hint)) { new_index = index_hint; // Set key and value KOKKOS_NONTEMPORAL_PREFETCH_STORE(&m_keys[new_index]); - m_keys[new_index] = k ; + m_keys[new_index] = k; if (!is_set) { KOKKOS_NONTEMPORAL_PREFETCH_STORE(&m_values[new_index]); - m_values[new_index] = v ; + m_values[new_index] = v; } // Do not proceed until key and value are updated in global memory memory_fence(); } - } - else if (failed_insert_ref) { + } else if (failed_insert_ref) { not_done = false; } // Attempt to append claimed entry into the list. - // Another thread may also be trying to append the same list so protect with atomic. - if ( new_index != invalid_index && - curr == atomic_compare_exchange(curr_ptr, static_cast(invalid_index), new_index) ) { + // Another thread may also be trying to append the same list so protect + // with atomic. + if (new_index != invalid_index && + curr == atomic_compare_exchange( + curr_ptr, static_cast(invalid_index), + new_index)) { // Succeeded in appending result.set_success(new_index); - not_done = false ; + not_done = false; } } - } // while ( not_done ) + } // while ( not_done ) - return result ; + return result; } KOKKOS_INLINE_FUNCTION - bool erase(key_type const& k) const - { + bool erase(key_type const &k) const { bool result = false; - if(is_insertable_map && 0u < capacity() && m_scalars((int)erasable_idx)) { - - if ( ! m_scalars((int)modified_idx) ) { + if (is_insertable_map && 0u < capacity() && m_scalars((int)erasable_idx)) { + if (!m_scalars((int)modified_idx)) { m_scalars((int)modified_idx) = true; } @@ -643,13 +635,15 @@ public: /// This is a device function; it may be called in a parallel /// kernel. KOKKOS_INLINE_FUNCTION - size_type find( const key_type & k) const - { - size_type curr = 0u < capacity() ? m_hash_lists( m_hasher(k) % m_hash_lists.extent(0) ) : invalid_index ; + size_type find(const key_type &k) const { + size_type curr = 0u < capacity() + ? m_hash_lists(m_hasher(k) % m_hash_lists.extent(0)) + : invalid_index; KOKKOS_NONTEMPORAL_PREFETCH_LOAD(&m_keys[curr != invalid_index ? curr : 0]); - while (curr != invalid_index && !m_equal_to( m_keys[curr], k) ) { - KOKKOS_NONTEMPORAL_PREFETCH_LOAD(&m_keys[curr != invalid_index ? curr : 0]); + while (curr != invalid_index && !m_equal_to(m_keys[curr], k)) { + KOKKOS_NONTEMPORAL_PREFETCH_LOAD( + &m_keys[curr != invalid_index ? curr : 0]); curr = m_next_index[curr]; } @@ -661,11 +655,7 @@ public: /// This is a device function; it may be called in a parallel /// kernel. KOKKOS_INLINE_FUNCTION - bool exists( const key_type & k) const - { - return valid_at(find(k)); - } - + bool exists(const key_type &k) const { return valid_at(find(k)); } /// \brief Get the value with \c i as its direct index. /// @@ -676,10 +666,10 @@ public: /// /// 'const value_type' via Cuda texture fetch must return by value. KOKKOS_FORCEINLINE_FUNCTION - typename Impl::if_c< (is_set || has_const_value), impl_value_type, impl_value_type &>::type - value_at(size_type i) const - { - return m_values[ is_set ? 0 : (i < capacity() ? i : capacity()) ]; + typename Impl::if_c<(is_set || has_const_value), impl_value_type, + impl_value_type &>::type + value_at(size_type i) const { + return m_values[is_set ? 0 : (i < capacity() ? i : capacity())]; } /// \brief Get the key with \c i as its direct index. @@ -689,138 +679,154 @@ public: /// This is a device function; it may be called in a parallel /// kernel. KOKKOS_FORCEINLINE_FUNCTION - key_type key_at(size_type i) const - { - return m_keys[ i < capacity() ? i : capacity() ]; + key_type key_at(size_type i) const { + return m_keys[i < capacity() ? i : capacity()]; } KOKKOS_FORCEINLINE_FUNCTION - bool valid_at(size_type i) const - { - return m_available_indexes.test(i); - } + bool valid_at(size_type i) const { return m_available_indexes.test(i); } template - UnorderedMap( UnorderedMap const& src, - typename Impl::enable_if< Impl::UnorderedMapCanAssign::value,int>::type = 0 - ) - : m_bounded_insert(src.m_bounded_insert) - , m_hasher(src.m_hasher) - , m_equal_to(src.m_equal_to) - , m_size(src.m_size) - , m_available_indexes(src.m_available_indexes) - , m_hash_lists(src.m_hash_lists) - , m_next_index(src.m_next_index) - , m_keys(src.m_keys) - , m_values(src.m_values) - , m_scalars(src.m_scalars) - {} - + UnorderedMap( + UnorderedMap const &src, + typename Impl::enable_if< + Impl::UnorderedMapCanAssign::value, + int>::type = 0) + : m_bounded_insert(src.m_bounded_insert), + m_hasher(src.m_hasher), + m_equal_to(src.m_equal_to), + m_size(src.m_size), + m_available_indexes(src.m_available_indexes), + m_hash_lists(src.m_hash_lists), + m_next_index(src.m_next_index), + m_keys(src.m_keys), + m_values(src.m_values), + m_scalars(src.m_scalars) {} template - typename Impl::enable_if< Impl::UnorderedMapCanAssign::value - ,declared_map_type & >::type - operator=( UnorderedMap const& src) - { - m_bounded_insert = src.m_bounded_insert; - m_hasher = src.m_hasher; - m_equal_to = src.m_equal_to; - m_size = src.m_size; + typename Impl::enable_if< + Impl::UnorderedMapCanAssign::value, + declared_map_type &>::type + operator=(UnorderedMap const &src) { + m_bounded_insert = src.m_bounded_insert; + m_hasher = src.m_hasher; + m_equal_to = src.m_equal_to; + m_size = src.m_size; m_available_indexes = src.m_available_indexes; - m_hash_lists = src.m_hash_lists; - m_next_index = src.m_next_index; - m_keys = src.m_keys; - m_values = src.m_values; - m_scalars = src.m_scalars; + m_hash_lists = src.m_hash_lists; + m_next_index = src.m_next_index; + m_keys = src.m_keys; + m_values = src.m_values; + m_scalars = src.m_scalars; return *this; } template - typename Impl::enable_if< std::is_same< typename Impl::remove_const::type, key_type>::value && - std::is_same< typename Impl::remove_const::type, value_type>::value - >::type - create_copy_view( UnorderedMap const& src) - { + typename Impl::enable_if< + std::is_same::type, key_type>::value && + std::is_same::type, + value_type>::value>::type + create_copy_view( + UnorderedMap const &src) { if (m_hash_lists.data() != src.m_hash_lists.data()) { - insertable_map_type tmp; - tmp.m_bounded_insert = src.m_bounded_insert; - tmp.m_hasher = src.m_hasher; - tmp.m_equal_to = src.m_equal_to; - tmp.m_size = src.size(); - tmp.m_available_indexes = bitset_type( src.capacity() ); - tmp.m_hash_lists = size_type_view( ViewAllocateWithoutInitializing("UnorderedMap hash list"), src.m_hash_lists.extent(0) ); - tmp.m_next_index = size_type_view( ViewAllocateWithoutInitializing("UnorderedMap next index"), src.m_next_index.extent(0) ); - tmp.m_keys = key_type_view( ViewAllocateWithoutInitializing("UnorderedMap keys"), src.m_keys.extent(0) ); - tmp.m_values = value_type_view( ViewAllocateWithoutInitializing("UnorderedMap values"), src.m_values.extent(0) ); - tmp.m_scalars = scalars_view("UnorderedMap scalars"); + tmp.m_bounded_insert = src.m_bounded_insert; + tmp.m_hasher = src.m_hasher; + tmp.m_equal_to = src.m_equal_to; + tmp.m_size = src.size(); + tmp.m_available_indexes = bitset_type(src.capacity()); + tmp.m_hash_lists = size_type_view( + ViewAllocateWithoutInitializing("UnorderedMap hash list"), + src.m_hash_lists.extent(0)); + tmp.m_next_index = size_type_view( + ViewAllocateWithoutInitializing("UnorderedMap next index"), + src.m_next_index.extent(0)); + tmp.m_keys = + key_type_view(ViewAllocateWithoutInitializing("UnorderedMap keys"), + src.m_keys.extent(0)); + tmp.m_values = value_type_view( + ViewAllocateWithoutInitializing("UnorderedMap values"), + src.m_values.extent(0)); + tmp.m_scalars = scalars_view("UnorderedMap scalars"); Kokkos::deep_copy(tmp.m_available_indexes, src.m_available_indexes); - typedef Kokkos::Impl::DeepCopy< typename device_type::memory_space, typename SDevice::memory_space > raw_deep_copy; + typedef Kokkos::Impl::DeepCopy + raw_deep_copy; - raw_deep_copy(tmp.m_hash_lists.data(), src.m_hash_lists.data(), sizeof(size_type)*src.m_hash_lists.extent(0)); - raw_deep_copy(tmp.m_next_index.data(), src.m_next_index.data(), sizeof(size_type)*src.m_next_index.extent(0)); - raw_deep_copy(tmp.m_keys.data(), src.m_keys.data(), sizeof(key_type)*src.m_keys.extent(0)); + raw_deep_copy(tmp.m_hash_lists.data(), src.m_hash_lists.data(), + sizeof(size_type) * src.m_hash_lists.extent(0)); + raw_deep_copy(tmp.m_next_index.data(), src.m_next_index.data(), + sizeof(size_type) * src.m_next_index.extent(0)); + raw_deep_copy(tmp.m_keys.data(), src.m_keys.data(), + sizeof(key_type) * src.m_keys.extent(0)); if (!is_set) { - raw_deep_copy(tmp.m_values.data(), src.m_values.data(), sizeof(impl_value_type)*src.m_values.extent(0)); + raw_deep_copy(tmp.m_values.data(), src.m_values.data(), + sizeof(impl_value_type) * src.m_values.extent(0)); } - raw_deep_copy(tmp.m_scalars.data(), src.m_scalars.data(), sizeof(int)*num_scalars ); + raw_deep_copy(tmp.m_scalars.data(), src.m_scalars.data(), + sizeof(int) * num_scalars); *this = tmp; } } //@} -private: // private member functions + private: // private member functions + bool modified() const { return get_flag(modified_idx); } - bool modified() const - { - return get_flag(modified_idx); - } - - void set_flag(int flag) const - { - typedef Kokkos::Impl::DeepCopy< typename device_type::memory_space, Kokkos::HostSpace > raw_deep_copy; + void set_flag(int flag) const { + typedef Kokkos::Impl::DeepCopy + raw_deep_copy; const int true_ = true; raw_deep_copy(m_scalars.data() + flag, &true_, sizeof(int)); } - void reset_flag(int flag) const - { - typedef Kokkos::Impl::DeepCopy< typename device_type::memory_space, Kokkos::HostSpace > raw_deep_copy; + void reset_flag(int flag) const { + typedef Kokkos::Impl::DeepCopy + raw_deep_copy; const int false_ = false; raw_deep_copy(m_scalars.data() + flag, &false_, sizeof(int)); } - bool get_flag(int flag) const - { - typedef Kokkos::Impl::DeepCopy< Kokkos::HostSpace, typename device_type::memory_space > raw_deep_copy; + bool get_flag(int flag) const { + typedef Kokkos::Impl::DeepCopy + raw_deep_copy; int result = false; raw_deep_copy(&result, m_scalars.data() + flag, sizeof(int)); return result; } - static uint32_t calculate_capacity(uint32_t capacity_hint) - { + static uint32_t calculate_capacity(uint32_t capacity_hint) { // increase by 16% and round to nears multiple of 128 - return capacity_hint ? ((static_cast(7ull*capacity_hint/6u) + 127u)/128u)*128u : 128u; + return capacity_hint + ? ((static_cast(7ull * capacity_hint / 6u) + 127u) / + 128u) * + 128u + : 128u; } -private: // private members - bool m_bounded_insert; - hasher_type m_hasher; - equal_to_type m_equal_to; + private: // private members + bool m_bounded_insert; + hasher_type m_hasher; + equal_to_type m_equal_to; mutable size_type m_size; - bitset_type m_available_indexes; - size_type_view m_hash_lists; - size_type_view m_next_index; - key_type_view m_keys; - value_type_view m_values; - scalars_view m_scalars; - - template + bitset_type m_available_indexes; + size_type_view m_hash_lists; + size_type_view m_next_index; + key_type_view m_keys; + value_type_view m_values; + scalars_view m_scalars; + + template friend class UnorderedMap; template @@ -834,17 +840,14 @@ private: // private members }; // Specialization of deep_copy for two UnorderedMap objects. -template < typename DKey, typename DT, typename DDevice - , typename SKey, typename ST, typename SDevice - , typename Hasher, typename EqualTo > -inline void deep_copy( UnorderedMap & dst - , const UnorderedMap & src ) -{ +template +inline void deep_copy( + UnorderedMap &dst, + const UnorderedMap &src) { dst.create_copy_view(src); } +} // namespace Kokkos -} // namespace Kokkos - -#endif //KOKKOS_UNORDERED_MAP_HPP - +#endif // KOKKOS_UNORDERED_MAP_HPP diff --git a/lib/kokkos/containers/src/Kokkos_Vector.hpp b/lib/kokkos/containers/src/Kokkos_Vector.hpp index a44d1f58b5..8962485abe 100644 --- a/lib/kokkos/containers/src/Kokkos_Vector.hpp +++ b/lib/kokkos/containers/src/Kokkos_Vector.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,15 +49,15 @@ #include /* Drop in replacement for std::vector based on Kokkos::DualView - * Most functions only work on the host (it will not compile if called from device kernel) + * Most functions only work on the host (it will not compile if called from + * device kernel) * */ - namespace Kokkos { +namespace Kokkos { -template< class Scalar, class Arg1Type = void> -class vector : public DualView { - -public: +template +class vector : public DualView { + public: typedef Scalar value_type; typedef Scalar* pointer; typedef const Scalar* const_pointer; @@ -64,213 +65,259 @@ public: typedef const Scalar& const_reference; typedef Scalar* iterator; typedef const Scalar* const_iterator; + typedef size_t size_type; -private: + private: size_t _size; - typedef size_t size_type; float _extra_storage; - typedef DualView DV; + typedef DualView DV; - -public: + public: #ifdef KOKKOS_ENABLE_CUDA_UVM - KOKKOS_INLINE_FUNCTION reference operator() (int i) const {return DV::h_view(i);}; - KOKKOS_INLINE_FUNCTION reference operator[] (int i) const {return DV::h_view(i);}; + KOKKOS_INLINE_FUNCTION reference operator()(int i) const { + return DV::h_view(i); + }; + KOKKOS_INLINE_FUNCTION reference operator[](int i) const { + return DV::h_view(i); + }; #else - inline reference operator() (int i) const {return DV::h_view(i);}; - inline reference operator[] (int i) const {return DV::h_view(i);}; + inline reference operator()(int i) const { return DV::h_view(i); }; + inline reference operator[](int i) const { return DV::h_view(i); }; #endif /* Member functions which behave like std::vector functions */ - vector():DV() { - _size = 0; + vector() : DV() { + _size = 0; _extra_storage = 1.1; } - - vector(int n, Scalar val=Scalar()):DualView("Vector",size_t(n*(1.1))) { - _size = n; - _extra_storage = 1.1; + vector(int n, Scalar val = Scalar()) + : DualView("Vector", size_t(n * (1.1))) { + _size = n; + _extra_storage = 1.1; DV::modified_flags(0) = 1; - assign(n,val); + assign(n, val); } - void resize(size_t n) { - if(n>=span()) - DV::resize(size_t (n*_extra_storage)); + if (n >= span()) DV::resize(size_t(n * _extra_storage)); _size = n; } - void resize(size_t n, const Scalar& val) { - assign(n,val); - } - - void assign (size_t n, const Scalar& val) { + void resize(size_t n, const Scalar& val) { assign(n, val); } - /* Resize if necessary (behavior of std:vector) */ + void assign(size_t n, const Scalar& val) { + /* Resize if necessary (behavour of std:vector) */ - if(n>span()) - DV::resize(size_t (n*_extra_storage)); + if (n > span()) DV::resize(size_t(n * _extra_storage)); _size = n; - /* Assign value either on host or on device */ + /* Assign value either on host or on device */ - if( DV::template need_sync() ) { - set_functor_host f(DV::h_view,val); - parallel_for(n,f); + if (DV::template need_sync()) { + set_functor_host f(DV::h_view, val); + parallel_for(n, f); typename DV::t_host::execution_space().fence(); DV::template modify(); } else { - set_functor f(DV::d_view,val); - parallel_for(n,f); + set_functor f(DV::d_view, val); + parallel_for(n, f); typename DV::t_dev::execution_space().fence(); DV::template modify(); } } - void reserve(size_t n) { - DV::resize(size_t (n*_extra_storage)); - } + void reserve(size_t n) { DV::resize(size_t(n * _extra_storage)); } void push_back(Scalar val) { DV::template sync(); DV::template modify(); - if(_size == span()) { - size_t new_size = _size*_extra_storage; - if(new_size == _size) new_size++; + if (_size == span()) { + size_t new_size = _size * _extra_storage; + if (new_size == _size) new_size++; DV::resize(new_size); } DV::h_view(_size) = val; _size++; + } + + void pop_back() { _size--; } + void clear() { _size = 0; } + + iterator insert(iterator it, const value_type& val) { + return insert(it, 1, val); } - void pop_back() { - _size--; + iterator insert(iterator it, size_type count, const value_type& val) { + if ((size() == 0) && (it == begin())) { + resize(count, val); + DV::sync_host(); + return begin(); + } + DV::sync_host(); + DV::modify_host(); + if (it < begin() || it > end()) + Kokkos::abort("Kokkos::vector::insert : invalid insert iterator"); + if (count == 0) return it; + ptrdiff_t start = std::distance(begin(), it); + auto org_size = size(); + resize(size() + count); + + std::copy_backward(begin() + start, begin() + org_size, + begin() + org_size + count); + std::fill_n(begin() + start, count, val); + + return begin() + start; } - void clear() { - _size = 0; + private: + template + struct impl_is_input_iterator + : /* TODO replace this */ std::integral_constant< + bool, !std::is_convertible::value> {}; + + public: + // TODO: can use detection idiom to generate better error message here later + template + typename std::enable_if::value, + iterator>::type + insert(iterator it, InputIterator b, InputIterator e) { + ptrdiff_t count = std::distance(b, e); + if (count == 0) return it; + + DV::sync_host(); + DV::modify_host(); + if (it < begin() || it > end()) + Kokkos::abort("Kokkos::vector::insert : invalid insert iterator"); + + bool resized = false; + if ((size() == 0) && (it == begin())) { + resize(count); + it = begin(); + resized = true; + } + ptrdiff_t start = std::distance(begin(), it); + auto org_size = size(); + if (!resized) resize(size() + count); + it = begin() + start; + + std::copy_backward(begin() + start, begin() + org_size, + begin() + org_size + count); + std::copy(b, e, it); + + return begin() + start; } - size_type size() const {return _size;} - size_type max_size() const {return 2000000000;} + size_type size() const { return _size; } + size_type max_size() const { return 2000000000; } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - size_type capacity() const {return DV::capacity();} + size_type capacity() const { return DV::capacity(); } #endif - size_type span() const {return DV::span();} - bool empty() const {return _size==0;} + size_type span() const { return DV::span(); } + bool empty() const { return _size == 0; } - iterator begin() const {return &DV::h_view(0);} + iterator begin() const { return DV::h_view.data(); } - iterator end() const {return &DV::h_view(_size);} + iterator end() const { + return _size > 0 ? DV::h_view.data() + _size : DV::h_view.data(); + } - reference front() {return DV::h_view(0);} + reference front() { return DV::h_view(0); } - reference back() {return DV::h_view(_size - 1);} + reference back() { return DV::h_view(_size - 1); } - const_reference front() const {return DV::h_view(0);} + const_reference front() const { return DV::h_view(0); } - const_reference back() const {return DV::h_view(_size - 1);} + const_reference back() const { return DV::h_view(_size - 1); } - /* std::algorithms which work originally with iterators, here they are implemented as member functions */ + /* std::algorithms wich work originally with iterators, here they are + * implemented as member functions */ - size_t - lower_bound (const size_t& start, - const size_t& theEnd, - const Scalar& comp_val) const - { - int lower = start; // FIXME (mfh 24 Apr 2014) narrowing conversion - int upper = _size > theEnd? theEnd : _size-1; // FIXME (mfh 24 Apr 2014) narrowing conversion + size_t lower_bound(const size_t& start, const size_t& theEnd, + const Scalar& comp_val) const { + int lower = start; // FIXME (mfh 24 Apr 2014) narrowing conversion + int upper = + _size > theEnd + ? theEnd + : _size - 1; // FIXME (mfh 24 Apr 2014) narrowing conversion if (upper <= lower) { return theEnd; } Scalar lower_val = DV::h_view(lower); Scalar upper_val = DV::h_view(upper); - size_t idx = (upper+lower)/2; - Scalar val = DV::h_view(idx); - if(val>upper_val) return upper; - if(val upper_val) return upper; + if (val < lower_val) return start; - while(upper>lower) { - if(comp_val>val) { + while (upper > lower) { + if (comp_val > val) { lower = ++idx; } else { upper = idx; } - idx = (upper+lower)/2; + idx = (upper + lower) / 2; val = DV::h_view(idx); } return idx; } bool is_sorted() { - for(int i=0;i<_size-1;i++) { - if(DV::h_view(i)>DV::h_view(i+1)) return false; + for (int i = 0; i < _size - 1; i++) { + if (DV::h_view(i) > DV::h_view(i + 1)) return false; } return true; } iterator find(Scalar val) const { - if(_size == 0) return end(); + if (_size == 0) return end(); - int upper,lower,current; - current = _size/2; - upper = _size-1; - lower = 0; + int upper, lower, current; + current = _size / 2; + upper = _size - 1; + lower = 0; - if((valDV::h_view(_size-1)) ) return end(); + if ((val < DV::h_view(0)) || (val > DV::h_view(_size - 1))) return end(); - while(upper>lower) - { - if(val>DV::h_view(current)) lower = current+1; - else upper = current; - current = (upper+lower)/2; + while (upper > lower) { + if (val > DV::h_view(current)) + lower = current + 1; + else + upper = current; + current = (upper + lower) / 2; } - if(val==DV::h_view(current)) return &DV::h_view(current); - else return end(); + if (val == DV::h_view(current)) + return &DV::h_view(current); + else + return end(); } /* Additional functions for data management */ - void device_to_host(){ - deep_copy(DV::h_view,DV::d_view); - } - void host_to_device() const { - deep_copy(DV::d_view,DV::h_view); - } - - void on_host() { - DV::template modify(); - } - void on_device() { - DV::template modify(); - } + void device_to_host() { deep_copy(DV::h_view, DV::d_view); } + void host_to_device() const { deep_copy(DV::d_view, DV::h_view); } - void set_overallocation(float extra) { - _extra_storage = 1.0 + extra; - } + void on_host() { DV::template modify(); } + void on_device() { DV::template modify(); } + void set_overallocation(float extra) { _extra_storage = 1.0 + extra; } -public: + public: struct set_functor { typedef typename DV::t_dev::execution_space execution_space; typename DV::t_dev _data; Scalar _val; - set_functor(typename DV::t_dev data, Scalar val) : - _data(data),_val(val) {} + set_functor(typename DV::t_dev data, Scalar val) : _data(data), _val(val) {} KOKKOS_INLINE_FUNCTION - void operator() (const int &i) const { - _data(i) = _val; - } + void operator()(const int& i) const { _data(i) = _val; } }; struct set_functor_host { @@ -278,18 +325,13 @@ public: typename DV::t_host _data; Scalar _val; - set_functor_host(typename DV::t_host data, Scalar val) : - _data(data),_val(val) {} + set_functor_host(typename DV::t_host data, Scalar val) + : _data(data), _val(val) {} KOKKOS_INLINE_FUNCTION - void operator() (const int &i) const { - _data(i) = _val; - } + void operator()(const int& i) const { _data(i) = _val; } }; - }; - -} +} // namespace Kokkos #endif - diff --git a/lib/kokkos/containers/src/impl/Kokkos_Bitset_impl.hpp b/lib/kokkos/containers/src/impl/Kokkos_Bitset_impl.hpp index 7ea2e102ce..f5fa4d518a 100644 --- a/lib/kokkos/containers/src/impl/Kokkos_Bitset_impl.hpp +++ b/lib/kokkos/containers/src/impl/Kokkos_Bitset_impl.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -57,53 +58,44 @@ namespace Kokkos { namespace Impl { KOKKOS_FORCEINLINE_FUNCTION -unsigned rotate_right( unsigned i, int r ) -{ - enum { size = static_cast( sizeof(unsigned) * CHAR_BIT ) }; - return r ? ( ( i >> r ) | ( i << ( size - r ) ) ) : i ; +unsigned rotate_right(unsigned i, int r) { + enum { size = static_cast(sizeof(unsigned) * CHAR_BIT) }; + return r ? ((i >> r) | (i << (size - r))) : i; } -template < typename Bitset > -struct BitsetCount -{ - typedef Bitset bitset_type; - typedef typename bitset_type::execution_space::execution_space execution_space; - typedef typename bitset_type::size_type size_type; - typedef size_type value_type; +template +struct BitsetCount { + typedef Bitset bitset_type; + typedef + typename bitset_type::execution_space::execution_space execution_space; + typedef typename bitset_type::size_type size_type; + typedef size_type value_type; bitset_type m_bitset; - BitsetCount( bitset_type const& bitset ) - : m_bitset(bitset) - {} + BitsetCount(bitset_type const& bitset) : m_bitset(bitset) {} - size_type apply() const - { + size_type apply() const { size_type count = 0u; - parallel_reduce( m_bitset.m_blocks.extent(0), *this, count ); + parallel_reduce(m_bitset.m_blocks.extent(0), *this, count); return count; } KOKKOS_INLINE_FUNCTION - void init( value_type & count ) const - { - count = 0u; - } + void init(value_type& count) const { count = 0u; } KOKKOS_INLINE_FUNCTION - void join( volatile value_type & count, const volatile size_type & incr ) const - { + void join(volatile value_type& count, const volatile size_type& incr) const { count += incr; } KOKKOS_INLINE_FUNCTION - void operator()( size_type i, value_type & count ) const - { - count += bit_count( m_bitset.m_blocks[i] ); + void operator()(size_type i, value_type& count) const { + count += bit_count(m_bitset.m_blocks[i]); } }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos -#endif // KOKKOS_BITSET_IMPL_HPP +#endif // KOKKOS_BITSET_IMPL_HPP diff --git a/lib/kokkos/containers/src/impl/Kokkos_Functional_impl.hpp b/lib/kokkos/containers/src/impl/Kokkos_Functional_impl.hpp index 8b17dcce4b..6ba67766aa 100644 --- a/lib/kokkos/containers/src/impl/Kokkos_Functional_impl.hpp +++ b/lib/kokkos/containers/src/impl/Kokkos_Functional_impl.hpp @@ -1,10 +1,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -22,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,28 +46,24 @@ #include #include -namespace Kokkos { namespace Impl { +namespace Kokkos { +namespace Impl { // MurmurHash3 was written by Austin Appleby, and is placed in the public // domain. The author hereby disclaims copyright to this source code. KOKKOS_FORCEINLINE_FUNCTION -uint32_t getblock32 ( const uint8_t * p, int i ) -{ -// used to avoid aliasing error which could cause errors with -// forced inlining - return ((uint32_t)p[i*4+0]) - | ((uint32_t)p[i*4+1] << 8) - | ((uint32_t)p[i*4+2] << 16) - | ((uint32_t)p[i*4+3] << 24); +uint32_t getblock32(const uint8_t* p, int i) { + // used to avoid aliasing error which could cause errors with + // forced inlining + return ((uint32_t)p[i * 4 + 0]) | ((uint32_t)p[i * 4 + 1] << 8) | + ((uint32_t)p[i * 4 + 2] << 16) | ((uint32_t)p[i * 4 + 3] << 24); } KOKKOS_FORCEINLINE_FUNCTION -uint32_t rotl32 ( uint32_t x, int8_t r ) -{ return (x << r) | (x >> (32 - r)); } +uint32_t rotl32(uint32_t x, int8_t r) { return (x << r) | (x >> (32 - r)); } KOKKOS_FORCEINLINE_FUNCTION -uint32_t fmix32 ( uint32_t h ) -{ +uint32_t fmix32(uint32_t h) { h ^= h >> 16; h *= 0x85ebca6b; h ^= h >> 13; @@ -77,10 +74,9 @@ uint32_t fmix32 ( uint32_t h ) } KOKKOS_INLINE_FUNCTION -uint32_t MurmurHash3_x86_32 ( const void * key, int len, uint32_t seed ) -{ - const uint8_t * data = (const uint8_t*)key; - const int nblocks = len / 4; +uint32_t MurmurHash3_x86_32(const void* key, int len, uint32_t seed) { + const uint8_t* data = (const uint8_t*)key; + const int nblocks = len / 4; uint32_t h1 = seed; @@ -90,32 +86,34 @@ uint32_t MurmurHash3_x86_32 ( const void * key, int len, uint32_t seed ) //---------- // body - for(int i=0; i -KOKKOS_FORCEINLINE_FUNCTION -bool bitwise_equal(T const * const a_ptr, T const * const b_ptr) -{ +KOKKOS_FORCEINLINE_FUNCTION bool bitwise_equal(T const* const a_ptr, + T const* const b_ptr) { typedef uint64_t KOKKOS_IMPL_MAY_ALIAS T64; typedef uint32_t KOKKOS_IMPL_MAY_ALIAS T32; typedef uint16_t KOKKOS_IMPL_MAY_ALIAS T16; - typedef uint8_t KOKKOS_IMPL_MAY_ALIAS T8; + typedef uint8_t KOKKOS_IMPL_MAY_ALIAS T8; enum { NUM_8 = sizeof(T), @@ -158,39 +153,37 @@ bool bitwise_equal(T const * const a_ptr, T const * const b_ptr) }; union { - T const * const ptr; - T64 const * const ptr64; - T32 const * const ptr32; - T16 const * const ptr16; - T8 const * const ptr8; + T const* const ptr; + T64 const* const ptr64; + T32 const* const ptr32; + T16 const* const ptr16; + T8 const* const ptr8; } a = {a_ptr}, b = {b_ptr}; bool result = true; - for (int i=0; i < NUM_64; ++i) { + for (int i = 0; i < NUM_64; ++i) { result = result && a.ptr64[i] == b.ptr64[i]; } - if ( NUM_64*2 < NUM_32 ) { - result = result && a.ptr32[NUM_64*2] == b.ptr32[NUM_64*2]; + if (NUM_64 * 2 < NUM_32) { + result = result && a.ptr32[NUM_64 * 2] == b.ptr32[NUM_64 * 2]; } - if ( NUM_32*2 < NUM_16 ) { - result = result && a.ptr16[NUM_32*2] == b.ptr16[NUM_32*2]; + if (NUM_32 * 2 < NUM_16) { + result = result && a.ptr16[NUM_32 * 2] == b.ptr16[NUM_32 * 2]; } - if ( NUM_16*2 < NUM_8 ) { - result = result && a.ptr8[NUM_16*2] == b.ptr8[NUM_16*2]; + if (NUM_16 * 2 < NUM_8) { + result = result && a.ptr8[NUM_16 * 2] == b.ptr8[NUM_16 * 2]; } return result; } - - #undef KOKKOS_IMPL_MAY_ALIAS -}} // namespace Kokkos::Impl - -#endif //KOKKOS_FUNCTIONAL_IMPL_HPP +} // namespace Impl +} // namespace Kokkos +#endif // KOKKOS_FUNCTIONAL_IMPL_HPP diff --git a/lib/kokkos/containers/src/impl/Kokkos_StaticCrsGraph_factory.hpp b/lib/kokkos/containers/src/impl/Kokkos_StaticCrsGraph_factory.hpp index 743c345b45..d644c57c0a 100644 --- a/lib/kokkos/containers/src/impl/Kokkos_StaticCrsGraph_factory.hpp +++ b/lib/kokkos/containers/src/impl/Kokkos_StaticCrsGraph_factory.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -50,193 +51,207 @@ namespace Kokkos { #ifdef KOKKOS_ENABLE_DEPRECATED_CODE -template< class DataType , class Arg1Type , class Arg2Type , typename SizeType , class Arg3Type> -inline -typename StaticCrsGraph< DataType , Arg1Type , Arg2Type , SizeType , Arg3Type >::HostMirror -create_mirror_view( const StaticCrsGraph & view , - typename Impl::enable_if< ViewTraits::is_hostspace >::type * = 0 ) -{ - return view ; +template +inline typename StaticCrsGraph::HostMirror +create_mirror_view( + const StaticCrsGraph& + view, + typename Impl::enable_if::is_hostspace>::type* = 0) { + return view; } #else -template< class DataType , class Arg1Type , class Arg2Type , class Arg3Type, typename SizeType > -inline -typename StaticCrsGraph< DataType , Arg1Type , Arg2Type , Arg3Type , SizeType >::HostMirror -create_mirror_view( const StaticCrsGraph & view , - typename Impl::enable_if< ViewTraits::is_hostspace >::type * = 0 ) -{ - return view ; +template +inline typename StaticCrsGraph::HostMirror +create_mirror_view( + const StaticCrsGraph& + view, + typename Impl::enable_if::is_hostspace>::type* = 0) { + return view; } #endif #ifdef KOKKOS_ENABLE_DEPRECATED_CODE -template< class DataType , class Arg1Type , class Arg2Type , typename SizeType , class Arg3Type> -inline -typename StaticCrsGraph< DataType , Arg1Type , Arg2Type , SizeType , Arg3Type >::HostMirror -create_mirror( const StaticCrsGraph & view ) -{ +template +inline typename StaticCrsGraph::HostMirror +create_mirror(const StaticCrsGraph& view) { // Force copy: - //typedef Impl::ViewAssignment< Impl::ViewDefault > alloc ; // unused - typedef StaticCrsGraph< DataType , Arg1Type , Arg2Type , SizeType , Arg3Type > staticcrsgraph_type ; + // typedef Impl::ViewAssignment< Impl::ViewDefault > alloc ; // unused + typedef StaticCrsGraph + staticcrsgraph_type; #else -template< class DataType , class Arg1Type , class Arg2Type , class Arg3Type, typename SizeType > -inline -typename StaticCrsGraph< DataType , Arg1Type , Arg2Type , Arg3Type , SizeType >::HostMirror -create_mirror( const StaticCrsGraph & view ) -{ +template +inline typename StaticCrsGraph::HostMirror +create_mirror(const StaticCrsGraph& view) { // Force copy: - //typedef Impl::ViewAssignment< Impl::ViewDefault > alloc ; // unused - typedef StaticCrsGraph< DataType , Arg1Type , Arg2Type , Arg3Type , SizeType > staticcrsgraph_type ; + // typedef Impl::ViewAssignment< Impl::ViewDefault > alloc ; // unused + typedef StaticCrsGraph + staticcrsgraph_type; #endif - typename staticcrsgraph_type::HostMirror tmp ; - typename staticcrsgraph_type::row_map_type::HostMirror tmp_row_map = create_mirror( view.row_map); - typename staticcrsgraph_type::row_block_type::HostMirror tmp_row_block_offsets = create_mirror( view.row_block_offsets); + typename staticcrsgraph_type::HostMirror tmp; + typename staticcrsgraph_type::row_map_type::HostMirror tmp_row_map = + create_mirror(view.row_map); + typename staticcrsgraph_type::row_block_type::HostMirror + tmp_row_block_offsets = create_mirror(view.row_block_offsets); // Allocation to match: - tmp.row_map = tmp_row_map ; // Assignment of 'const' from 'non-const' - tmp.entries = create_mirror( view.entries ); - tmp.row_block_offsets = tmp_row_block_offsets ; // Assignment of 'const' from 'non-const' + tmp.row_map = tmp_row_map; // Assignment of 'const' from 'non-const' + tmp.entries = create_mirror(view.entries); + tmp.row_block_offsets = + tmp_row_block_offsets; // Assignment of 'const' from 'non-const' // Deep copy: - deep_copy( tmp_row_map , view.row_map ); - deep_copy( tmp.entries , view.entries ); - deep_copy( tmp_row_block_offsets , view.row_block_offsets ); + deep_copy(tmp_row_map, view.row_map); + deep_copy(tmp.entries, view.entries); + deep_copy(tmp_row_block_offsets, view.row_block_offsets); - return tmp ; + return tmp; } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE -template< class DataType , class Arg1Type , class Arg2Type , typename SizeType , class Arg3Type> -inline -typename StaticCrsGraph< DataType , Arg1Type , Arg2Type , SizeType , Arg3Type >::HostMirror -create_mirror_view( const StaticCrsGraph & view , - typename Impl::enable_if< ! ViewTraits::is_hostspace >::type * = 0 ) +template +inline typename StaticCrsGraph::HostMirror +create_mirror_view( + const StaticCrsGraph& + view, + typename Impl::enable_if::is_hostspace>::type* = 0) #else -template< class DataType , class Arg1Type , class Arg2Type , class Arg3Type, typename SizeType > -inline -typename StaticCrsGraph< DataType , Arg1Type , Arg2Type , Arg3Type , SizeType >::HostMirror -create_mirror_view( const StaticCrsGraph & view , - typename Impl::enable_if< ! ViewTraits::is_hostspace >::type * = 0 ) +template +inline typename StaticCrsGraph::HostMirror +create_mirror_view( + const StaticCrsGraph& + view, + typename Impl::enable_if::is_hostspace>::type* = 0) #endif { - return create_mirror( view ); + return create_mirror(view); } -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- namespace Kokkos { -template< class StaticCrsGraphType , class InputSizeType > -inline -typename StaticCrsGraphType::staticcrsgraph_type -create_staticcrsgraph( const std::string & label , - const std::vector< InputSizeType > & input ) -{ - typedef StaticCrsGraphType output_type ; - //typedef std::vector< InputSizeType > input_type ; // unused +template +inline typename StaticCrsGraphType::staticcrsgraph_type create_staticcrsgraph( + const std::string& label, const std::vector& input) { + typedef StaticCrsGraphType output_type; + // typedef std::vector< InputSizeType > input_type ; // unused - typedef typename output_type::entries_type entries_type ; + typedef typename output_type::entries_type entries_type; - typedef View< typename output_type::size_type [] , - typename output_type::array_layout , - typename output_type::execution_space, - typename output_type::memory_traits > work_type ; + typedef View + work_type; - output_type output ; + output_type output; // Create the row map: const size_t length = input.size(); { - work_type row_work( "tmp" , length + 1 ); + work_type row_work("tmp", length + 1); - typename work_type::HostMirror row_work_host = - create_mirror_view( row_work ); + typename work_type::HostMirror row_work_host = create_mirror_view(row_work); - size_t sum = 0 ; - row_work_host[0] = 0 ; - for ( size_t i = 0 ; i < length ; ++i ) { - row_work_host[i+1] = sum += input[i]; + size_t sum = 0; + row_work_host[0] = 0; + for (size_t i = 0; i < length; ++i) { + row_work_host[i + 1] = sum += input[i]; } - deep_copy( row_work , row_work_host ); + deep_copy(row_work, row_work_host); - output.entries = entries_type( label , sum ); - output.row_map = row_work ; + output.entries = entries_type(label, sum); + output.row_map = row_work; } - return output ; + return output; } //---------------------------------------------------------------------------- -template< class StaticCrsGraphType , class InputSizeType > -inline -typename StaticCrsGraphType::staticcrsgraph_type -create_staticcrsgraph( const std::string & label , - const std::vector< std::vector< InputSizeType > > & input ) -{ - typedef StaticCrsGraphType output_type ; - typedef typename output_type::entries_type entries_type ; +template +inline typename StaticCrsGraphType::staticcrsgraph_type create_staticcrsgraph( + const std::string& label, + const std::vector >& input) { + typedef StaticCrsGraphType output_type; + typedef typename output_type::entries_type entries_type; - static_assert( entries_type::rank == 1 - , "Graph entries view must be rank one" ); + static_assert(entries_type::rank == 1, "Graph entries view must be rank one"); - typedef View< typename output_type::size_type [] , - typename output_type::array_layout , - typename output_type::execution_space, - typename output_type::memory_traits > work_type ; + typedef View + work_type; - output_type output ; + output_type output; - // Create the row map: + // Create the row map: const size_t length = input.size(); { - work_type row_work( "tmp" , length + 1 ); + work_type row_work("tmp", length + 1); - typename work_type::HostMirror row_work_host = - create_mirror_view( row_work ); + typename work_type::HostMirror row_work_host = create_mirror_view(row_work); - size_t sum = 0 ; - row_work_host[0] = 0 ; - for ( size_t i = 0 ; i < length ; ++i ) { - row_work_host[i+1] = sum += input[i].size(); + size_t sum = 0; + row_work_host[0] = 0; + for (size_t i = 0; i < length; ++i) { + row_work_host[i + 1] = sum += input[i].size(); } - deep_copy( row_work , row_work_host ); + deep_copy(row_work, row_work_host); - output.entries = entries_type( label , sum ); - output.row_map = row_work ; + output.entries = entries_type(label, sum); + output.row_map = row_work; } // Fill in the entries: { typename entries_type::HostMirror host_entries = - create_mirror_view( output.entries ); + create_mirror_view(output.entries); - size_t sum = 0 ; - for ( size_t i = 0 ; i < length ; ++i ) { - for ( size_t j = 0 ; j < input[i].size() ; ++j , ++sum ) { - host_entries( sum ) = input[i][j] ; + size_t sum = 0; + for (size_t i = 0; i < length; ++i) { + for (size_t j = 0; j < input[i].size(); ++j, ++sum) { + host_entries(sum) = input[i][j]; } } - deep_copy( output.entries , host_entries ); + deep_copy(output.entries, host_entries); } - return output ; + return output; } -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- #endif /* #ifndef KOKKOS_IMPL_CRSARRAY_FACTORY_HPP */ - diff --git a/lib/kokkos/containers/src/impl/Kokkos_UnorderedMap_impl.cpp b/lib/kokkos/containers/src/impl/Kokkos_UnorderedMap_impl.cpp index 88ca200daf..e10e256b6a 100644 --- a/lib/kokkos/containers/src/impl/Kokkos_UnorderedMap_impl.cpp +++ b/lib/kokkos/containers/src/impl/Kokkos_UnorderedMap_impl.cpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,58 +37,62 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ #include -namespace Kokkos { namespace Impl { +namespace Kokkos { +namespace Impl { -uint32_t find_hash_size(uint32_t size) -{ +uint32_t find_hash_size(uint32_t size) { if (size == 0u) return 0u; // these primes try to preserve randomness of hash - static const uint32_t primes [] = { - 3, 7, 13, 23, 53, 97, 193, 389, 769, 1543 - , 2237, 2423, 2617, 2797, 2999, 3167, 3359, 3539 - , 3727, 3911, 4441 , 4787 , 5119 , 5471 , 5801 , 6143 , 6521 , 6827 - , 7177 , 7517 , 7853 , 8887 , 9587 , 10243 , 10937 , 11617 , 12289 - , 12967 , 13649 , 14341 , 15013 , 15727 - , 17749 , 19121 , 20479 , 21859 , 23209 , 24593 , 25939 , 27329 - , 28669 , 30047 , 31469 , 35507 , 38231 , 40961 , 43711 , 46439 - , 49157 , 51893 , 54617 , 57347 , 60077 , 62801 , 70583 , 75619 - , 80669 , 85703 , 90749 , 95783 , 100823 , 105871 , 110909 , 115963 - , 120997 , 126031 , 141157 , 151237 , 161323 , 171401 , 181499 , 191579 - , 201653 , 211741 , 221813 , 231893 , 241979 , 252079 - , 282311 , 302483 , 322649 , 342803 , 362969 , 383143 , 403301 , 423457 - , 443629 , 463787 , 483953 , 504121 , 564617 , 604949 , 645313 , 685609 - , 725939 , 766273 , 806609 , 846931 , 887261 , 927587 , 967919 , 1008239 - , 1123477 , 1198397 , 1273289 , 1348177 , 1423067 , 1497983 , 1572869 - , 1647761 , 1722667 , 1797581 , 1872461 , 1947359 , 2022253 - , 2246953 , 2396759 , 2546543 , 2696363 , 2846161 , 2995973 , 3145739 - , 3295541 , 3445357 , 3595117 , 3744941 , 3894707 , 4044503 - , 4493921 , 4793501 , 5093089 , 5392679 , 5692279 , 5991883 , 6291469 - , 6591059 , 6890641 , 7190243 , 7489829 , 7789447 , 8089033 - , 8987807 , 9586981 , 10186177 , 10785371 , 11384539 , 11983729 - , 12582917 , 13182109 , 13781291 , 14380469 , 14979667 , 15578861 - , 16178053 , 17895707 , 19014187 , 20132683 , 21251141 , 22369661 - , 23488103 , 24606583 , 25725083 , 26843549 , 27962027 , 29080529 - , 30198989 , 31317469 , 32435981 , 35791397 , 38028379 , 40265327 - , 42502283 , 44739259 , 46976221 , 49213237 , 51450131 , 53687099 - , 55924061 , 58161041 , 60397993 , 62634959 , 64871921 - , 71582857 , 76056727 , 80530643 , 85004567 , 89478503 , 93952427 - , 98426347 , 102900263 , 107374217 , 111848111 , 116322053 , 120795971 - , 125269877 , 129743807 , 143165587 , 152113427 , 161061283 , 170009141 - , 178956983 , 187904819 , 196852693 , 205800547 , 214748383 , 223696237 - , 232644089 , 241591943 , 250539763 , 259487603 , 268435399 - }; + static const uint32_t primes[] = { + 3, 7, 13, 23, 53, 97, + 193, 389, 769, 1543, 2237, 2423, + 2617, 2797, 2999, 3167, 3359, 3539, + 3727, 3911, 4441, 4787, 5119, 5471, + 5801, 6143, 6521, 6827, 7177, 7517, + 7853, 8887, 9587, 10243, 10937, 11617, + 12289, 12967, 13649, 14341, 15013, 15727, + 17749, 19121, 20479, 21859, 23209, 24593, + 25939, 27329, 28669, 30047, 31469, 35507, + 38231, 40961, 43711, 46439, 49157, 51893, + 54617, 57347, 60077, 62801, 70583, 75619, + 80669, 85703, 90749, 95783, 100823, 105871, + 110909, 115963, 120997, 126031, 141157, 151237, + 161323, 171401, 181499, 191579, 201653, 211741, + 221813, 231893, 241979, 252079, 282311, 302483, + 322649, 342803, 362969, 383143, 403301, 423457, + 443629, 463787, 483953, 504121, 564617, 604949, + 645313, 685609, 725939, 766273, 806609, 846931, + 887261, 927587, 967919, 1008239, 1123477, 1198397, + 1273289, 1348177, 1423067, 1497983, 1572869, 1647761, + 1722667, 1797581, 1872461, 1947359, 2022253, 2246953, + 2396759, 2546543, 2696363, 2846161, 2995973, 3145739, + 3295541, 3445357, 3595117, 3744941, 3894707, 4044503, + 4493921, 4793501, 5093089, 5392679, 5692279, 5991883, + 6291469, 6591059, 6890641, 7190243, 7489829, 7789447, + 8089033, 8987807, 9586981, 10186177, 10785371, 11384539, + 11983729, 12582917, 13182109, 13781291, 14380469, 14979667, + 15578861, 16178053, 17895707, 19014187, 20132683, 21251141, + 22369661, 23488103, 24606583, 25725083, 26843549, 27962027, + 29080529, 30198989, 31317469, 32435981, 35791397, 38028379, + 40265327, 42502283, 44739259, 46976221, 49213237, 51450131, + 53687099, 55924061, 58161041, 60397993, 62634959, 64871921, + 71582857, 76056727, 80530643, 85004567, 89478503, 93952427, + 98426347, 102900263, 107374217, 111848111, 116322053, 120795971, + 125269877, 129743807, 143165587, 152113427, 161061283, 170009141, + 178956983, 187904819, 196852693, 205800547, 214748383, 223696237, + 232644089, 241591943, 250539763, 259487603, 268435399}; - const uint32_t num_primes = sizeof(primes)/sizeof(uint32_t); + const uint32_t num_primes = sizeof(primes) / sizeof(uint32_t); - uint32_t hsize = primes[num_primes-1] ; + uint32_t hsize = primes[num_primes - 1]; for (uint32_t i = 0; i < num_primes; ++i) { if (size <= primes[i]) { hsize = primes[i]; @@ -97,5 +102,5 @@ uint32_t find_hash_size(uint32_t size) return hsize; } -}} // namespace Kokkos::Impl - +} // namespace Impl +} // namespace Kokkos diff --git a/lib/kokkos/containers/src/impl/Kokkos_UnorderedMap_impl.hpp b/lib/kokkos/containers/src/impl/Kokkos_UnorderedMap_impl.hpp index f97c1fc046..55e76c424d 100644 --- a/lib/kokkos/containers/src/impl/Kokkos_UnorderedMap_impl.hpp +++ b/lib/kokkos/containers/src/impl/Kokkos_UnorderedMap_impl.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -52,42 +53,34 @@ #include #include -namespace Kokkos { namespace Impl { +namespace Kokkos { +namespace Impl { -uint32_t find_hash_size( uint32_t size ); +uint32_t find_hash_size(uint32_t size); template -struct UnorderedMapRehash -{ +struct UnorderedMapRehash { typedef Map map_type; typedef typename map_type::const_map_type const_map_type; typedef typename map_type::execution_space execution_space; typedef typename map_type::size_type size_type; - map_type m_dst; + map_type m_dst; const_map_type m_src; - UnorderedMapRehash( map_type const& dst, const_map_type const& src) - : m_dst(dst), m_src(src) - {} + UnorderedMapRehash(map_type const& dst, const_map_type const& src) + : m_dst(dst), m_src(src) {} - void apply() const - { - parallel_for(m_src.capacity(), *this); - } + void apply() const { parallel_for(m_src.capacity(), *this); } KOKKOS_INLINE_FUNCTION - void operator()(size_type i) const - { - if ( m_src.valid_at(i) ) - m_dst.insert(m_src.key_at(i), m_src.value_at(i)); + void operator()(size_type i) const { + if (m_src.valid_at(i)) m_dst.insert(m_src.key_at(i), m_src.value_at(i)); } - }; template -struct UnorderedMapErase -{ +struct UnorderedMapErase { typedef UMap map_type; typedef typename map_type::execution_space execution_space; typedef typename map_type::size_type size_type; @@ -96,18 +89,12 @@ struct UnorderedMapErase map_type m_map; - UnorderedMapErase( map_type const& map) - : m_map(map) - {} + UnorderedMapErase(map_type const& map) : m_map(map) {} - void apply() const - { - parallel_for(m_map.m_hash_lists.extent(0), *this); - } + void apply() const { parallel_for(m_map.m_hash_lists.extent(0), *this); } KOKKOS_INLINE_FUNCTION - void operator()( size_type i ) const - { + void operator()(size_type i) const { const size_type invalid_index = map_type::invalid_index; size_type curr = m_map.m_hash_lists(i); @@ -115,29 +102,28 @@ struct UnorderedMapErase // remove erased head of the linked-list while (curr != invalid_index && !m_map.valid_at(curr)) { - next = m_map.m_next_index[curr]; + next = m_map.m_next_index[curr]; m_map.m_next_index[curr] = invalid_index; - m_map.m_keys[curr] = key_type(); + m_map.m_keys[curr] = key_type(); if (m_map.is_set) m_map.m_values[curr] = value_type(); - curr = next; + curr = next; m_map.m_hash_lists(i) = next; } // if the list is non-empty and the head is valid - if (curr != invalid_index && m_map.valid_at(curr) ) { + if (curr != invalid_index && m_map.valid_at(curr)) { size_type prev = curr; - curr = m_map.m_next_index[prev]; + curr = m_map.m_next_index[prev]; while (curr != invalid_index) { next = m_map.m_next_index[curr]; if (m_map.valid_at(curr)) { prev = curr; - } - else { + } else { // remove curr from list m_map.m_next_index[prev] = next; m_map.m_next_index[curr] = invalid_index; - m_map.m_keys[curr] = key_type(); + m_map.m_keys[curr] = key_type(); if (map_type::is_set) m_map.m_values[curr] = value_type(); } curr = next; @@ -147,8 +133,7 @@ struct UnorderedMapErase }; template -struct UnorderedMapHistogram -{ +struct UnorderedMapHistogram { typedef UMap map_type; typedef typename map_type::execution_space execution_space; typedef typename map_type::size_type size_type; @@ -161,117 +146,100 @@ struct UnorderedMapHistogram histogram_view m_distance; histogram_view m_block_distance; - UnorderedMapHistogram( map_type const& map) - : m_map(map) - , m_length("UnorderedMap Histogram") - , m_distance("UnorderedMap Histogram") - , m_block_distance("UnorderedMap Histogram") - {} + UnorderedMapHistogram(map_type const& map) + : m_map(map), + m_length("UnorderedMap Histogram"), + m_distance("UnorderedMap Histogram"), + m_block_distance("UnorderedMap Histogram") {} - void calculate() - { - parallel_for(m_map.m_hash_lists.extent(0), *this); - } + void calculate() { parallel_for(m_map.m_hash_lists.extent(0), *this); } - void clear() - { + void clear() { Kokkos::deep_copy(m_length, 0); Kokkos::deep_copy(m_distance, 0); Kokkos::deep_copy(m_block_distance, 0); } - void print_length(std::ostream &out) - { + void print_length(std::ostream& out) { host_histogram_view host_copy = create_mirror_view(m_length); Kokkos::deep_copy(host_copy, m_length); - for (int i=0, size = host_copy.extent(0); i -struct UnorderedMapPrint -{ +struct UnorderedMapPrint { typedef UMap map_type; typedef typename map_type::execution_space execution_space; typedef typename map_type::size_type size_type; map_type m_map; - UnorderedMapPrint( map_type const& map) - : m_map(map) - {} + UnorderedMapPrint(map_type const& map) : m_map(map) {} - void apply() - { - parallel_for(m_map.m_hash_lists.extent(0), *this); - } + void apply() { parallel_for(m_map.m_hash_lists.extent(0), *this); } KOKKOS_INLINE_FUNCTION - void operator()( size_type i ) const - { + void operator()(size_type i) const { const size_type invalid_index = map_type::invalid_index; uint32_t list = m_map.m_hash_lists(i); - for (size_type curr = list, ii=0; curr != invalid_index; curr = m_map.m_next_index[curr], ++ii) { - printf("%d[%d]: %d->%d\n", list, ii, m_map.key_at(curr), m_map.value_at(curr)); + for (size_type curr = list, ii = 0; curr != invalid_index; + curr = m_map.m_next_index[curr], ++ii) { + printf("%d[%d]: %d->%d\n", list, ii, m_map.key_at(curr), + m_map.value_at(curr)); } } }; @@ -280,19 +248,20 @@ template struct UnorderedMapCanAssign : public false_ {}; template -struct UnorderedMapCanAssign : public true_ {}; +struct UnorderedMapCanAssign : public true_ {}; template -struct UnorderedMapCanAssign : public true_ {}; +struct UnorderedMapCanAssign : public true_ {}; template -struct UnorderedMapCanAssign : public true_ {}; +struct UnorderedMapCanAssign + : public true_ {}; template -struct UnorderedMapCanAssign : public true_ {}; - - -}} //Kokkos::Impl +struct UnorderedMapCanAssign + : public true_ {}; -#endif // KOKKOS_UNORDERED_MAP_IMPL_HPP +} // namespace Impl +} // namespace Kokkos +#endif // KOKKOS_UNORDERED_MAP_IMPL_HPP diff --git a/lib/kokkos/containers/unit_tests/CMakeLists.txt b/lib/kokkos/containers/unit_tests/CMakeLists.txt index 8564bd9ddd..a83ab1293c 100644 --- a/lib/kokkos/containers/unit_tests/CMakeLists.txt +++ b/lib/kokkos/containers/unit_tests/CMakeLists.txt @@ -1,138 +1,35 @@ -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) -INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${CMAKE_CURRENT_SOURCE_DIR}) -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../src ) - -IF(NOT KOKKOS_HAS_TRILINOS) - IF(KOKKOS_SEPARATE_LIBS) - set(TEST_LINK_TARGETS kokkoscore) - ELSE() - set(TEST_LINK_TARGETS kokkos) - ENDIF() -ENDIF() - -IF(Kokkos_ENABLE_Pthread) -TRIBITS_ADD_EXECUTABLE_AND_TEST( - UnitTest_Threads - SOURCES - UnitTestMain.cpp - threads/TestThreads_BitSet.cpp - threads/TestThreads_DualView.cpp - threads/TestThreads_DynamicView.cpp - threads/TestThreads_DynRankViewAPI_generic.cpp - threads/TestThreads_DynRankViewAPI_rank12345.cpp - threads/TestThreads_DynRankViewAPI_rank67.cpp - threads/TestThreads_ErrorReporter.cpp - threads/TestThreads_OffsetView.cpp - threads/TestThreads_ScatterView.cpp - threads/TestThreads_StaticCrsGraph.cpp - threads/TestThreads_UnorderedMap.cpp - threads/TestThreads_Vector.cpp - threads/TestThreads_ViewCtorPropEmbeddedDim.cpp - COMM serial mpi - NUM_MPI_PROCS 1 - FAIL_REGULAR_EXPRESSION " FAILED " - TESTONLYLIBS kokkos_gtest ${TEST_LINK_TARGETS} - ) -ENDIF() - -IF(Kokkos_ENABLE_Serial) -TRIBITS_ADD_EXECUTABLE_AND_TEST( - UnitTest_Serial - SOURCES - UnitTestMain.cpp - serial/TestSerial_BitSet.cpp - serial/TestSerial_DualView.cpp - serial/TestSerial_DynamicView.cpp - serial/TestSerial_DynRankViewAPI_generic.cpp - serial/TestSerial_DynRankViewAPI_rank12345.cpp - serial/TestSerial_DynRankViewAPI_rank67.cpp - serial/TestSerial_ErrorReporter.cpp - serial/TestSerial_OffsetView.cpp - serial/TestSerial_ScatterView.cpp - serial/TestSerial_StaticCrsGraph.cpp - serial/TestSerial_UnorderedMap.cpp - serial/TestSerial_Vector.cpp - serial/TestSerial_ViewCtorPropEmbeddedDim.cpp - COMM serial mpi - NUM_MPI_PROCS 1 - FAIL_REGULAR_EXPRESSION " FAILED " - TESTONLYLIBS kokkos_gtest ${TEST_LINK_TARGETS} - ) -ENDIF() - -IF(Kokkos_ENABLE_OpenMP) -TRIBITS_ADD_EXECUTABLE_AND_TEST( - UnitTest_OpenMP - SOURCES - UnitTestMain.cpp - openmp/TestOpenMP_BitSet.cpp - openmp/TestOpenMP_DualView.cpp - openmp/TestOpenMP_DynamicView.cpp - openmp/TestOpenMP_DynRankViewAPI_generic.cpp - openmp/TestOpenMP_DynRankViewAPI_rank12345.cpp - openmp/TestOpenMP_DynRankViewAPI_rank67.cpp - openmp/TestOpenMP_ErrorReporter.cpp - openmp/TestOpenMP_OffsetView.cpp - openmp/TestOpenMP_ScatterView.cpp - openmp/TestOpenMP_StaticCrsGraph.cpp - openmp/TestOpenMP_UnorderedMap.cpp - openmp/TestOpenMP_Vector.cpp - openmp/TestOpenMP_ViewCtorPropEmbeddedDim.cpp - COMM serial mpi - NUM_MPI_PROCS 1 - FAIL_REGULAR_EXPRESSION " FAILED " - TESTONLYLIBS kokkos_gtest ${TEST_LINK_TARGETS} - ) -ENDIF() - -IF(Kokkos_ENABLE_HPX) -TRIBITS_ADD_EXECUTABLE_AND_TEST( - UnitTest_HPX - SOURCES - UnitTestMain.cpp - hpx/TestHPX_BitSet.cpp - hpx/TestHPX_DualView.cpp - hpx/TestHPX_DynamicView.cpp - hpx/TestHPX_DynRankViewAPI_generic.cpp - hpx/TestHPX_DynRankViewAPI_rank12345.cpp - hpx/TestHPX_DynRankViewAPI_rank67.cpp - hpx/TestHPX_ErrorReporter.cpp - hpx/TestHPX_OffsetView.cpp - hpx/TestHPX_ScatterView.cpp - hpx/TestHPX_StaticCrsGraph.cpp - hpx/TestHPX_UnorderedMap.cpp - hpx/TestHPX_Vector.cpp - hpx/TestHPX_ViewCtorPropEmbeddedDim.cpp - COMM serial mpi - NUM_MPI_PROCS 1 - FAIL_REGULAR_EXPRESSION " FAILED " - TESTONLYLIBS kokkos_gtest ${TEST_LINK_TARGETS} - ) -ENDIF() - -IF(Kokkos_ENABLE_Cuda) -TRIBITS_ADD_EXECUTABLE_AND_TEST( - UnitTest_Cuda - SOURCES - UnitTestMain.cpp - cuda/TestCuda_BitSet.cpp - cuda/TestCuda_DualView.cpp - cuda/TestCuda_DynamicView.cpp - cuda/TestCuda_DynRankViewAPI_generic.cpp - cuda/TestCuda_DynRankViewAPI_rank12345.cpp - cuda/TestCuda_DynRankViewAPI_rank67.cpp - cuda/TestCuda_ErrorReporter.cpp - cuda/TestCuda_OffsetView.cpp - cuda/TestCuda_ScatterView.cpp - cuda/TestCuda_StaticCrsGraph.cpp - cuda/TestCuda_UnorderedMap.cpp - cuda/TestCuda_Vector.cpp - cuda/TestCuda_ViewCtorPropEmbeddedDim.cpp - COMM serial mpi - NUM_MPI_PROCS 1 - FAIL_REGULAR_EXPRESSION " FAILED " - TESTONLYLIBS kokkos_gtest ${TEST_LINK_TARGETS} - ) -ENDIF() - +KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +KOKKOS_INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${CMAKE_CURRENT_SOURCE_DIR}) +KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../src ) + +foreach(Tag Threads;Serial;OpenMP;HPX;Cuda) + # Because there is always an exception to the rule + if(Tag STREQUAL "Threads") + set(DEVICE "PTHREAD") + else() + string(TOUPPER ${Tag} DEVICE) + endif() + string(TOLOWER ${Tag} dir) + # Add test for that backend if it is enabled + if(Kokkos_ENABLE_${DEVICE}) + KOKKOS_ADD_EXECUTABLE_AND_TEST( + UnitTest_${Tag} + SOURCES + UnitTestMain.cpp + ${dir}/Test${Tag}_BitSet.cpp + ${dir}/Test${Tag}_DualView.cpp + ${dir}/Test${Tag}_DynamicView.cpp + ${dir}/Test${Tag}_DynRankViewAPI_generic.cpp + ${dir}/Test${Tag}_DynRankViewAPI_rank12345.cpp + ${dir}/Test${Tag}_DynRankViewAPI_rank67.cpp + ${dir}/Test${Tag}_ErrorReporter.cpp + ${dir}/Test${Tag}_OffsetView.cpp + ${dir}/Test${Tag}_ScatterView.cpp + ${dir}/Test${Tag}_StaticCrsGraph.cpp + ${dir}/Test${Tag}_UnorderedMap.cpp + ${dir}/Test${Tag}_Vector.cpp + ${dir}/Test${Tag}_ViewCtorPropEmbeddedDim.cpp + ) + endif() +endforeach() diff --git a/lib/kokkos/containers/unit_tests/TestBitset.hpp b/lib/kokkos/containers/unit_tests/TestBitset.hpp index 55d0e8b938..70528880a4 100644 --- a/lib/kokkos/containers/unit_tests/TestBitset.hpp +++ b/lib/kokkos/containers/unit_tests/TestBitset.hpp @@ -1,12 +1,13 @@ //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -22,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -35,7 +36,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER @@ -52,240 +53,208 @@ namespace Test { namespace Impl { template -struct TestBitset -{ +struct TestBitset { typedef Bitset bitset_type; typedef typename bitset_type::execution_space execution_space; typedef uint32_t value_type; bitset_type m_bitset; - TestBitset( bitset_type const& bitset) - : m_bitset(bitset) - {} + TestBitset(bitset_type const& bitset) : m_bitset(bitset) {} - unsigned testit(unsigned collisions) - { + unsigned testit(unsigned collisions) { execution_space().fence(); unsigned count = 0; - Kokkos::parallel_reduce( m_bitset.size()*collisions, *this, count); + Kokkos::parallel_reduce(m_bitset.size() * collisions, *this, count); return count; } - KOKKOS_INLINE_FUNCTION - void init( value_type & v ) const { v = 0; } + void init(value_type& v) const { v = 0; } KOKKOS_INLINE_FUNCTION - void join( volatile value_type & dst, const volatile value_type & src ) const - { dst += src; } + void join(volatile value_type& dst, const volatile value_type& src) const { + dst += src; + } KOKKOS_INLINE_FUNCTION - void operator()(uint32_t i, value_type & v) const - { + void operator()(uint32_t i, value_type& v) const { i = i % m_bitset.size(); if (Set) { if (m_bitset.set(i)) { if (m_bitset.test(i)) ++v; } - } - else { + } else { if (m_bitset.reset(i)) { if (!m_bitset.test(i)) ++v; } } } - }; template -struct TestBitsetTest -{ +struct TestBitsetTest { typedef Bitset bitset_type; typedef typename bitset_type::execution_space execution_space; typedef uint32_t value_type; bitset_type m_bitset; - TestBitsetTest( bitset_type const& bitset) - : m_bitset(bitset) - {} + TestBitsetTest(bitset_type const& bitset) : m_bitset(bitset) {} - unsigned testit() - { + unsigned testit() { execution_space().fence(); unsigned count = 0; - Kokkos::parallel_reduce( m_bitset.size(), *this, count); + Kokkos::parallel_reduce(m_bitset.size(), *this, count); return count; } - KOKKOS_INLINE_FUNCTION - void init( value_type & v ) const { v = 0; } + void init(value_type& v) const { v = 0; } KOKKOS_INLINE_FUNCTION - void join( volatile value_type & dst, const volatile value_type & src ) const - { dst += src; } + void join(volatile value_type& dst, const volatile value_type& src) const { + dst += src; + } KOKKOS_INLINE_FUNCTION - void operator()(uint32_t i, value_type & v) const - { - if (m_bitset.test( i )) ++v; + void operator()(uint32_t i, value_type& v) const { + if (m_bitset.test(i)) ++v; } }; template -struct TestBitsetAny -{ +struct TestBitsetAny { typedef Bitset bitset_type; typedef typename bitset_type::execution_space execution_space; typedef uint32_t value_type; bitset_type m_bitset; - TestBitsetAny( bitset_type const& bitset) - : m_bitset(bitset) - {} + TestBitsetAny(bitset_type const& bitset) : m_bitset(bitset) {} - unsigned testit() - { + unsigned testit() { execution_space().fence(); unsigned count = 0; - Kokkos::parallel_reduce( m_bitset.size(), *this, count); + Kokkos::parallel_reduce(m_bitset.size(), *this, count); return count; } - KOKKOS_INLINE_FUNCTION - void init( value_type & v ) const { v = 0; } + void init(value_type& v) const { v = 0; } KOKKOS_INLINE_FUNCTION - void join( volatile value_type & dst, const volatile value_type & src ) const - { dst += src; } + void join(volatile value_type& dst, const volatile value_type& src) const { + dst += src; + } KOKKOS_INLINE_FUNCTION - void operator()(uint32_t i, value_type & v) const - { - bool result = false; + void operator()(uint32_t i, value_type& v) const { + bool result = false; unsigned attempts = 0; - uint32_t hint = (i >> 4) << 4; + uint32_t hint = (i >> 4) << 4; while (attempts < m_bitset.max_hint()) { if (Set) { Kokkos::tie(result, hint) = m_bitset.find_any_unset_near(hint, i); if (result && m_bitset.set(hint)) { ++v; break; - } - else if (!result) { + } else if (!result) { ++attempts; } - } - else { + } else { Kokkos::tie(result, hint) = m_bitset.find_any_set_near(hint, i); if (result && m_bitset.reset(hint)) { ++v; break; - } - else if (!result) { + } else if (!result) { ++attempts; } } } } - }; -} // namespace Impl - - +} // namespace Impl template -void test_bitset() -{ - typedef Kokkos::Bitset< Device > bitset_type; - typedef Kokkos::ConstBitset< Device > const_bitset_type; +void test_bitset() { + typedef Kokkos::Bitset bitset_type; + typedef Kokkos::ConstBitset const_bitset_type; - //unsigned test_sizes[] = { 0u, 1000u, 1u<<14, 1u<<16, 10000001 }; - unsigned test_sizes[] = { 1000u, 1u<<14, 1u<<16, 10000001 }; + // unsigned test_sizes[] = { 0u, 1000u, 1u<<14, 1u<<16, 10000001 }; + unsigned test_sizes[] = {1000u, 1u << 14, 1u << 16, 10000001}; - for (int i=0, end = sizeof(test_sizes)/sizeof(unsigned); i f(bitset); + Impl::TestBitsetTest f(bitset); uint32_t count = f.testit(); EXPECT_EQ(0u, count); EXPECT_EQ(count, bitset.count()); } - //std::cout << " Check set() " << std::endl; + // std::cout << " Check set() " << std::endl; bitset.set(); // everything should be set { - Impl::TestBitsetTest< const_bitset_type > f(bitset); + Impl::TestBitsetTest f(bitset); uint32_t count = f.testit(); EXPECT_EQ(bitset.size(), count); EXPECT_EQ(count, bitset.count()); } - //std::cout << " Check reset() " << std::endl; + // std::cout << " Check reset() " << std::endl; bitset.reset(); EXPECT_EQ(0u, bitset.count()); - //std::cout << " Check set(i) " << std::endl; + // std::cout << " Check set(i) " << std::endl; // test setting bits { - Impl::TestBitset< bitset_type, true > f(bitset); + Impl::TestBitset f(bitset); uint32_t count = f.testit(10u); - EXPECT_EQ( bitset.size(), bitset.count()); - EXPECT_EQ( bitset.size(), count ); + EXPECT_EQ(bitset.size(), bitset.count()); + EXPECT_EQ(bitset.size(), count); } - //std::cout << " Check reset(i) " << std::endl; + // std::cout << " Check reset(i) " << std::endl; // test resetting bits { - Impl::TestBitset< bitset_type, false > f(bitset); + Impl::TestBitset f(bitset); uint32_t count = f.testit(10u); - EXPECT_EQ( bitset.size(), count); - EXPECT_EQ( 0u, bitset.count() ); + EXPECT_EQ(bitset.size(), count); + EXPECT_EQ(0u, bitset.count()); } - - //std::cout << " Check find_any_set(i) " << std::endl; + // std::cout << " Check find_any_set(i) " << std::endl; // test setting any bits { - Impl::TestBitsetAny< bitset_type, true > f(bitset); + Impl::TestBitsetAny f(bitset); uint32_t count = f.testit(); - EXPECT_EQ( bitset.size(), bitset.count()); - EXPECT_EQ( bitset.size(), count ); + EXPECT_EQ(bitset.size(), bitset.count()); + EXPECT_EQ(bitset.size(), count); } - //std::cout << " Check find_any_unset(i) " << std::endl; + // std::cout << " Check find_any_unset(i) " << std::endl; // test resetting any bits { - Impl::TestBitsetAny< bitset_type, false > f(bitset); + Impl::TestBitsetAny f(bitset); uint32_t count = f.testit(); - EXPECT_EQ( bitset.size(), count); - EXPECT_EQ( 0u, bitset.count() ); + EXPECT_EQ(bitset.size(), count); + EXPECT_EQ(0u, bitset.count()); } - } - -} - -TEST_F( TEST_CATEGORY, bitset ) -{ - test_bitset(); } -} // namespace Test +TEST(TEST_CATEGORY, bitset) { test_bitset(); } -#endif //KOKKOS_TEST_BITSET_HPP +} // namespace Test +#endif // KOKKOS_TEST_BITSET_HPP diff --git a/lib/kokkos/containers/unit_tests/TestDualView.hpp b/lib/kokkos/containers/unit_tests/TestDualView.hpp index 767f93c093..572ef48839 100644 --- a/lib/kokkos/containers/unit_tests/TestDualView.hpp +++ b/lib/kokkos/containers/unit_tests/TestDualView.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -55,169 +56,159 @@ namespace Test { namespace Impl { - template - struct test_dualview_combinations - { - typedef test_dualview_combinations self_type; +template +struct test_dualview_combinations { + typedef test_dualview_combinations self_type; - typedef Scalar scalar_type; - typedef Device execution_space; + typedef Scalar scalar_type; + typedef Device execution_space; - Scalar reference; - Scalar result; + Scalar reference; + Scalar result; - template - Scalar run_me(unsigned int n,unsigned int m){ - if(n<10) n = 10; - if(m<3) m = 3; - ViewType a("A",n,m); + template + Scalar run_me(unsigned int n, unsigned int m) { + if (n < 10) n = 10; + if (m < 3) m = 3; + ViewType a("A", n, m); - Kokkos::deep_copy( a.d_view , 1 ); + Kokkos::deep_copy(a.d_view, 1); - a.template modify(); - a.template sync(); + a.template modify(); + a.template sync(); - a.h_view(5,1) = 3; - a.h_view(6,1) = 4; - a.h_view(7,2) = 5; - a.template modify(); - ViewType b = Kokkos::subview(a,std::pair(6,9),std::pair(0,1)); - a.template sync(); - b.template modify(); + a.h_view(5, 1) = 3; + a.h_view(6, 1) = 4; + a.h_view(7, 2) = 5; + a.template modify(); + ViewType b = Kokkos::subview(a, std::pair(6, 9), + std::pair(0, 1)); + a.template sync(); + b.template modify(); - Kokkos::deep_copy( b.d_view , 2 ); + Kokkos::deep_copy(b.d_view, 2); - a.template sync(); - Scalar count = 0; - for(unsigned int i = 0; i >(size,3); - } + a.template sync(); + Scalar count = 0; + for (unsigned int i = 0; i < a.d_view.extent(0); i++) + for (unsigned int j = 0; j < a.d_view.extent(1); j++) + count += a.h_view(i, j); + return count - a.d_view.extent(0) * a.d_view.extent(1) - 2 - 4 - 3 * 2; + } - }; + test_dualview_combinations(unsigned int size) { + result = run_me >( + size, 3); + } +}; - template < typename Scalar, class ViewType > - struct SumViewEntriesFunctor { +template +struct SumViewEntriesFunctor { + typedef Scalar value_type; - typedef Scalar value_type; + ViewType fv; - ViewType fv; + SumViewEntriesFunctor(const ViewType& fv_) : fv(fv_) {} - SumViewEntriesFunctor ( const ViewType & fv_ ) : fv(fv_) {} - - KOKKOS_INLINE_FUNCTION - void operator() ( const int i , value_type & total ) const { - for ( size_t j = 0; j < fv.extent(1); ++j ) { - total += fv(i,j); - } + KOKKOS_INLINE_FUNCTION + void operator()(const int i, value_type& total) const { + for (size_t j = 0; j < fv.extent(1); ++j) { + total += fv(i, j); } + } +}; + +template +struct test_dual_view_deep_copy { + typedef Scalar scalar_type; + typedef Device execution_space; + + template + void run_me() { + const unsigned int n = 10; + const unsigned int m = 5; + const unsigned int sum_total = n * m; + + ViewType a("A", n, m); + ViewType b("B", n, m); + + Kokkos::deep_copy(a.d_view, 1); + + a.template modify(); + a.template sync(); + + // Check device view is initialized as expected + scalar_type a_d_sum = 0; + // Execute on the execution_space associated with t_dev's memory space + typedef typename ViewType::t_dev::memory_space::execution_space + t_dev_exec_space; + Kokkos::parallel_reduce( + Kokkos::RangePolicy(0, n), + SumViewEntriesFunctor(a.d_view), + a_d_sum); + ASSERT_EQ(a_d_sum, sum_total); + + // Check host view is synced as expected + scalar_type a_h_sum = 0; + for (size_t i = 0; i < a.h_view.extent(0); ++i) + for (size_t j = 0; j < a.h_view.extent(1); ++j) { + a_h_sum += a.h_view(i, j); + } - }; - - - template - struct test_dual_view_deep_copy - { - typedef Scalar scalar_type; - typedef Device execution_space; - - template - void run_me() { - - const unsigned int n = 10; - const unsigned int m = 5; - const unsigned int sum_total = n * m; - - ViewType a("A",n,m); - ViewType b("B",n,m); - - Kokkos::deep_copy( a.d_view , 1 ); - - a.template modify(); - a.template sync(); - - // Check device view is initialized as expected - scalar_type a_d_sum = 0; - // Execute on the execution_space associated with t_dev's memory space - typedef typename ViewType::t_dev::memory_space::execution_space t_dev_exec_space; - Kokkos::parallel_reduce( Kokkos::RangePolicy(0,n), SumViewEntriesFunctor(a.d_view), a_d_sum ); - ASSERT_EQ(a_d_sum, sum_total); - - // Check host view is synced as expected - scalar_type a_h_sum = 0; - for ( size_t i = 0; i < a.h_view.extent(0); ++i ) - for ( size_t j = 0; j < a.h_view.extent(1); ++j ) { - a_h_sum += a.h_view(i,j); - } - - ASSERT_EQ(a_h_sum, sum_total); - - - // Test deep_copy - Kokkos::deep_copy( b, a ); - b.template sync(); - - // Perform same checks on b as done on a - // Check device view is initialized as expected - scalar_type b_d_sum = 0; - // Execute on the execution_space associated with t_dev's memory space - Kokkos::parallel_reduce( Kokkos::RangePolicy(0,n), SumViewEntriesFunctor(b.d_view), b_d_sum ); - ASSERT_EQ(b_d_sum, sum_total); - - // Check host view is synced as expected - scalar_type b_h_sum = 0; - for ( size_t i = 0; i < b.h_view.extent(0); ++i ) - for ( size_t j = 0; j < b.h_view.extent(1); ++j ) { - b_h_sum += b.h_view(i,j); - } - - ASSERT_EQ(b_h_sum, sum_total); - - } // end run_me - - test_dual_view_deep_copy() - { - run_me< Kokkos::DualView >(); - } + ASSERT_EQ(a_h_sum, sum_total); + + // Test deep_copy + Kokkos::deep_copy(b, a); + b.template sync(); + + // Perform same checks on b as done on a + // Check device view is initialized as expected + scalar_type b_d_sum = 0; + // Execute on the execution_space associated with t_dev's memory space + Kokkos::parallel_reduce( + Kokkos::RangePolicy(0, n), + SumViewEntriesFunctor(b.d_view), + b_d_sum); + ASSERT_EQ(b_d_sum, sum_total); + + // Check host view is synced as expected + scalar_type b_h_sum = 0; + for (size_t i = 0; i < b.h_view.extent(0); ++i) + for (size_t j = 0; j < b.h_view.extent(1); ++j) { + b_h_sum += b.h_view(i, j); + } - }; + ASSERT_EQ(b_h_sum, sum_total); -} // namespace Impl + } // end run_me + test_dual_view_deep_copy() { + run_me >(); + } +}; +} // namespace Impl template -void test_dualview_combinations(unsigned int size) -{ - Impl::test_dualview_combinations test(size); - ASSERT_EQ( test.result,0); - +void test_dualview_combinations(unsigned int size) { + Impl::test_dualview_combinations test(size); + ASSERT_EQ(test.result, 0); } template -void test_dualview_deep_copy() -{ - Impl::test_dual_view_deep_copy (); +void test_dualview_deep_copy() { + Impl::test_dual_view_deep_copy(); } -TEST_F( TEST_CATEGORY, dualview_combination) { - test_dualview_combinations(10); +TEST(TEST_CATEGORY, dualview_combination) { + test_dualview_combinations(10); } -TEST_F( TEST_CATEGORY, dualview_deep_copy) { - test_dualview_deep_copy(); - test_dualview_deep_copy(); +TEST(TEST_CATEGORY, dualview_deep_copy) { + test_dualview_deep_copy(); + test_dualview_deep_copy(); } +} // namespace Test -} // namespace Test - -#endif //KOKKOS_TEST_UNORDERED_MAP_HPP - +#endif // KOKKOS_TEST_UNORDERED_MAP_HPP diff --git a/lib/kokkos/containers/unit_tests/TestDynViewAPI.hpp b/lib/kokkos/containers/unit_tests/TestDynViewAPI.hpp index 13e56c9f8d..3692aa8a12 100644 --- a/lib/kokkos/containers/unit_tests/TestDynViewAPI.hpp +++ b/lib/kokkos/containers/unit_tests/TestDynViewAPI.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -51,680 +52,661 @@ /*--------------------------------------------------------------------------*/ - /*--------------------------------------------------------------------------*/ namespace Test { -template< class T , class ... P > -size_t allocation_count( const Kokkos::DynRankView & view ) -{ +template +size_t allocation_count(const Kokkos::DynRankView& view) { const size_t card = view.size(); const size_t alloc = view.span(); - return card <= alloc ? alloc : 0 ; + return card <= alloc ? alloc : 0; } /*--------------------------------------------------------------------------*/ -template< typename T, class DeviceType> -struct TestViewOperator -{ - typedef DeviceType execution_space ; +template +struct TestViewOperator { + typedef DeviceType execution_space; - static const unsigned N = 100 ; - static const unsigned D = 3 ; + static const unsigned N = 100; + static const unsigned D = 3; - typedef Kokkos::DynRankView< T , execution_space > view_type ; + typedef Kokkos::DynRankView view_type; - const view_type v1 ; - const view_type v2 ; + const view_type v1; + const view_type v2; - TestViewOperator() - : v1( "v1" , N , D ) - , v2( "v2" , N , D ) - {} + TestViewOperator() : v1("v1", N, D), v2("v2", N, D) {} - static void testit() - { - Kokkos::parallel_for( N , TestViewOperator() ); - } + static void testit() { Kokkos::parallel_for(N, TestViewOperator()); } KOKKOS_INLINE_FUNCTION - void operator()( const unsigned i ) const - { - const unsigned X = 0 ; - const unsigned Y = 1 ; - const unsigned Z = 2 ; - - v2(i,X) = v1(i,X); - v2(i,Y) = v1(i,Y); - v2(i,Z) = v1(i,Z); + void operator()(const unsigned i) const { + const unsigned X = 0; + const unsigned Y = 1; + const unsigned Z = 2; + + v2(i, X) = v1(i, X); + v2(i, Y) = v1(i, Y); + v2(i, Z) = v1(i, Z); } }; /*--------------------------------------------------------------------------*/ -template< class DataType , - class DeviceType , - unsigned Rank > -struct TestViewOperator_LeftAndRight ; +template +struct TestViewOperator_LeftAndRight; -template< class DataType , class DeviceType > -struct TestViewOperator_LeftAndRight< DataType , DeviceType , 7 > -{ - typedef DeviceType execution_space ; - typedef typename execution_space::memory_space memory_space ; - typedef typename execution_space::size_type size_type ; +template +struct TestViewOperator_LeftAndRight { + typedef DeviceType execution_space; + typedef typename execution_space::memory_space memory_space; + typedef typename execution_space::size_type size_type; - typedef int value_type ; + typedef int value_type; KOKKOS_INLINE_FUNCTION - static void join( volatile value_type & update , - const volatile value_type & input ) - { update |= input ; } + static void join(volatile value_type& update, + const volatile value_type& input) { + update |= input; + } KOKKOS_INLINE_FUNCTION - static void init( value_type & update ) - { update = 0 ; } + static void init(value_type& update) { update = 0; } + typedef Kokkos::DynRankView + left_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutLeft, execution_space > left_view ; + typedef Kokkos::DynRankView + right_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutRight, execution_space > right_view ; + left_view left; + right_view right; + long left_alloc; + long right_alloc; - left_view left ; - right_view right ; - long left_alloc ; - long right_alloc ; + TestViewOperator_LeftAndRight(unsigned N0, unsigned N1, unsigned N2, + unsigned N3, unsigned N4, unsigned N5, + unsigned N6) + : left("left", N0, N1, N2, N3, N4, N5, N6), + right("right", N0, N1, N2, N3, N4, N5, N6), + left_alloc(allocation_count(left)), + right_alloc(allocation_count(right)) {} - TestViewOperator_LeftAndRight(unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4, unsigned N5, unsigned N6 ) - : left( "left" , N0, N1, N2, N3, N4, N5, N6 ) - , right( "right" , N0, N1, N2, N3, N4, N5, N6 ) - , left_alloc( allocation_count( left ) ) - , right_alloc( allocation_count( right ) ) - {} + static void testit(unsigned N0, unsigned N1, unsigned N2, unsigned N3, + unsigned N4, unsigned N5, unsigned N6) { + TestViewOperator_LeftAndRight driver(N0, N1, N2, N3, N4, N5, N6); - static void testit(unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4, unsigned N5, unsigned N6 ) - { - TestViewOperator_LeftAndRight driver(N0, N1, N2, N3, N4, N5, N6 ); + int error_flag = 0; - int error_flag = 0 ; + Kokkos::parallel_reduce(1, driver, error_flag); - Kokkos::parallel_reduce( 1 , driver , error_flag ); - - ASSERT_EQ( error_flag , 0 ); + ASSERT_EQ(error_flag, 0); } KOKKOS_INLINE_FUNCTION - void operator()( const size_type , value_type & update ) const - { - long offset ; - - offset = -1 ; - for ( unsigned i6 = 0 ; i6 < unsigned(left.extent(6)) ; ++i6 ) - for ( unsigned i5 = 0 ; i5 < unsigned(left.extent(5)) ; ++i5 ) - for ( unsigned i4 = 0 ; i4 < unsigned(left.extent(4)) ; ++i4 ) - for ( unsigned i3 = 0 ; i3 < unsigned(left.extent(3)) ; ++i3 ) - for ( unsigned i2 = 0 ; i2 < unsigned(left.extent(2)) ; ++i2 ) - for ( unsigned i1 = 0 ; i1 < unsigned(left.extent(1)) ; ++i1 ) - for ( unsigned i0 = 0 ; i0 < unsigned(left.extent(0)) ; ++i0 ) - { - const long j = & left( i0, i1, i2, i3, i4, i5, i6 ) - - & left( 0, 0, 0, 0, 0, 0, 0 ); - if ( j <= offset || left_alloc <= j ) { update |= 1 ; } - offset = j ; - } - - offset = -1 ; - for ( unsigned i0 = 0 ; i0 < unsigned(right.extent(0)) ; ++i0 ) - for ( unsigned i1 = 0 ; i1 < unsigned(right.extent(1)) ; ++i1 ) - for ( unsigned i2 = 0 ; i2 < unsigned(right.extent(2)) ; ++i2 ) - for ( unsigned i3 = 0 ; i3 < unsigned(right.extent(3)) ; ++i3 ) - for ( unsigned i4 = 0 ; i4 < unsigned(right.extent(4)) ; ++i4 ) - for ( unsigned i5 = 0 ; i5 < unsigned(right.extent(5)) ; ++i5 ) - for ( unsigned i6 = 0 ; i6 < unsigned(right.extent(6)) ; ++i6 ) - { - const long j = & right( i0, i1, i2, i3, i4, i5, i6 ) - - & right( 0, 0, 0, 0, 0, 0, 0 ); - if ( j <= offset || right_alloc <= j ) { update |= 2 ; } - offset = j ; - } + void operator()(const size_type, value_type& update) const { + long offset; + + offset = -1; + for (unsigned i6 = 0; i6 < unsigned(left.extent(6)); ++i6) + for (unsigned i5 = 0; i5 < unsigned(left.extent(5)); ++i5) + for (unsigned i4 = 0; i4 < unsigned(left.extent(4)); ++i4) + for (unsigned i3 = 0; i3 < unsigned(left.extent(3)); ++i3) + for (unsigned i2 = 0; i2 < unsigned(left.extent(2)); ++i2) + for (unsigned i1 = 0; i1 < unsigned(left.extent(1)); ++i1) + for (unsigned i0 = 0; i0 < unsigned(left.extent(0)); ++i0) { + const long j = &left(i0, i1, i2, i3, i4, i5, i6) - + &left(0, 0, 0, 0, 0, 0, 0); + if (j <= offset || left_alloc <= j) { + update |= 1; + } + offset = j; + } + + offset = -1; + for (unsigned i0 = 0; i0 < unsigned(right.extent(0)); ++i0) + for (unsigned i1 = 0; i1 < unsigned(right.extent(1)); ++i1) + for (unsigned i2 = 0; i2 < unsigned(right.extent(2)); ++i2) + for (unsigned i3 = 0; i3 < unsigned(right.extent(3)); ++i3) + for (unsigned i4 = 0; i4 < unsigned(right.extent(4)); ++i4) + for (unsigned i5 = 0; i5 < unsigned(right.extent(5)); ++i5) + for (unsigned i6 = 0; i6 < unsigned(right.extent(6)); ++i6) { + const long j = &right(i0, i1, i2, i3, i4, i5, i6) - + &right(0, 0, 0, 0, 0, 0, 0); + if (j <= offset || right_alloc <= j) { + update |= 2; + } + offset = j; + } } }; -template< class DataType , class DeviceType > -struct TestViewOperator_LeftAndRight< DataType , DeviceType , 6 > -{ - typedef DeviceType execution_space ; - typedef typename execution_space::memory_space memory_space ; - typedef typename execution_space::size_type size_type ; +template +struct TestViewOperator_LeftAndRight { + typedef DeviceType execution_space; + typedef typename execution_space::memory_space memory_space; + typedef typename execution_space::size_type size_type; - typedef int value_type ; + typedef int value_type; KOKKOS_INLINE_FUNCTION - static void join( volatile value_type & update , - const volatile value_type & input ) - { update |= input ; } + static void join(volatile value_type& update, + const volatile value_type& input) { + update |= input; + } KOKKOS_INLINE_FUNCTION - static void init( value_type & update ) - { update = 0 ; } + static void init(value_type& update) { update = 0; } + typedef Kokkos::DynRankView + left_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutLeft, execution_space > left_view ; + typedef Kokkos::DynRankView + right_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutRight, execution_space > right_view ; + left_view left; + right_view right; + long left_alloc; + long right_alloc; - left_view left ; - right_view right ; - long left_alloc ; - long right_alloc ; + TestViewOperator_LeftAndRight(unsigned N0, unsigned N1, unsigned N2, + unsigned N3, unsigned N4, unsigned N5) + : left("left", N0, N1, N2, N3, N4, N5), + right("right", N0, N1, N2, N3, N4, N5), + left_alloc(allocation_count(left)), + right_alloc(allocation_count(right)) {} - TestViewOperator_LeftAndRight(unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4, unsigned N5 ) - : left( "left" , N0, N1, N2, N3, N4, N5 ) - , right( "right" , N0, N1, N2, N3, N4, N5 ) - , left_alloc( allocation_count( left ) ) - , right_alloc( allocation_count( right ) ) - {} + static void testit(unsigned N0, unsigned N1, unsigned N2, unsigned N3, + unsigned N4, unsigned N5) { + TestViewOperator_LeftAndRight driver(N0, N1, N2, N3, N4, N5); - static void testit(unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4, unsigned N5) - { - TestViewOperator_LeftAndRight driver (N0, N1, N2, N3, N4, N5); + int error_flag = 0; - int error_flag = 0 ; + Kokkos::parallel_reduce(1, driver, error_flag); - Kokkos::parallel_reduce( 1 , driver , error_flag ); - - ASSERT_EQ( error_flag , 0 ); + ASSERT_EQ(error_flag, 0); } KOKKOS_INLINE_FUNCTION - void operator()( const size_type , value_type & update ) const - { - long offset ; - - offset = -1 ; - for ( unsigned i5 = 0 ; i5 < unsigned(left.extent(5)) ; ++i5 ) - for ( unsigned i4 = 0 ; i4 < unsigned(left.extent(4)) ; ++i4 ) - for ( unsigned i3 = 0 ; i3 < unsigned(left.extent(3)) ; ++i3 ) - for ( unsigned i2 = 0 ; i2 < unsigned(left.extent(2)) ; ++i2 ) - for ( unsigned i1 = 0 ; i1 < unsigned(left.extent(1)) ; ++i1 ) - for ( unsigned i0 = 0 ; i0 < unsigned(left.extent(0)) ; ++i0 ) - { - const long j = & left( i0, i1, i2, i3, i4, i5 ) - - & left( 0, 0, 0, 0, 0, 0 ); - if ( j <= offset || left_alloc <= j ) { update |= 1 ; } - offset = j ; - } - - offset = -1 ; - for ( unsigned i0 = 0 ; i0 < unsigned(right.extent(0)) ; ++i0 ) - for ( unsigned i1 = 0 ; i1 < unsigned(right.extent(1)) ; ++i1 ) - for ( unsigned i2 = 0 ; i2 < unsigned(right.extent(2)) ; ++i2 ) - for ( unsigned i3 = 0 ; i3 < unsigned(right.extent(3)) ; ++i3 ) - for ( unsigned i4 = 0 ; i4 < unsigned(right.extent(4)) ; ++i4 ) - for ( unsigned i5 = 0 ; i5 < unsigned(right.extent(5)) ; ++i5 ) - { - const long j = & right( i0, i1, i2, i3, i4, i5 ) - - & right( 0, 0, 0, 0, 0, 0 ); - if ( j <= offset || right_alloc <= j ) { update |= 2 ; } - offset = j ; - } + void operator()(const size_type, value_type& update) const { + long offset; + + offset = -1; + for (unsigned i5 = 0; i5 < unsigned(left.extent(5)); ++i5) + for (unsigned i4 = 0; i4 < unsigned(left.extent(4)); ++i4) + for (unsigned i3 = 0; i3 < unsigned(left.extent(3)); ++i3) + for (unsigned i2 = 0; i2 < unsigned(left.extent(2)); ++i2) + for (unsigned i1 = 0; i1 < unsigned(left.extent(1)); ++i1) + for (unsigned i0 = 0; i0 < unsigned(left.extent(0)); ++i0) { + const long j = + &left(i0, i1, i2, i3, i4, i5) - &left(0, 0, 0, 0, 0, 0); + if (j <= offset || left_alloc <= j) { + update |= 1; + } + offset = j; + } + + offset = -1; + for (unsigned i0 = 0; i0 < unsigned(right.extent(0)); ++i0) + for (unsigned i1 = 0; i1 < unsigned(right.extent(1)); ++i1) + for (unsigned i2 = 0; i2 < unsigned(right.extent(2)); ++i2) + for (unsigned i3 = 0; i3 < unsigned(right.extent(3)); ++i3) + for (unsigned i4 = 0; i4 < unsigned(right.extent(4)); ++i4) + for (unsigned i5 = 0; i5 < unsigned(right.extent(5)); ++i5) { + const long j = + &right(i0, i1, i2, i3, i4, i5) - &right(0, 0, 0, 0, 0, 0); + if (j <= offset || right_alloc <= j) { + update |= 2; + } + offset = j; + } } }; -template< class DataType , class DeviceType > -struct TestViewOperator_LeftAndRight< DataType , DeviceType , 5 > -{ - typedef DeviceType execution_space ; - typedef typename execution_space::memory_space memory_space ; - typedef typename execution_space::size_type size_type ; +template +struct TestViewOperator_LeftAndRight { + typedef DeviceType execution_space; + typedef typename execution_space::memory_space memory_space; + typedef typename execution_space::size_type size_type; - typedef int value_type ; + typedef int value_type; KOKKOS_INLINE_FUNCTION - static void join( volatile value_type & update , - const volatile value_type & input ) - { update |= input ; } + static void join(volatile value_type& update, + const volatile value_type& input) { + update |= input; + } KOKKOS_INLINE_FUNCTION - static void init( value_type & update ) - { update = 0 ; } - - - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutLeft, execution_space > left_view ; - - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutRight, execution_space > right_view ; - - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutStride, execution_space > stride_view ; - - left_view left ; - right_view right ; - stride_view left_stride ; - stride_view right_stride ; - long left_alloc ; - long right_alloc ; - - TestViewOperator_LeftAndRight(unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4 ) - : left( "left" , N0, N1, N2, N3, N4 ) - , right( "right" , N0, N1, N2, N3, N4 ) - , left_stride( left ) - , right_stride( right ) - , left_alloc( allocation_count( left ) ) - , right_alloc( allocation_count( right ) ) - {} - - static void testit(unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4) - { + static void init(value_type& update) { update = 0; } + + typedef Kokkos::DynRankView + left_view; + + typedef Kokkos::DynRankView + right_view; + + typedef Kokkos::DynRankView + stride_view; + + left_view left; + right_view right; + stride_view left_stride; + stride_view right_stride; + long left_alloc; + long right_alloc; + + TestViewOperator_LeftAndRight(unsigned N0, unsigned N1, unsigned N2, + unsigned N3, unsigned N4) + : left("left", N0, N1, N2, N3, N4), + right("right", N0, N1, N2, N3, N4), + left_stride(left), + right_stride(right), + left_alloc(allocation_count(left)), + right_alloc(allocation_count(right)) {} + + static void testit(unsigned N0, unsigned N1, unsigned N2, unsigned N3, + unsigned N4) { TestViewOperator_LeftAndRight driver(N0, N1, N2, N3, N4); - int error_flag = 0 ; + int error_flag = 0; - Kokkos::parallel_reduce( 1 , driver , error_flag ); + Kokkos::parallel_reduce(1, driver, error_flag); - ASSERT_EQ( error_flag , 0 ); + ASSERT_EQ(error_flag, 0); } KOKKOS_INLINE_FUNCTION - void operator()( const size_type , value_type & update ) const - { - long offset ; - - offset = -1 ; - for ( unsigned i4 = 0 ; i4 < unsigned(left.extent(4)) ; ++i4 ) - for ( unsigned i3 = 0 ; i3 < unsigned(left.extent(3)) ; ++i3 ) - for ( unsigned i2 = 0 ; i2 < unsigned(left.extent(2)) ; ++i2 ) - for ( unsigned i1 = 0 ; i1 < unsigned(left.extent(1)) ; ++i1 ) - for ( unsigned i0 = 0 ; i0 < unsigned(left.extent(0)) ; ++i0 ) - { - const long j = & left( i0, i1, i2, i3, i4 ) - - & left( 0, 0, 0, 0, 0 ); - if ( j <= offset || left_alloc <= j ) { update |= 1 ; } - offset = j ; - - if ( & left( i0, i1, i2, i3, i4 ) != - & left_stride( i0, i1, i2, i3, i4 ) ) { update |= 4 ; } - } - - offset = -1 ; - for ( unsigned i0 = 0 ; i0 < unsigned(right.extent(0)) ; ++i0 ) - for ( unsigned i1 = 0 ; i1 < unsigned(right.extent(1)) ; ++i1 ) - for ( unsigned i2 = 0 ; i2 < unsigned(right.extent(2)) ; ++i2 ) - for ( unsigned i3 = 0 ; i3 < unsigned(right.extent(3)) ; ++i3 ) - for ( unsigned i4 = 0 ; i4 < unsigned(right.extent(4)) ; ++i4 ) - { - const long j = & right( i0, i1, i2, i3, i4 ) - - & right( 0, 0, 0, 0, 0 ); - if ( j <= offset || right_alloc <= j ) { update |= 2 ; } - offset = j ; - - if ( & right( i0, i1, i2, i3, i4 ) != - & right_stride( i0, i1, i2, i3, i4 ) ) { update |= 8 ; } - } + void operator()(const size_type, value_type& update) const { + long offset; + + offset = -1; + for (unsigned i4 = 0; i4 < unsigned(left.extent(4)); ++i4) + for (unsigned i3 = 0; i3 < unsigned(left.extent(3)); ++i3) + for (unsigned i2 = 0; i2 < unsigned(left.extent(2)); ++i2) + for (unsigned i1 = 0; i1 < unsigned(left.extent(1)); ++i1) + for (unsigned i0 = 0; i0 < unsigned(left.extent(0)); ++i0) { + const long j = &left(i0, i1, i2, i3, i4) - &left(0, 0, 0, 0, 0); + if (j <= offset || left_alloc <= j) { + update |= 1; + } + offset = j; + + if (&left(i0, i1, i2, i3, i4) != + &left_stride(i0, i1, i2, i3, i4)) { + update |= 4; + } + } + + offset = -1; + for (unsigned i0 = 0; i0 < unsigned(right.extent(0)); ++i0) + for (unsigned i1 = 0; i1 < unsigned(right.extent(1)); ++i1) + for (unsigned i2 = 0; i2 < unsigned(right.extent(2)); ++i2) + for (unsigned i3 = 0; i3 < unsigned(right.extent(3)); ++i3) + for (unsigned i4 = 0; i4 < unsigned(right.extent(4)); ++i4) { + const long j = &right(i0, i1, i2, i3, i4) - &right(0, 0, 0, 0, 0); + if (j <= offset || right_alloc <= j) { + update |= 2; + } + offset = j; + + if (&right(i0, i1, i2, i3, i4) != + &right_stride(i0, i1, i2, i3, i4)) { + update |= 8; + } + } } }; -template< class DataType , class DeviceType > -struct TestViewOperator_LeftAndRight< DataType , DeviceType , 4 > -{ - typedef DeviceType execution_space ; - typedef typename execution_space::memory_space memory_space ; - typedef typename execution_space::size_type size_type ; +template +struct TestViewOperator_LeftAndRight { + typedef DeviceType execution_space; + typedef typename execution_space::memory_space memory_space; + typedef typename execution_space::size_type size_type; - typedef int value_type ; + typedef int value_type; KOKKOS_INLINE_FUNCTION - static void join( volatile value_type & update , - const volatile value_type & input ) - { update |= input ; } + static void join(volatile value_type& update, + const volatile value_type& input) { + update |= input; + } KOKKOS_INLINE_FUNCTION - static void init( value_type & update ) - { update = 0 ; } - + static void init(value_type& update) { update = 0; } - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutLeft, execution_space > left_view ; + typedef Kokkos::DynRankView + left_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutRight, execution_space > right_view ; + typedef Kokkos::DynRankView + right_view; - left_view left ; - right_view right ; - long left_alloc ; - long right_alloc ; + left_view left; + right_view right; + long left_alloc; + long right_alloc; - TestViewOperator_LeftAndRight(unsigned N0, unsigned N1, unsigned N2, unsigned N3) - : left( "left" , N0, N1, N2, N3 ) - , right( "right" , N0, N1, N2, N3 ) - , left_alloc( allocation_count( left ) ) - , right_alloc( allocation_count( right ) ) - {} + TestViewOperator_LeftAndRight(unsigned N0, unsigned N1, unsigned N2, + unsigned N3) + : left("left", N0, N1, N2, N3), + right("right", N0, N1, N2, N3), + left_alloc(allocation_count(left)), + right_alloc(allocation_count(right)) {} - static void testit(unsigned N0, unsigned N1, unsigned N2, unsigned N3) - { - TestViewOperator_LeftAndRight driver (N0, N1, N2, N3); + static void testit(unsigned N0, unsigned N1, unsigned N2, unsigned N3) { + TestViewOperator_LeftAndRight driver(N0, N1, N2, N3); - int error_flag = 0 ; + int error_flag = 0; - Kokkos::parallel_reduce( 1 , driver , error_flag ); + Kokkos::parallel_reduce(1, driver, error_flag); - ASSERT_EQ( error_flag , 0 ); + ASSERT_EQ(error_flag, 0); } KOKKOS_INLINE_FUNCTION - void operator()( const size_type , value_type & update ) const - { - long offset ; - - offset = -1 ; - for ( unsigned i3 = 0 ; i3 < unsigned(left.extent(3)) ; ++i3 ) - for ( unsigned i2 = 0 ; i2 < unsigned(left.extent(2)) ; ++i2 ) - for ( unsigned i1 = 0 ; i1 < unsigned(left.extent(1)) ; ++i1 ) - for ( unsigned i0 = 0 ; i0 < unsigned(left.extent(0)) ; ++i0 ) - { - const long j = & left( i0, i1, i2, i3 ) - - & left( 0, 0, 0, 0 ); - if ( j <= offset || left_alloc <= j ) { update |= 1 ; } - offset = j ; - } - - offset = -1 ; - for ( unsigned i0 = 0 ; i0 < unsigned(right.extent(0)) ; ++i0 ) - for ( unsigned i1 = 0 ; i1 < unsigned(right.extent(1)) ; ++i1 ) - for ( unsigned i2 = 0 ; i2 < unsigned(right.extent(2)) ; ++i2 ) - for ( unsigned i3 = 0 ; i3 < unsigned(right.extent(3)) ; ++i3 ) - { - const long j = & right( i0, i1, i2, i3 ) - - & right( 0, 0, 0, 0 ); - if ( j <= offset || right_alloc <= j ) { update |= 2 ; } - offset = j ; - } + void operator()(const size_type, value_type& update) const { + long offset; + + offset = -1; + for (unsigned i3 = 0; i3 < unsigned(left.extent(3)); ++i3) + for (unsigned i2 = 0; i2 < unsigned(left.extent(2)); ++i2) + for (unsigned i1 = 0; i1 < unsigned(left.extent(1)); ++i1) + for (unsigned i0 = 0; i0 < unsigned(left.extent(0)); ++i0) { + const long j = &left(i0, i1, i2, i3) - &left(0, 0, 0, 0); + if (j <= offset || left_alloc <= j) { + update |= 1; + } + offset = j; + } + + offset = -1; + for (unsigned i0 = 0; i0 < unsigned(right.extent(0)); ++i0) + for (unsigned i1 = 0; i1 < unsigned(right.extent(1)); ++i1) + for (unsigned i2 = 0; i2 < unsigned(right.extent(2)); ++i2) + for (unsigned i3 = 0; i3 < unsigned(right.extent(3)); ++i3) { + const long j = &right(i0, i1, i2, i3) - &right(0, 0, 0, 0); + if (j <= offset || right_alloc <= j) { + update |= 2; + } + offset = j; + } } }; -template< class DataType , class DeviceType > -struct TestViewOperator_LeftAndRight< DataType , DeviceType , 3 > -{ - typedef DeviceType execution_space ; - typedef typename execution_space::memory_space memory_space ; - typedef typename execution_space::size_type size_type ; +template +struct TestViewOperator_LeftAndRight { + typedef DeviceType execution_space; + typedef typename execution_space::memory_space memory_space; + typedef typename execution_space::size_type size_type; - typedef int value_type ; + typedef int value_type; KOKKOS_INLINE_FUNCTION - static void join( volatile value_type & update , - const volatile value_type & input ) - { update |= input ; } + static void join(volatile value_type& update, + const volatile value_type& input) { + update |= input; + } KOKKOS_INLINE_FUNCTION - static void init( value_type & update ) - { update = 0 ; } - + static void init(value_type& update) { update = 0; } - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutLeft, execution_space > left_view ; + typedef Kokkos::DynRankView + left_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutRight, execution_space > right_view ; + typedef Kokkos::DynRankView + right_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutStride, execution_space > stride_view ; + typedef Kokkos::DynRankView + stride_view; - left_view left ; - right_view right ; - stride_view left_stride ; - stride_view right_stride ; - long left_alloc ; - long right_alloc ; + left_view left; + right_view right; + stride_view left_stride; + stride_view right_stride; + long left_alloc; + long right_alloc; TestViewOperator_LeftAndRight(unsigned N0, unsigned N1, unsigned N2) - : left( std::string("left") , N0, N1, N2 ) - , right( std::string("right") , N0, N1, N2 ) - , left_stride( left ) - , right_stride( right ) - , left_alloc( allocation_count( left ) ) - , right_alloc( allocation_count( right ) ) - {} + : left(std::string("left"), N0, N1, N2), + right(std::string("right"), N0, N1, N2), + left_stride(left), + right_stride(right), + left_alloc(allocation_count(left)), + right_alloc(allocation_count(right)) {} - static void testit(unsigned N0, unsigned N1, unsigned N2) - { - TestViewOperator_LeftAndRight driver (N0, N1, N2); + static void testit(unsigned N0, unsigned N1, unsigned N2) { + TestViewOperator_LeftAndRight driver(N0, N1, N2); - int error_flag = 0 ; + int error_flag = 0; - Kokkos::parallel_reduce( 1 , driver , error_flag ); + Kokkos::parallel_reduce(1, driver, error_flag); - ASSERT_EQ( error_flag , 0 ); + ASSERT_EQ(error_flag, 0); } KOKKOS_INLINE_FUNCTION - void operator()( const size_type , value_type & update ) const - { - long offset ; - - offset = -1 ; - for ( unsigned i2 = 0 ; i2 < unsigned(left.extent(2)) ; ++i2 ) - for ( unsigned i1 = 0 ; i1 < unsigned(left.extent(1)) ; ++i1 ) - for ( unsigned i0 = 0 ; i0 < unsigned(left.extent(0)) ; ++i0 ) - { - const long j = & left( i0, i1, i2 ) - - & left( 0, 0, 0 ); - if ( j <= offset || left_alloc <= j ) { update |= 1 ; } - offset = j ; - - if ( & left(i0,i1,i2) != & left_stride(i0,i1,i2) ) { update |= 4 ; } - } - - offset = -1 ; - for ( unsigned i0 = 0 ; i0 < unsigned(right.extent(0)) ; ++i0 ) - for ( unsigned i1 = 0 ; i1 < unsigned(right.extent(1)) ; ++i1 ) - for ( unsigned i2 = 0 ; i2 < unsigned(right.extent(2)) ; ++i2 ) - { - const long j = & right( i0, i1, i2 ) - - & right( 0, 0, 0 ); - if ( j <= offset || right_alloc <= j ) { update |= 2 ; } - offset = j ; - - if ( & right(i0,i1,i2) != & right_stride(i0,i1,i2) ) { update |= 8 ; } - } - - for ( unsigned i0 = 0 ; i0 < unsigned(left.extent(0)) ; ++i0 ) - for ( unsigned i1 = 0 ; i1 < unsigned(left.extent(1)) ; ++i1 ) - for ( unsigned i2 = 0 ; i2 < unsigned(left.extent(2)) ; ++i2 ) - { - if ( & left(i0,i1,i2) != & left(i0,i1,i2,0,0,0,0) ) { update |= 3 ; } - if ( & right(i0,i1,i2) != & right(i0,i1,i2,0,0,0,0) ) { update |= 3 ; } - } + void operator()(const size_type, value_type& update) const { + long offset; + + offset = -1; + for (unsigned i2 = 0; i2 < unsigned(left.extent(2)); ++i2) + for (unsigned i1 = 0; i1 < unsigned(left.extent(1)); ++i1) + for (unsigned i0 = 0; i0 < unsigned(left.extent(0)); ++i0) { + const long j = &left(i0, i1, i2) - &left(0, 0, 0); + if (j <= offset || left_alloc <= j) { + update |= 1; + } + offset = j; + + if (&left(i0, i1, i2) != &left_stride(i0, i1, i2)) { + update |= 4; + } + } + + offset = -1; + for (unsigned i0 = 0; i0 < unsigned(right.extent(0)); ++i0) + for (unsigned i1 = 0; i1 < unsigned(right.extent(1)); ++i1) + for (unsigned i2 = 0; i2 < unsigned(right.extent(2)); ++i2) { + const long j = &right(i0, i1, i2) - &right(0, 0, 0); + if (j <= offset || right_alloc <= j) { + update |= 2; + } + offset = j; + + if (&right(i0, i1, i2) != &right_stride(i0, i1, i2)) { + update |= 8; + } + } + + for (unsigned i0 = 0; i0 < unsigned(left.extent(0)); ++i0) + for (unsigned i1 = 0; i1 < unsigned(left.extent(1)); ++i1) + for (unsigned i2 = 0; i2 < unsigned(left.extent(2)); ++i2) { + if (&left(i0, i1, i2) != &left(i0, i1, i2, 0, 0, 0, 0)) { + update |= 3; + } + if (&right(i0, i1, i2) != &right(i0, i1, i2, 0, 0, 0, 0)) { + update |= 3; + } + } } }; -template< class DataType , class DeviceType > -struct TestViewOperator_LeftAndRight< DataType , DeviceType , 2 > -{ - typedef DeviceType execution_space ; - typedef typename execution_space::memory_space memory_space ; - typedef typename execution_space::size_type size_type ; +template +struct TestViewOperator_LeftAndRight { + typedef DeviceType execution_space; + typedef typename execution_space::memory_space memory_space; + typedef typename execution_space::size_type size_type; - typedef int value_type ; + typedef int value_type; KOKKOS_INLINE_FUNCTION - static void join( volatile value_type & update , - const volatile value_type & input ) - { update |= input ; } + static void join(volatile value_type& update, + const volatile value_type& input) { + update |= input; + } KOKKOS_INLINE_FUNCTION - static void init( value_type & update ) - { update = 0 ; } + static void init(value_type& update) { update = 0; } + typedef Kokkos::DynRankView + left_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutLeft, execution_space > left_view ; + typedef Kokkos::DynRankView + right_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutRight, execution_space > right_view ; - - left_view left ; - right_view right ; - long left_alloc ; - long right_alloc ; + left_view left; + right_view right; + long left_alloc; + long right_alloc; TestViewOperator_LeftAndRight(unsigned N0, unsigned N1) - : left( "left" , N0, N1 ) - , right( "right" , N0, N1 ) - , left_alloc( allocation_count( left ) ) - , right_alloc( allocation_count( right ) ) - {} - - static void testit(unsigned N0, unsigned N1) - { + : left("left", N0, N1), + right("right", N0, N1), + left_alloc(allocation_count(left)), + right_alloc(allocation_count(right)) {} + + static void testit(unsigned N0, unsigned N1) { TestViewOperator_LeftAndRight driver(N0, N1); - int error_flag = 0 ; + int error_flag = 0; - Kokkos::parallel_reduce( 1 , driver , error_flag ); + Kokkos::parallel_reduce(1, driver, error_flag); - ASSERT_EQ( error_flag , 0 ); + ASSERT_EQ(error_flag, 0); } KOKKOS_INLINE_FUNCTION - void operator()( const size_type , value_type & update ) const - { - long offset ; - - offset = -1 ; - for ( unsigned i1 = 0 ; i1 < unsigned(left.extent(1)) ; ++i1 ) - for ( unsigned i0 = 0 ; i0 < unsigned(left.extent(0)) ; ++i0 ) - { - const long j = & left( i0, i1 ) - - & left( 0, 0 ); - if ( j <= offset || left_alloc <= j ) { update |= 1 ; } - offset = j ; - } - - offset = -1 ; - for ( unsigned i0 = 0 ; i0 < unsigned(right.extent(0)) ; ++i0 ) - for ( unsigned i1 = 0 ; i1 < unsigned(right.extent(1)) ; ++i1 ) - { - const long j = & right( i0, i1 ) - - & right( 0, 0 ); - if ( j <= offset || right_alloc <= j ) { update |= 2 ; } - offset = j ; - } - - for ( unsigned i0 = 0 ; i0 < unsigned(left.extent(0)) ; ++i0 ) - for ( unsigned i1 = 0 ; i1 < unsigned(left.extent(1)) ; ++i1 ) - { - if ( & left(i0,i1) != & left(i0,i1,0,0,0,0,0) ) { update |= 3 ; } - if ( & right(i0,i1) != & right(i0,i1,0,0,0,0,0) ) { update |= 3 ; } - } + void operator()(const size_type, value_type& update) const { + long offset; + + offset = -1; + for (unsigned i1 = 0; i1 < unsigned(left.extent(1)); ++i1) + for (unsigned i0 = 0; i0 < unsigned(left.extent(0)); ++i0) { + const long j = &left(i0, i1) - &left(0, 0); + if (j <= offset || left_alloc <= j) { + update |= 1; + } + offset = j; + } + + offset = -1; + for (unsigned i0 = 0; i0 < unsigned(right.extent(0)); ++i0) + for (unsigned i1 = 0; i1 < unsigned(right.extent(1)); ++i1) { + const long j = &right(i0, i1) - &right(0, 0); + if (j <= offset || right_alloc <= j) { + update |= 2; + } + offset = j; + } + + for (unsigned i0 = 0; i0 < unsigned(left.extent(0)); ++i0) + for (unsigned i1 = 0; i1 < unsigned(left.extent(1)); ++i1) { + if (&left(i0, i1) != &left(i0, i1, 0, 0, 0, 0, 0)) { + update |= 3; + } + if (&right(i0, i1) != &right(i0, i1, 0, 0, 0, 0, 0)) { + update |= 3; + } + } } }; -template< class DataType , class DeviceType > -struct TestViewOperator_LeftAndRight< DataType , DeviceType , 1 > -{ - typedef DeviceType execution_space ; - typedef typename execution_space::memory_space memory_space ; - typedef typename execution_space::size_type size_type ; +template +struct TestViewOperator_LeftAndRight { + typedef DeviceType execution_space; + typedef typename execution_space::memory_space memory_space; + typedef typename execution_space::size_type size_type; - typedef int value_type ; + typedef int value_type; KOKKOS_INLINE_FUNCTION - static void join( volatile value_type & update , - const volatile value_type & input ) - { update |= input ; } + static void join(volatile value_type& update, + const volatile value_type& input) { + update |= input; + } KOKKOS_INLINE_FUNCTION - static void init( value_type & update ) - { update = 0 ; } + static void init(value_type& update) { update = 0; } + typedef Kokkos::DynRankView + left_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutLeft, execution_space > left_view ; + typedef Kokkos::DynRankView + right_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutRight, execution_space > right_view ; + typedef Kokkos::DynRankView + stride_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutStride, execution_space > stride_view ; - - left_view left ; - right_view right ; - stride_view left_stride ; - stride_view right_stride ; - long left_alloc ; - long right_alloc ; + left_view left; + right_view right; + stride_view left_stride; + stride_view right_stride; + long left_alloc; + long right_alloc; TestViewOperator_LeftAndRight(unsigned N0) - : left( "left" , N0 ) - , right( "right" , N0 ) - , left_stride( left ) - , right_stride( right ) - , left_alloc( allocation_count( left ) ) - , right_alloc( allocation_count( right ) ) - {} + : left("left", N0), + right("right", N0), + left_stride(left), + right_stride(right), + left_alloc(allocation_count(left)), + right_alloc(allocation_count(right)) {} - static void testit(unsigned N0) - { - TestViewOperator_LeftAndRight driver (N0) ; + static void testit(unsigned N0) { + TestViewOperator_LeftAndRight driver(N0); - int error_flag = 0 ; + int error_flag = 0; - Kokkos::parallel_reduce( 1 , driver , error_flag ); + Kokkos::parallel_reduce(1, driver, error_flag); - ASSERT_EQ( error_flag , 0 ); + ASSERT_EQ(error_flag, 0); } KOKKOS_INLINE_FUNCTION - void operator()( const size_type , value_type & update ) const - { - for ( unsigned i0 = 0 ; i0 < unsigned(left.extent(0)) ; ++i0 ) - { - if ( & left(i0) != & left(i0,0,0,0,0,0,0) ) { update |= 3 ; } - if ( & right(i0) != & right(i0,0,0,0,0,0,0) ) { update |= 3 ; } - if ( & left(i0) != & left_stride(i0) ) { update |= 4 ; } - if ( & right(i0) != & right_stride(i0) ) { update |= 8 ; } + void operator()(const size_type, value_type& update) const { + for (unsigned i0 = 0; i0 < unsigned(left.extent(0)); ++i0) { + if (&left(i0) != &left(i0, 0, 0, 0, 0, 0, 0)) { + update |= 3; + } + if (&right(i0) != &right(i0, 0, 0, 0, 0, 0, 0)) { + update |= 3; + } + if (&left(i0) != &left_stride(i0)) { + update |= 4; + } + if (&right(i0) != &right_stride(i0)) { + update |= 8; + } } } }; /*--------------------------------------------------------------------------*/ -template< typename T, class DeviceType > -class TestDynViewAPI -{ -public: - typedef DeviceType device ; +template +class TestDynViewAPI { + public: + typedef DeviceType device; - enum { N0 = 1000 , - N1 = 3 , - N2 = 5 , - N3 = 7 }; + enum { N0 = 1000, N1 = 3, N2 = 5, N3 = 7 }; - typedef Kokkos::DynRankView< T , device > dView0 ; - typedef Kokkos::DynRankView< const T , device > const_dView0 ; + typedef Kokkos::DynRankView dView0; + typedef Kokkos::DynRankView const_dView0; - typedef Kokkos::DynRankView< T, device, Kokkos::MemoryUnmanaged > dView0_unmanaged ; - typedef typename dView0::host_mirror_space host_drv_space ; + typedef Kokkos::DynRankView + dView0_unmanaged; + typedef typename dView0::host_mirror_space host_drv_space; - typedef Kokkos::View< T , device > View0 ; - typedef Kokkos::View< T* , device > View1 ; - typedef Kokkos::View< T******* , device > View7 ; + typedef Kokkos::View View0; + typedef Kokkos::View View1; + typedef Kokkos::View View7; - typedef typename View0::host_mirror_space host_view_space ; + typedef typename View0::host_mirror_space host_view_space; - TestDynViewAPI() - { - } + TestDynViewAPI() {} static void run_tests() { run_test_resize_realloc(); @@ -738,459 +720,475 @@ public: run_test_vector(); } - static void run_operator_test_rank12345 () { - TestViewOperator< T , device >::testit(); - TestViewOperator_LeftAndRight< int , device , 5 >::testit(2,3,4,2,3); - TestViewOperator_LeftAndRight< int , device , 4 >::testit(2,3,4,2); - TestViewOperator_LeftAndRight< int , device , 3 >::testit(2,3,4); - TestViewOperator_LeftAndRight< int , device , 2 >::testit(2,3); - TestViewOperator_LeftAndRight< int , device , 1 >::testit(2); + static void run_operator_test_rank12345() { + TestViewOperator::testit(); + TestViewOperator_LeftAndRight::testit(2, 3, 4, 2, 3); + TestViewOperator_LeftAndRight::testit(2, 3, 4, 2); + TestViewOperator_LeftAndRight::testit(2, 3, 4); + TestViewOperator_LeftAndRight::testit(2, 3); + TestViewOperator_LeftAndRight::testit(2); } - static void run_operator_test_rank67 () { - TestViewOperator_LeftAndRight< int , device , 7 >::testit(2,3,4,2,3,4,2); - TestViewOperator_LeftAndRight< int , device , 6 >::testit(2,3,4,2,3,4); + static void run_operator_test_rank67() { + TestViewOperator_LeftAndRight::testit(2, 3, 4, 2, 3, 4, 2); + TestViewOperator_LeftAndRight::testit(2, 3, 4, 2, 3, 4); } - static void run_test_resize_realloc() - { + static void run_test_resize_realloc() { dView0 drv0("drv0", 10, 20, 30); - ASSERT_EQ( drv0.rank(), 3); + ASSERT_EQ(drv0.rank(), 3); Kokkos::resize(drv0, 5, 10); - ASSERT_EQ( drv0.rank(), 2); - ASSERT_EQ( drv0.extent(0), 5); - ASSERT_EQ( drv0.extent(1), 10); - ASSERT_EQ( drv0.extent(2), 1); + ASSERT_EQ(drv0.rank(), 2); + ASSERT_EQ(drv0.extent(0), 5); + ASSERT_EQ(drv0.extent(1), 10); + ASSERT_EQ(drv0.extent(2), 1); Kokkos::realloc(drv0, 10, 20); - ASSERT_EQ( drv0.rank(), 2); - ASSERT_EQ( drv0.extent(0), 10); - ASSERT_EQ( drv0.extent(1), 20); - ASSERT_EQ( drv0.extent(2), 1); - + ASSERT_EQ(drv0.rank(), 2); + ASSERT_EQ(drv0.extent(0), 10); + ASSERT_EQ(drv0.extent(1), 20); + ASSERT_EQ(drv0.extent(2), 1); } - static void run_test_mirror() - { - typedef Kokkos::DynRankView< int , host_drv_space > view_type ; - typedef typename view_type::HostMirror mirror_type ; + static void run_test_mirror() { + typedef Kokkos::DynRankView view_type; + typedef typename view_type::HostMirror mirror_type; view_type a("a"); mirror_type am = Kokkos::create_mirror_view(a); mirror_type ax = Kokkos::create_mirror(a); - ASSERT_EQ( & a() , & am() ); - ASSERT_EQ( a.rank() , am.rank() ); - ASSERT_EQ( ax.rank() , am.rank() ); + ASSERT_EQ(&a(), &am()); + ASSERT_EQ(a.rank(), am.rank()); + ASSERT_EQ(ax.rank(), am.rank()); { - Kokkos::DynRankView a_h("A",1000); - auto a_h2 = Kokkos::create_mirror(Kokkos::HostSpace(),a_h); - auto a_d = Kokkos::create_mirror(typename device::memory_space(),a_h); - - int equal_ptr_h_h2 = (a_h.data() ==a_h2.data())?1:0; - int equal_ptr_h_d = (a_h.data() ==a_d. data())?1:0; - int equal_ptr_h2_d = (a_h2.data()==a_d. data())?1:0; - - ASSERT_EQ(equal_ptr_h_h2,0); - ASSERT_EQ(equal_ptr_h_d ,0); - ASSERT_EQ(equal_ptr_h2_d,0); - - ASSERT_EQ(a_h.extent(0),a_h2.extent(0)); - ASSERT_EQ(a_h.extent(0),a_d .extent(0)); - - ASSERT_EQ(a_h.rank(),a_h2.rank()); - ASSERT_EQ(a_h.rank(),a_d.rank()); - } - { - Kokkos::DynRankView a_h("A",1000); - auto a_h2 = Kokkos::create_mirror(Kokkos::HostSpace(),a_h); - auto a_d = Kokkos::create_mirror(typename device::memory_space(),a_h); - - int equal_ptr_h_h2 = (a_h.data() ==a_h2.data())?1:0; - int equal_ptr_h_d = (a_h.data() ==a_d. data())?1:0; - int equal_ptr_h2_d = (a_h2.data()==a_d. data())?1:0; - - ASSERT_EQ(equal_ptr_h_h2,0); - ASSERT_EQ(equal_ptr_h_d ,0); - ASSERT_EQ(equal_ptr_h2_d,0); - - ASSERT_EQ(a_h.extent(0),a_h2.extent(0)); - ASSERT_EQ(a_h.extent(0),a_d .extent(0)); - - ASSERT_EQ(a_h.rank(),a_h2.rank()); - ASSERT_EQ(a_h.rank(),a_d.rank()); - } + Kokkos::DynRankView a_h( + "A", 1000); + auto a_h2 = Kokkos::create_mirror(Kokkos::HostSpace(), a_h); + auto a_d = Kokkos::create_mirror(typename device::memory_space(), a_h); - { - Kokkos::DynRankView a_h("A",1000); - auto a_h2 = Kokkos::create_mirror_view(Kokkos::HostSpace(),a_h); - auto a_d = Kokkos::create_mirror_view(typename device::memory_space(),a_h); - - int equal_ptr_h_h2 = a_h.data() ==a_h2.data()?1:0; - int equal_ptr_h_d = a_h.data() ==a_d. data()?1:0; - int equal_ptr_h2_d = a_h2.data()==a_d. data()?1:0; + int equal_ptr_h_h2 = (a_h.data() == a_h2.data()) ? 1 : 0; + int equal_ptr_h_d = (a_h.data() == a_d.data()) ? 1 : 0; + int equal_ptr_h2_d = (a_h2.data() == a_d.data()) ? 1 : 0; - int is_same_memspace = std::is_same::value?1:0; - ASSERT_EQ(equal_ptr_h_h2,1); - ASSERT_EQ(equal_ptr_h_d ,is_same_memspace); - ASSERT_EQ(equal_ptr_h2_d ,is_same_memspace); + ASSERT_EQ(equal_ptr_h_h2, 0); + ASSERT_EQ(equal_ptr_h_d, 0); + ASSERT_EQ(equal_ptr_h2_d, 0); - ASSERT_EQ(a_h.extent(0),a_h2.extent(0)); - ASSERT_EQ(a_h.extent(0),a_d .extent(0)); + ASSERT_EQ(a_h.extent(0), a_h2.extent(0)); + ASSERT_EQ(a_h.extent(0), a_d.extent(0)); - ASSERT_EQ(a_h.rank(),a_h2.rank()); - ASSERT_EQ(a_h.rank(),a_d.rank()); + ASSERT_EQ(a_h.rank(), a_h2.rank()); + ASSERT_EQ(a_h.rank(), a_d.rank()); } { - Kokkos::DynRankView a_h("A",1000); - auto a_h2 = Kokkos::create_mirror_view(Kokkos::HostSpace(),a_h); - auto a_d = Kokkos::create_mirror_view(typename device::memory_space(),a_h); + Kokkos::DynRankView a_h( + "A", 1000); + auto a_h2 = Kokkos::create_mirror(Kokkos::HostSpace(), a_h); + auto a_d = Kokkos::create_mirror(typename device::memory_space(), a_h); - int equal_ptr_h_h2 = a_h.data() ==a_h2.data()?1:0; - int equal_ptr_h_d = a_h.data() ==a_d. data()?1:0; - int equal_ptr_h2_d = a_h2.data()==a_d. data()?1:0; + int equal_ptr_h_h2 = (a_h.data() == a_h2.data()) ? 1 : 0; + int equal_ptr_h_d = (a_h.data() == a_d.data()) ? 1 : 0; + int equal_ptr_h2_d = (a_h2.data() == a_d.data()) ? 1 : 0; - int is_same_memspace = std::is_same::value?1:0; - ASSERT_EQ(equal_ptr_h_h2,1); - ASSERT_EQ(equal_ptr_h_d ,is_same_memspace); - ASSERT_EQ(equal_ptr_h2_d ,is_same_memspace); + ASSERT_EQ(equal_ptr_h_h2, 0); + ASSERT_EQ(equal_ptr_h_d, 0); + ASSERT_EQ(equal_ptr_h2_d, 0); - - ASSERT_EQ(a_h.extent(0),a_h2.extent(0)); - ASSERT_EQ(a_h.extent(0),a_d .extent(0)); + ASSERT_EQ(a_h.extent(0), a_h2.extent(0)); + ASSERT_EQ(a_h.extent(0), a_d.extent(0)); - ASSERT_EQ(a_h.rank(),a_h2.rank()); - ASSERT_EQ(a_h.rank(),a_d.rank()); + ASSERT_EQ(a_h.rank(), a_h2.rank()); + ASSERT_EQ(a_h.rank(), a_d.rank()); } + { - typedef Kokkos::DynRankView< int , Kokkos::LayoutStride , Kokkos::HostSpace > view_stride_type ; - unsigned order[] = { 6,5,4,3,2,1,0 }, dimen[] = { N0, N1, N2, 2, 2, 2, 2 }; //LayoutRight equivalent - view_stride_type a_h( "a" , Kokkos::LayoutStride::order_dimensions(7, order, dimen) ); - auto a_h2 = Kokkos::create_mirror_view(Kokkos::HostSpace(),a_h); - auto a_d = Kokkos::create_mirror_view(typename device::memory_space(),a_h); - - int equal_ptr_h_h2 = a_h.data() ==a_h2.data()?1:0; - int equal_ptr_h_d = a_h.data() ==a_d. data()?1:0; - int equal_ptr_h2_d = a_h2.data()==a_d. data()?1:0; - - int is_same_memspace = std::is_same::value?1:0; - ASSERT_EQ(equal_ptr_h_h2,1); - ASSERT_EQ(equal_ptr_h_d ,is_same_memspace); - ASSERT_EQ(equal_ptr_h2_d ,is_same_memspace); - - ASSERT_EQ(a_h.extent(0),a_h2.extent(0)); - ASSERT_EQ(a_h.extent(0),a_d .extent(0)); - - ASSERT_EQ(a_h.rank(),a_h2.rank()); - ASSERT_EQ(a_h.rank(),a_d.rank()); + Kokkos::DynRankView a_h( + "A", 1000); + auto a_h2 = Kokkos::create_mirror_view(Kokkos::HostSpace(), a_h); + auto a_d = + Kokkos::create_mirror_view(typename device::memory_space(), a_h); + + int equal_ptr_h_h2 = a_h.data() == a_h2.data() ? 1 : 0; + int equal_ptr_h_d = a_h.data() == a_d.data() ? 1 : 0; + int equal_ptr_h2_d = a_h2.data() == a_d.data() ? 1 : 0; + + int is_same_memspace = + std::is_same::value + ? 1 + : 0; + ASSERT_EQ(equal_ptr_h_h2, 1); + ASSERT_EQ(equal_ptr_h_d, is_same_memspace); + ASSERT_EQ(equal_ptr_h2_d, is_same_memspace); + + ASSERT_EQ(a_h.extent(0), a_h2.extent(0)); + ASSERT_EQ(a_h.extent(0), a_d.extent(0)); + + ASSERT_EQ(a_h.rank(), a_h2.rank()); + ASSERT_EQ(a_h.rank(), a_d.rank()); + } + { + Kokkos::DynRankView a_h( + "A", 1000); + auto a_h2 = Kokkos::create_mirror_view(Kokkos::HostSpace(), a_h); + auto a_d = + Kokkos::create_mirror_view(typename device::memory_space(), a_h); + + int equal_ptr_h_h2 = a_h.data() == a_h2.data() ? 1 : 0; + int equal_ptr_h_d = a_h.data() == a_d.data() ? 1 : 0; + int equal_ptr_h2_d = a_h2.data() == a_d.data() ? 1 : 0; + + int is_same_memspace = + std::is_same::value + ? 1 + : 0; + ASSERT_EQ(equal_ptr_h_h2, 1); + ASSERT_EQ(equal_ptr_h_d, is_same_memspace); + ASSERT_EQ(equal_ptr_h2_d, is_same_memspace); + + ASSERT_EQ(a_h.extent(0), a_h2.extent(0)); + ASSERT_EQ(a_h.extent(0), a_d.extent(0)); + + ASSERT_EQ(a_h.rank(), a_h2.rank()); + ASSERT_EQ(a_h.rank(), a_d.rank()); + } + { + typedef Kokkos::DynRankView + view_stride_type; + unsigned order[] = {6, 5, 4, 3, 2, 1, 0}, + dimen[] = {N0, N1, N2, 2, 2, 2, 2}; // LayoutRight equivalent + view_stride_type a_h( + "a", Kokkos::LayoutStride::order_dimensions(7, order, dimen)); + auto a_h2 = Kokkos::create_mirror_view(Kokkos::HostSpace(), a_h); + auto a_d = + Kokkos::create_mirror_view(typename device::memory_space(), a_h); + + int equal_ptr_h_h2 = a_h.data() == a_h2.data() ? 1 : 0; + int equal_ptr_h_d = a_h.data() == a_d.data() ? 1 : 0; + int equal_ptr_h2_d = a_h2.data() == a_d.data() ? 1 : 0; + + int is_same_memspace = + std::is_same::value + ? 1 + : 0; + ASSERT_EQ(equal_ptr_h_h2, 1); + ASSERT_EQ(equal_ptr_h_d, is_same_memspace); + ASSERT_EQ(equal_ptr_h2_d, is_same_memspace); + + ASSERT_EQ(a_h.extent(0), a_h2.extent(0)); + ASSERT_EQ(a_h.extent(0), a_d.extent(0)); + + ASSERT_EQ(a_h.rank(), a_h2.rank()); + ASSERT_EQ(a_h.rank(), a_d.rank()); } } - static void run_test_mirror_and_copy() - { + static void run_test_mirror_and_copy() { // LayoutLeft { - Kokkos::DynRankView< double, Kokkos::LayoutLeft, Kokkos::HostSpace > a_org( "A", 10 ); + Kokkos::DynRankView a_org( + "A", 10); a_org(5) = 42.0; - Kokkos::DynRankView< double, Kokkos::LayoutLeft, Kokkos::HostSpace > a_h = a_org; - auto a_h2 = Kokkos::create_mirror_view_and_copy( Kokkos::HostSpace(), a_h ); - auto a_d = Kokkos::create_mirror_view_and_copy( DeviceType(), a_h ); - auto a_h3 = Kokkos::create_mirror_view_and_copy( Kokkos::HostSpace(), a_d ); - - int equal_ptr_h_h2 = a_h.data() == a_h2.data() ? 1 : 0; - int equal_ptr_h_d = a_h.data() == a_d.data() ? 1 : 0; - int equal_ptr_h2_d = a_h2.data() == a_d.data() ? 1 : 0; - int equal_ptr_h3_d = a_h3.data() == a_d.data() ? 1 : 0; - - int is_same_memspace = std::is_same< Kokkos::HostSpace, typename DeviceType::memory_space >::value ? 1 : 0; - ASSERT_EQ( equal_ptr_h_h2, 1 ); - ASSERT_EQ( equal_ptr_h_d, is_same_memspace ); - ASSERT_EQ( equal_ptr_h2_d, is_same_memspace ); - ASSERT_EQ( equal_ptr_h3_d, is_same_memspace ); - - ASSERT_EQ( a_h.extent(0), a_h3.extent(0) ); - ASSERT_EQ( a_h.extent(0), a_h2.extent(0) ); - ASSERT_EQ( a_h.extent(0), a_d .extent(0) ); - ASSERT_EQ( a_h.extent(0), a_h3.extent(0) ); - ASSERT_EQ( a_h.rank(), a_org.rank() ); - ASSERT_EQ( a_h.rank(), a_h2.rank() ); - ASSERT_EQ( a_h.rank(), a_h3.rank() ); - ASSERT_EQ( a_h.rank(), a_d.rank() ); - ASSERT_EQ( a_org(5), a_h3(5) ); + Kokkos::DynRankView a_h = + a_org; + auto a_h2 = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), a_h); + auto a_d = Kokkos::create_mirror_view_and_copy(DeviceType(), a_h); + auto a_h3 = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), a_d); + + int equal_ptr_h_h2 = a_h.data() == a_h2.data() ? 1 : 0; + int equal_ptr_h_d = a_h.data() == a_d.data() ? 1 : 0; + int equal_ptr_h2_d = a_h2.data() == a_d.data() ? 1 : 0; + int equal_ptr_h3_d = a_h3.data() == a_d.data() ? 1 : 0; + + int is_same_memspace = + std::is_same::value + ? 1 + : 0; + ASSERT_EQ(equal_ptr_h_h2, 1); + ASSERT_EQ(equal_ptr_h_d, is_same_memspace); + ASSERT_EQ(equal_ptr_h2_d, is_same_memspace); + ASSERT_EQ(equal_ptr_h3_d, is_same_memspace); + + ASSERT_EQ(a_h.extent(0), a_h3.extent(0)); + ASSERT_EQ(a_h.extent(0), a_h2.extent(0)); + ASSERT_EQ(a_h.extent(0), a_d.extent(0)); + ASSERT_EQ(a_h.extent(0), a_h3.extent(0)); + ASSERT_EQ(a_h.rank(), a_org.rank()); + ASSERT_EQ(a_h.rank(), a_h2.rank()); + ASSERT_EQ(a_h.rank(), a_h3.rank()); + ASSERT_EQ(a_h.rank(), a_d.rank()); + ASSERT_EQ(a_org(5), a_h3(5)); } // LayoutRight { - Kokkos::DynRankView< double, Kokkos::LayoutRight, Kokkos::HostSpace > a_org( "A", 10 ); + Kokkos::DynRankView a_org( + "A", 10); a_org(5) = 42.0; - Kokkos::DynRankView< double, Kokkos::LayoutRight, Kokkos::HostSpace > a_h = a_org; - auto a_h2 = Kokkos::create_mirror_view_and_copy( Kokkos::HostSpace(), a_h ); - auto a_d = Kokkos::create_mirror_view_and_copy( DeviceType(), a_h ); - auto a_h3 = Kokkos::create_mirror_view_and_copy( Kokkos::HostSpace(), a_d ); - - int equal_ptr_h_h2 = a_h.data() == a_h2.data() ? 1 : 0; - int equal_ptr_h_d = a_h.data() == a_d.data() ? 1 : 0; - int equal_ptr_h2_d = a_h2.data() == a_d.data() ? 1 : 0; - int equal_ptr_h3_d = a_h3.data() == a_d.data() ? 1 : 0; - - int is_same_memspace = std::is_same< Kokkos::HostSpace, typename DeviceType::memory_space >::value ? 1 : 0; - ASSERT_EQ( equal_ptr_h_h2, 1 ); - ASSERT_EQ( equal_ptr_h_d, is_same_memspace ); - ASSERT_EQ( equal_ptr_h2_d, is_same_memspace ); - ASSERT_EQ( equal_ptr_h3_d, is_same_memspace ); - - ASSERT_EQ( a_h.extent(0), a_h3.extent(0) ); - ASSERT_EQ( a_h.extent(0), a_h2.extent(0) ); - ASSERT_EQ( a_h.extent(0), a_d .extent(0) ); - ASSERT_EQ( a_h.rank(), a_org.rank() ); - ASSERT_EQ( a_h.rank(), a_h2.rank() ); - ASSERT_EQ( a_h.rank(), a_h3.rank() ); - ASSERT_EQ( a_h.rank(), a_d.rank() ); - ASSERT_EQ( a_org(5), a_h3(5) ); + Kokkos::DynRankView a_h = + a_org; + auto a_h2 = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), a_h); + auto a_d = Kokkos::create_mirror_view_and_copy(DeviceType(), a_h); + auto a_h3 = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), a_d); + + int equal_ptr_h_h2 = a_h.data() == a_h2.data() ? 1 : 0; + int equal_ptr_h_d = a_h.data() == a_d.data() ? 1 : 0; + int equal_ptr_h2_d = a_h2.data() == a_d.data() ? 1 : 0; + int equal_ptr_h3_d = a_h3.data() == a_d.data() ? 1 : 0; + + int is_same_memspace = + std::is_same::value + ? 1 + : 0; + ASSERT_EQ(equal_ptr_h_h2, 1); + ASSERT_EQ(equal_ptr_h_d, is_same_memspace); + ASSERT_EQ(equal_ptr_h2_d, is_same_memspace); + ASSERT_EQ(equal_ptr_h3_d, is_same_memspace); + + ASSERT_EQ(a_h.extent(0), a_h3.extent(0)); + ASSERT_EQ(a_h.extent(0), a_h2.extent(0)); + ASSERT_EQ(a_h.extent(0), a_d.extent(0)); + ASSERT_EQ(a_h.rank(), a_org.rank()); + ASSERT_EQ(a_h.rank(), a_h2.rank()); + ASSERT_EQ(a_h.rank(), a_h3.rank()); + ASSERT_EQ(a_h.rank(), a_d.rank()); + ASSERT_EQ(a_org(5), a_h3(5)); } } - static void run_test_scalar() - { - typedef typename dView0::HostMirror hView0 ; //HostMirror of DynRankView is a DynRankView + static void run_test_scalar() { + typedef typename dView0::HostMirror + hView0; // HostMirror of DynRankView is a DynRankView - dView0 dx , dy ; - hView0 hx , hy ; + dView0 dx, dy; + hView0 hx, hy; - dx = dView0( "dx" ); - dy = dView0( "dy" ); + dx = dView0("dx"); + dy = dView0("dy"); - hx = Kokkos::create_mirror( dx ); - hy = Kokkos::create_mirror( dy ); + hx = Kokkos::create_mirror(dx); + hy = Kokkos::create_mirror(dy); - hx() = 1 ; + hx() = 1; - Kokkos::deep_copy( dx , hx ); - Kokkos::deep_copy( dy , dx ); - Kokkos::deep_copy( hy , dy ); + Kokkos::deep_copy(dx, hx); + Kokkos::deep_copy(dy, dx); + Kokkos::deep_copy(hy, dy); - ASSERT_EQ( hx(), hy() ); - ASSERT_EQ( dx.rank() , hx.rank() ); - ASSERT_EQ( dy.rank() , hy.rank() ); + ASSERT_EQ(hx(), hy()); + ASSERT_EQ(dx.rank(), hx.rank()); + ASSERT_EQ(dy.rank(), hy.rank()); - //View - DynRankView Interoperability tests - // deep_copy DynRankView to View + // View - DynRankView Interoperability tests + // deep_copy DynRankView to View View0 vx("vx"); - Kokkos::deep_copy( vx , dx ); - ASSERT_EQ( rank(dx) , rank(vx) ); + Kokkos::deep_copy(vx, dx); + ASSERT_EQ(rank(dx), rank(vx)); View0 vy("vy"); - Kokkos::deep_copy( vy , dy ); - ASSERT_EQ( rank(dy) , rank(vy) ); + Kokkos::deep_copy(vy, dy); + ASSERT_EQ(rank(dy), rank(vy)); - // deep_copy View to DynRankView + // deep_copy View to DynRankView dView0 dxx("dxx"); - Kokkos::deep_copy( dxx , vx ); - ASSERT_EQ( rank(dxx) , rank(vx) ); - + Kokkos::deep_copy(dxx, vx); + ASSERT_EQ(rank(dxx), rank(vx)); View7 vcast = dx.ConstDownCast(); - ASSERT_EQ( dx.extent(0) , vcast.extent(0) ); - ASSERT_EQ( dx.extent(1) , vcast.extent(1) ); - ASSERT_EQ( dx.extent(2) , vcast.extent(2) ); - ASSERT_EQ( dx.extent(3) , vcast.extent(3) ); - ASSERT_EQ( dx.extent(4) , vcast.extent(4) ); - - View7 vcast1( dy.ConstDownCast() ); - ASSERT_EQ( dy.extent(0) , vcast1.extent(0) ); - ASSERT_EQ( dy.extent(1) , vcast1.extent(1) ); - ASSERT_EQ( dy.extent(2) , vcast1.extent(2) ); - ASSERT_EQ( dy.extent(3) , vcast1.extent(3) ); - ASSERT_EQ( dy.extent(4) , vcast1.extent(4) ); - - //View - DynRankView Interoperability tests - // copy View to DynRankView - dView0 dfromvx( vx ); - auto hmx = Kokkos::create_mirror_view(dfromvx) ; - Kokkos::deep_copy(hmx , dfromvx); - auto hvx = Kokkos::create_mirror_view(vx) ; - Kokkos::deep_copy(hvx , vx); - ASSERT_EQ( rank(hvx) , rank(hmx) ); - ASSERT_EQ( hvx.extent(0) , hmx.extent(0) ); - ASSERT_EQ( hvx.extent(1) , hmx.extent(1) ); - - // copy-assign View to DynRankView - dView0 dfromvy = vy ; - auto hmy = Kokkos::create_mirror_view(dfromvy) ; - Kokkos::deep_copy(hmy , dfromvy); - auto hvy = Kokkos::create_mirror_view(vy) ; - Kokkos::deep_copy(hvy , vy); - ASSERT_EQ( rank(hvy) , rank(hmy) ); - ASSERT_EQ( hvy.extent(0) , hmy.extent(0) ); - ASSERT_EQ( hvy.extent(1) , hmy.extent(1) ); - - - View7 vtest1("vtest1",2,2,2,2,2,2,2); - dView0 dfromv1( vtest1 ); - ASSERT_EQ( dfromv1.rank() , vtest1.Rank ); - ASSERT_EQ( dfromv1.extent(0) , vtest1.extent(0) ); - ASSERT_EQ( dfromv1.extent(1) , vtest1.extent(1) ); - ASSERT_EQ( dfromv1.use_count() , vtest1.use_count() ); - - dView0 dfromv2( vcast ); - ASSERT_EQ( dfromv2.rank() , vcast.Rank ); - ASSERT_EQ( dfromv2.extent(0) , vcast.extent(0) ); - ASSERT_EQ( dfromv2.extent(1) , vcast.extent(1) ); - ASSERT_EQ( dfromv2.use_count() , vcast.use_count() ); + ASSERT_EQ(dx.extent(0), vcast.extent(0)); + ASSERT_EQ(dx.extent(1), vcast.extent(1)); + ASSERT_EQ(dx.extent(2), vcast.extent(2)); + ASSERT_EQ(dx.extent(3), vcast.extent(3)); + ASSERT_EQ(dx.extent(4), vcast.extent(4)); + + View7 vcast1(dy.ConstDownCast()); + ASSERT_EQ(dy.extent(0), vcast1.extent(0)); + ASSERT_EQ(dy.extent(1), vcast1.extent(1)); + ASSERT_EQ(dy.extent(2), vcast1.extent(2)); + ASSERT_EQ(dy.extent(3), vcast1.extent(3)); + ASSERT_EQ(dy.extent(4), vcast1.extent(4)); + + // View - DynRankView Interoperability tests + // copy View to DynRankView + dView0 dfromvx(vx); + auto hmx = Kokkos::create_mirror_view(dfromvx); + Kokkos::deep_copy(hmx, dfromvx); + auto hvx = Kokkos::create_mirror_view(vx); + Kokkos::deep_copy(hvx, vx); + ASSERT_EQ(rank(hvx), rank(hmx)); + ASSERT_EQ(hvx.extent(0), hmx.extent(0)); + ASSERT_EQ(hvx.extent(1), hmx.extent(1)); + + // copy-assign View to DynRankView + dView0 dfromvy = vy; + auto hmy = Kokkos::create_mirror_view(dfromvy); + Kokkos::deep_copy(hmy, dfromvy); + auto hvy = Kokkos::create_mirror_view(vy); + Kokkos::deep_copy(hvy, vy); + ASSERT_EQ(rank(hvy), rank(hmy)); + ASSERT_EQ(hvy.extent(0), hmy.extent(0)); + ASSERT_EQ(hvy.extent(1), hmy.extent(1)); + + View7 vtest1("vtest1", 2, 2, 2, 2, 2, 2, 2); + dView0 dfromv1(vtest1); + ASSERT_EQ(dfromv1.rank(), vtest1.Rank); + ASSERT_EQ(dfromv1.extent(0), vtest1.extent(0)); + ASSERT_EQ(dfromv1.extent(1), vtest1.extent(1)); + ASSERT_EQ(dfromv1.use_count(), vtest1.use_count()); + + dView0 dfromv2(vcast); + ASSERT_EQ(dfromv2.rank(), vcast.Rank); + ASSERT_EQ(dfromv2.extent(0), vcast.extent(0)); + ASSERT_EQ(dfromv2.extent(1), vcast.extent(1)); + ASSERT_EQ(dfromv2.use_count(), vcast.use_count()); dView0 dfromv3 = vcast1; - ASSERT_EQ( dfromv3.rank() , vcast1.Rank ); - ASSERT_EQ( dfromv3.extent(0) , vcast1.extent(0) ); - ASSERT_EQ( dfromv3.extent(1) , vcast1.extent(1) ); - ASSERT_EQ( dfromv3.use_count() , vcast1.use_count() ); + ASSERT_EQ(dfromv3.rank(), vcast1.Rank); + ASSERT_EQ(dfromv3.extent(0), vcast1.extent(0)); + ASSERT_EQ(dfromv3.extent(1), vcast1.extent(1)); + ASSERT_EQ(dfromv3.use_count(), vcast1.use_count()); } - static void run_test() - { + static void run_test() { // mfh 14 Feb 2014: This test doesn't actually create instances of // these types. In order to avoid "declared but unused typedef" // warnings, we declare empty instances of these types, with the // usual "(void)" marker to avoid compiler warnings for unused // variables. - typedef typename dView0::HostMirror hView0 ; + typedef typename dView0::HostMirror hView0; { hView0 thing; - (void) thing; + (void)thing; } - dView0 d_uninitialized(Kokkos::ViewAllocateWithoutInitializing("uninit"),10,20); - ASSERT_TRUE( d_uninitialized.data() != nullptr ); - ASSERT_EQ( d_uninitialized.rank() , 2 ); - ASSERT_EQ( d_uninitialized.extent(0) , 10 ); - ASSERT_EQ( d_uninitialized.extent(1) , 20 ); - ASSERT_EQ( d_uninitialized.extent(2) , 1 ); - - dView0 dx , dy , dz ; - hView0 hx , hy , hz ; - - ASSERT_TRUE( Kokkos::is_dyn_rank_view::value ); - ASSERT_FALSE( Kokkos::is_dyn_rank_view< Kokkos::View >::value ); - - ASSERT_TRUE( dx.data() == 0 ); //Okay with UVM - ASSERT_TRUE( dy.data() == 0 ); //Okay with UVM - ASSERT_TRUE( dz.data() == 0 ); //Okay with UVM - ASSERT_TRUE( hx.data() == 0 ); - ASSERT_TRUE( hy.data() == 0 ); - ASSERT_TRUE( hz.data() == 0 ); - ASSERT_EQ( dx.extent(0) , 0u ); //Okay with UVM - ASSERT_EQ( dy.extent(0) , 0u ); //Okay with UVM - ASSERT_EQ( dz.extent(0) , 0u ); //Okay with UVM - ASSERT_EQ( hx.extent(0) , 0u ); - ASSERT_EQ( hy.extent(0) , 0u ); - ASSERT_EQ( hz.extent(0) , 0u ); - ASSERT_EQ( dx.rank() , 0u ); //Okay with UVM - ASSERT_EQ( hx.rank() , 0u ); - - dx = dView0( "dx" , N1 , N2 , N3 ); - dy = dView0( "dy" , N1 , N2 , N3 ); - - hx = hView0( "hx" , N1 , N2 , N3 ); - hy = hView0( "hy" , N1 , N2 , N3 ); - - ASSERT_EQ( dx.extent(0) , unsigned(N1) ); //Okay with UVM - ASSERT_EQ( dy.extent(0) , unsigned(N1) ); //Okay with UVM - ASSERT_EQ( hx.extent(0) , unsigned(N1) ); - ASSERT_EQ( hy.extent(0) , unsigned(N1) ); - ASSERT_EQ( dx.rank() , 3 ); //Okay with UVM - ASSERT_EQ( hx.rank() , 3 ); - - dx = dView0( "dx" , N0 , N1 , N2 , N3 ); - dy = dView0( "dy" , N0 , N1 , N2 , N3 ); - hx = hView0( "hx" , N0 , N1 , N2 , N3 ); - hy = hView0( "hy" , N0 , N1 , N2 , N3 ); - - ASSERT_EQ( dx.extent(0) , unsigned(N0) ); - ASSERT_EQ( dy.extent(0) , unsigned(N0) ); - ASSERT_EQ( hx.extent(0) , unsigned(N0) ); - ASSERT_EQ( hy.extent(0) , unsigned(N0) ); - ASSERT_EQ( dx.rank() , 4 ); - ASSERT_EQ( dy.rank() , 4 ); - ASSERT_EQ( hx.rank() , 4 ); - ASSERT_EQ( hy.rank() , 4 ); - - ASSERT_EQ( dx.use_count() , size_t(1) ); + dView0 d_uninitialized(Kokkos::ViewAllocateWithoutInitializing("uninit"), + 10, 20); + ASSERT_TRUE(d_uninitialized.data() != nullptr); + ASSERT_EQ(d_uninitialized.rank(), 2); + ASSERT_EQ(d_uninitialized.extent(0), 10); + ASSERT_EQ(d_uninitialized.extent(1), 20); + ASSERT_EQ(d_uninitialized.extent(2), 1); + + dView0 dx, dy, dz; + hView0 hx, hy, hz; + + ASSERT_TRUE(Kokkos::is_dyn_rank_view::value); + ASSERT_FALSE(Kokkos::is_dyn_rank_view >::value); + + ASSERT_TRUE(dx.data() == 0); // Okay with UVM + ASSERT_TRUE(dy.data() == 0); // Okay with UVM + ASSERT_TRUE(dz.data() == 0); // Okay with UVM + ASSERT_TRUE(hx.data() == 0); + ASSERT_TRUE(hy.data() == 0); + ASSERT_TRUE(hz.data() == 0); + ASSERT_EQ(dx.extent(0), 0u); // Okay with UVM + ASSERT_EQ(dy.extent(0), 0u); // Okay with UVM + ASSERT_EQ(dz.extent(0), 0u); // Okay with UVM + ASSERT_EQ(hx.extent(0), 0u); + ASSERT_EQ(hy.extent(0), 0u); + ASSERT_EQ(hz.extent(0), 0u); + ASSERT_EQ(dx.rank(), 0u); // Okay with UVM + ASSERT_EQ(hx.rank(), 0u); + + dx = dView0("dx", N1, N2, N3); + dy = dView0("dy", N1, N2, N3); + + hx = hView0("hx", N1, N2, N3); + hy = hView0("hy", N1, N2, N3); + + ASSERT_EQ(dx.extent(0), unsigned(N1)); // Okay with UVM + ASSERT_EQ(dy.extent(0), unsigned(N1)); // Okay with UVM + ASSERT_EQ(hx.extent(0), unsigned(N1)); + ASSERT_EQ(hy.extent(0), unsigned(N1)); + ASSERT_EQ(dx.rank(), 3); // Okay with UVM + ASSERT_EQ(hx.rank(), 3); + + dx = dView0("dx", N0, N1, N2, N3); + dy = dView0("dy", N0, N1, N2, N3); + hx = hView0("hx", N0, N1, N2, N3); + hy = hView0("hy", N0, N1, N2, N3); + + ASSERT_EQ(dx.extent(0), unsigned(N0)); + ASSERT_EQ(dy.extent(0), unsigned(N0)); + ASSERT_EQ(hx.extent(0), unsigned(N0)); + ASSERT_EQ(hy.extent(0), unsigned(N0)); + ASSERT_EQ(dx.rank(), 4); + ASSERT_EQ(dy.rank(), 4); + ASSERT_EQ(hx.rank(), 4); + ASSERT_EQ(hy.rank(), 4); + + ASSERT_EQ(dx.use_count(), size_t(1)); dView0_unmanaged unmanaged_dx = dx; - ASSERT_EQ( dx.use_count() , size_t(1) ); - - - dView0_unmanaged unmanaged_from_ptr_dx = dView0_unmanaged(dx.data(), - dx.extent(0), - dx.extent(1), - dx.extent(2), - dx.extent(3)); + ASSERT_EQ(dx.use_count(), size_t(1)); + dView0_unmanaged unmanaged_from_ptr_dx = dView0_unmanaged( + dx.data(), dx.extent(0), dx.extent(1), dx.extent(2), dx.extent(3)); { // Destruction of this view should be harmless - const_dView0 unmanaged_from_ptr_const_dx( dx.data() , - dx.extent(0) , - dx.extent(1) , - dx.extent(2) , - dx.extent(3) ); + const_dView0 unmanaged_from_ptr_const_dx( + dx.data(), dx.extent(0), dx.extent(1), dx.extent(2), dx.extent(3)); } - const_dView0 const_dx = dx ; - ASSERT_EQ( dx.use_count() , size_t(2) ); + const_dView0 const_dx = dx; + ASSERT_EQ(dx.use_count(), size_t(2)); { const_dView0 const_dx2; const_dx2 = const_dx; - ASSERT_EQ( dx.use_count() , size_t(3) ); + ASSERT_EQ(dx.use_count(), size_t(3)); const_dx2 = dy; - ASSERT_EQ( dx.use_count() , size_t(2) ); + ASSERT_EQ(dx.use_count(), size_t(2)); const_dView0 const_dx3(dx); - ASSERT_EQ( dx.use_count() , size_t(3) ); - + ASSERT_EQ(dx.use_count(), size_t(3)); + dView0_unmanaged dx4_unmanaged(dx); - ASSERT_EQ( dx.use_count() , size_t(3) ); + ASSERT_EQ(dx.use_count(), size_t(3)); } - ASSERT_EQ( dx.use_count() , size_t(2) ); - + ASSERT_EQ(dx.use_count(), size_t(2)); - ASSERT_FALSE( dx.data() == 0 ); - ASSERT_FALSE( const_dx.data() == 0 ); - ASSERT_FALSE( unmanaged_dx.data() == 0 ); - ASSERT_FALSE( unmanaged_from_ptr_dx.data() == 0 ); - ASSERT_FALSE( dy.data() == 0 ); - ASSERT_NE( dx , dy ); + ASSERT_FALSE(dx.data() == 0); + ASSERT_FALSE(const_dx.data() == 0); + ASSERT_FALSE(unmanaged_dx.data() == 0); + ASSERT_FALSE(unmanaged_from_ptr_dx.data() == 0); + ASSERT_FALSE(dy.data() == 0); + ASSERT_NE(dx, dy); - ASSERT_EQ( dx.extent(0) , unsigned(N0) ); - ASSERT_EQ( dx.extent(1) , unsigned(N1) ); - ASSERT_EQ( dx.extent(2) , unsigned(N2) ); - ASSERT_EQ( dx.extent(3) , unsigned(N3) ); + ASSERT_EQ(dx.extent(0), unsigned(N0)); + ASSERT_EQ(dx.extent(1), unsigned(N1)); + ASSERT_EQ(dx.extent(2), unsigned(N2)); + ASSERT_EQ(dx.extent(3), unsigned(N3)); - ASSERT_EQ( dy.extent(0) , unsigned(N0) ); - ASSERT_EQ( dy.extent(1) , unsigned(N1) ); - ASSERT_EQ( dy.extent(2) , unsigned(N2) ); - ASSERT_EQ( dy.extent(3) , unsigned(N3) ); + ASSERT_EQ(dy.extent(0), unsigned(N0)); + ASSERT_EQ(dy.extent(1), unsigned(N1)); + ASSERT_EQ(dy.extent(2), unsigned(N2)); + ASSERT_EQ(dy.extent(3), unsigned(N3)); - ASSERT_EQ( unmanaged_from_ptr_dx.span(),unsigned(N0)*unsigned(N1)*unsigned(N2)*unsigned(N3) ); + ASSERT_EQ(unmanaged_from_ptr_dx.span(), + unsigned(N0) * unsigned(N1) * unsigned(N2) * unsigned(N3)); - hx = Kokkos::create_mirror( dx ); - hy = Kokkos::create_mirror( dy ); + hx = Kokkos::create_mirror(dx); + hy = Kokkos::create_mirror(dy); - ASSERT_EQ( hx.rank() , dx.rank() ); - ASSERT_EQ( hy.rank() , dy.rank() ); + ASSERT_EQ(hx.rank(), dx.rank()); + ASSERT_EQ(hy.rank(), dy.rank()); - ASSERT_EQ( hx.extent(0) , unsigned(N0) ); - ASSERT_EQ( hx.extent(1) , unsigned(N1) ); - ASSERT_EQ( hx.extent(2) , unsigned(N2) ); - ASSERT_EQ( hx.extent(3) , unsigned(N3) ); + ASSERT_EQ(hx.extent(0), unsigned(N0)); + ASSERT_EQ(hx.extent(1), unsigned(N1)); + ASSERT_EQ(hx.extent(2), unsigned(N2)); + ASSERT_EQ(hx.extent(3), unsigned(N3)); - ASSERT_EQ( hy.extent(0) , unsigned(N0) ); - ASSERT_EQ( hy.extent(1) , unsigned(N1) ); - ASSERT_EQ( hy.extent(2) , unsigned(N2) ); - ASSERT_EQ( hy.extent(3) , unsigned(N3) ); + ASSERT_EQ(hy.extent(0), unsigned(N0)); + ASSERT_EQ(hy.extent(1), unsigned(N1)); + ASSERT_EQ(hy.extent(2), unsigned(N2)); + ASSERT_EQ(hy.extent(3), unsigned(N3)); // T v1 = hx() ; // Generates compile error as intended // T v2 = hx(0,0) ; // Generates compile error as intended @@ -1265,365 +1263,422 @@ public: // Testing with synchronous deep copy { - size_t count = 0 ; - for ( size_t ip = 0 ; ip < N0 ; ++ip ) { - for ( size_t i1 = 0 ; i1 < hx.extent(1) ; ++i1 ) { - for ( size_t i2 = 0 ; i2 < hx.extent(2) ; ++i2 ) { - for ( size_t i3 = 0 ; i3 < hx.extent(3) ; ++i3 ) { - hx(ip,i1,i2,i3) = ++count ; - }}}} - - Kokkos::deep_copy( dx , hx ); - Kokkos::deep_copy( dy , dx ); - Kokkos::deep_copy( hy , dy ); + size_t count = 0; + for (size_t ip = 0; ip < N0; ++ip) { + for (size_t i1 = 0; i1 < hx.extent(1); ++i1) { + for (size_t i2 = 0; i2 < hx.extent(2); ++i2) { + for (size_t i3 = 0; i3 < hx.extent(3); ++i3) { + hx(ip, i1, i2, i3) = ++count; + } + } + } + } + + Kokkos::deep_copy(dx, hx); + Kokkos::deep_copy(dy, dx); + Kokkos::deep_copy(hy, dy); Kokkos::fence(); - for ( size_t ip = 0 ; ip < N0 ; ++ip ) { - for ( size_t i1 = 0 ; i1 < N1 ; ++i1 ) { - for ( size_t i2 = 0 ; i2 < N2 ; ++i2 ) { - for ( size_t i3 = 0 ; i3 < N3 ; ++i3 ) { - { ASSERT_EQ( hx(ip,i1,i2,i3) , hy(ip,i1,i2,i3) ); } - }}}} - - Kokkos::deep_copy( dx , T(0) ); - Kokkos::deep_copy( hx , dx ); + for (size_t ip = 0; ip < N0; ++ip) { + for (size_t i1 = 0; i1 < N1; ++i1) { + for (size_t i2 = 0; i2 < N2; ++i2) { + for (size_t i3 = 0; i3 < N3; ++i3) { + { + ASSERT_EQ(hx(ip, i1, i2, i3), hy(ip, i1, i2, i3)); + } + } + } + } + } + + Kokkos::deep_copy(dx, T(0)); + Kokkos::deep_copy(hx, dx); Kokkos::fence(); - for ( size_t ip = 0 ; ip < N0 ; ++ip ) { - for ( size_t i1 = 0 ; i1 < N1 ; ++i1 ) { - for ( size_t i2 = 0 ; i2 < N2 ; ++i2 ) { - for ( size_t i3 = 0 ; i3 < N3 ; ++i3 ) { - { ASSERT_EQ( hx(ip,i1,i2,i3) , T(0) ); } - }}}} -// ASSERT_EQ( hx(0,0,0,0,0,0,0,0) , T(0) ); //Test rank8 op behaves properly - if implemented + for (size_t ip = 0; ip < N0; ++ip) { + for (size_t i1 = 0; i1 < N1; ++i1) { + for (size_t i2 = 0; i2 < N2; ++i2) { + for (size_t i3 = 0; i3 < N3; ++i3) { + { + ASSERT_EQ(hx(ip, i1, i2, i3), T(0)); + } + } + } + } + } + // ASSERT_EQ( hx(0,0,0,0,0,0,0,0) , T(0) ); //Test rank8 op behaves + // properly - if implemented } - dz = dx ; ASSERT_EQ( dx, dz); ASSERT_NE( dy, dz); - dz = dy ; ASSERT_EQ( dy, dz); ASSERT_NE( dx, dz); + dz = dx; + ASSERT_EQ(dx, dz); + ASSERT_NE(dy, dz); + dz = dy; + ASSERT_EQ(dy, dz); + ASSERT_NE(dx, dz); dx = dView0(); - ASSERT_TRUE( dx.data() == 0 ); - ASSERT_FALSE( dy.data() == 0 ); - ASSERT_FALSE( dz.data() == 0 ); + ASSERT_TRUE(dx.data() == 0); + ASSERT_FALSE(dy.data() == 0); + ASSERT_FALSE(dz.data() == 0); dy = dView0(); - ASSERT_TRUE( dx.data() == 0 ); - ASSERT_TRUE( dy.data() == 0 ); - ASSERT_FALSE( dz.data() == 0 ); + ASSERT_TRUE(dx.data() == 0); + ASSERT_TRUE(dy.data() == 0); + ASSERT_FALSE(dz.data() == 0); dz = dView0(); - ASSERT_TRUE( dx.data() == 0 ); - ASSERT_TRUE( dy.data() == 0 ); - ASSERT_TRUE( dz.data() == 0 ); + ASSERT_TRUE(dx.data() == 0); + ASSERT_TRUE(dy.data() == 0); + ASSERT_TRUE(dz.data() == 0); - //View - DynRankView Interoperability tests + // View - DynRankView Interoperability tests // deep_copy from view to dynrankview const int testdim = 4; - dView0 dxx("dxx",testdim); - View1 vxx("vxx",testdim); - auto hvxx = Kokkos::create_mirror_view(vxx); - for (int i = 0; i < testdim; ++i) - { hvxx(i) = i; } - Kokkos::deep_copy(vxx,hvxx); - Kokkos::deep_copy(dxx,vxx); + dView0 dxx("dxx", testdim); + View1 vxx("vxx", testdim); + auto hvxx = Kokkos::create_mirror_view(vxx); + for (int i = 0; i < testdim; ++i) { + hvxx(i) = i; + } + Kokkos::deep_copy(vxx, hvxx); + Kokkos::deep_copy(dxx, vxx); auto hdxx = Kokkos::create_mirror_view(dxx); - Kokkos::deep_copy(hdxx,dxx); - for (int i = 0; i < testdim; ++i) - { ASSERT_EQ( hvxx(i) , hdxx(i) ); } + Kokkos::deep_copy(hdxx, dxx); + for (int i = 0; i < testdim; ++i) { + ASSERT_EQ(hvxx(i), hdxx(i)); + } - ASSERT_EQ( rank(hdxx) , rank(hvxx) ); - ASSERT_EQ( hdxx.extent(0) , testdim ); - ASSERT_EQ( hdxx.extent(0) , hvxx.extent(0) ); + ASSERT_EQ(rank(hdxx), rank(hvxx)); + ASSERT_EQ(hdxx.extent(0), testdim); + ASSERT_EQ(hdxx.extent(0), hvxx.extent(0)); // deep_copy from dynrankview to view - View1 vdxx("vdxx",testdim); + View1 vdxx("vdxx", testdim); auto hvdxx = Kokkos::create_mirror_view(vdxx); - Kokkos::deep_copy(hvdxx , hdxx); - ASSERT_EQ( rank(hdxx) , rank(hvdxx) ); - ASSERT_EQ( hvdxx.extent(0) , testdim ); - ASSERT_EQ( hdxx.extent(0) , hvdxx.extent(0) ); - for (int i = 0; i < testdim; ++i) - { ASSERT_EQ( hvxx(i) , hvdxx(i) ); } + Kokkos::deep_copy(hvdxx, hdxx); + ASSERT_EQ(rank(hdxx), rank(hvdxx)); + ASSERT_EQ(hvdxx.extent(0), testdim); + ASSERT_EQ(hdxx.extent(0), hvdxx.extent(0)); + for (int i = 0; i < testdim; ++i) { + ASSERT_EQ(hvxx(i), hvdxx(i)); + } } - typedef T DataType ; + typedef T DataType; - static void - check_auto_conversion_to_const( - const Kokkos::DynRankView< const DataType , device > & arg_const , - const Kokkos::DynRankView< DataType , device > & arg ) - { - ASSERT_TRUE( arg_const == arg ); + static void check_auto_conversion_to_const( + const Kokkos::DynRankView& arg_const, + const Kokkos::DynRankView& arg) { + ASSERT_TRUE(arg_const == arg); } - static void run_test_const() - { - typedef Kokkos::DynRankView< DataType , device > typeX ; - typedef Kokkos::DynRankView< const DataType , device > const_typeX ; - typedef Kokkos::DynRankView< const DataType , device , Kokkos::MemoryRandomAccess > const_typeR ; - typeX x( "X", 2 ); - const_typeX xc = x ; - const_typeR xr = x ; + static void run_test_const() { + typedef Kokkos::DynRankView typeX; + typedef Kokkos::DynRankView const_typeX; + typedef Kokkos::DynRankView + const_typeR; + typeX x("X", 2); + const_typeX xc = x; + const_typeR xr = x; - ASSERT_TRUE( xc == x ); - ASSERT_TRUE( x == xc ); + ASSERT_TRUE(xc == x); + ASSERT_TRUE(x == xc); // For CUDA the constant random access View does not return // an lvalue reference due to retrieving through texture cache // therefore not allowed to query the underlying pointer. #if defined(KOKKOS_ENABLE_CUDA) - if ( ! std::is_same< typename device::execution_space , Kokkos::Cuda >::value ) + if (!std::is_same::value) #endif { - ASSERT_TRUE( x.data() == xr.data() ); + ASSERT_TRUE(x.data() == xr.data()); } // typeX xf = xc ; // setting non-const from const must not compile - check_auto_conversion_to_const( x , x ); + check_auto_conversion_to_const(x, x); } - - static void run_test_subview() - { - typedef Kokkos::DynRankView< const T , device > cdView ; - typedef Kokkos::DynRankView< T , device > dView ; - // LayoutStride required for all returned DynRankView subdynrankview's - typedef Kokkos::DynRankView< T , Kokkos::LayoutStride , device > sdView ; - - dView0 d0( "d0" ); - cdView s0 = d0 ; - - // N0 = 1000,N1 = 3,N2 = 5,N3 = 7 - unsigned order[] = { 6,5,4,3,2,1,0 }, dimen[] = { N0, N1, N2, 2, 2, 2, 2 }; //LayoutRight equivalent - sdView d7( "d7" , Kokkos::LayoutStride::order_dimensions(7, order, dimen) ); - ASSERT_EQ( d7.rank() , 7 ); - - sdView ds0 = Kokkos::subdynrankview( d7 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ); - ASSERT_EQ( ds0.rank() , 0 ); - -//Basic test - ALL - sdView dsALL = Kokkos::subdynrankview( d7 , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() ); - ASSERT_EQ( dsALL.rank() , 7 ); - -// Send a value to final rank returning rank 6 subview - sdView dsm1 = Kokkos::subdynrankview( d7 , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , 1 ); - ASSERT_EQ( dsm1.rank() , 6 ); - -// Send a std::pair as argument to a rank - sdView dssp = Kokkos::subdynrankview( d7 , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , std::pair(1,2) ); - ASSERT_EQ( dssp.rank() , 7 ); - -// Send a kokkos::pair as argument to a rank; take default layout as input - dView0 dd0("dd0" , N0 , N1 , N2 , 2 , 2 , 2 , 2 ); //default layout - ASSERT_EQ( dd0.rank() , 7 ); - sdView dtkp = Kokkos::subdynrankview( dd0 , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::pair(0,1) ); - ASSERT_EQ( dtkp.rank() , 7 ); - -// Return rank 7 subview, taking a pair as one argument, layout stride input - sdView ds7 = Kokkos::subdynrankview( d7 , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::pair(0,1) ); - ASSERT_EQ( ds7.rank() , 7 ); - -// Default Layout DynRankView - dView dv6("dv6" , N0 , N1 , N2 , N3 , 2 , 2 ); - ASSERT_EQ( dv6.rank() , 6 ); - -// DynRankView with LayoutRight - typedef Kokkos::DynRankView< T , Kokkos::LayoutRight , device > drView ; - drView dr5( "dr5" , N0 , N1 , N2 , 2 , 2 ); - ASSERT_EQ( dr5.rank() , 5 ); - -// LayoutStride but arranged as LayoutRight - // NOTE: unused arg_layout dimensions must be set toKOKKOS_INVALID_INDEX so that - // rank deduction can properly take place - unsigned order5[] = { 4,3,2,1,0 }, dimen5[] = { N0, N1, N2, 2, 2 }; - Kokkos::LayoutStride ls = Kokkos::LayoutStride::order_dimensions(5, order5, dimen5); - ls.dimension[5] =KOKKOS_INVALID_INDEX; - ls.dimension[6] =KOKKOS_INVALID_INDEX; - ls.dimension[7] =KOKKOS_INVALID_INDEX; + static void run_test_subview() { + typedef Kokkos::DynRankView cdView; + typedef Kokkos::DynRankView dView; + // LayoutStride required for all returned DynRankView subdynrankview's + typedef Kokkos::DynRankView sdView; + + dView0 d0("d0"); + cdView s0 = d0; + + // N0 = 1000,N1 = 3,N2 = 5,N3 = 7 + unsigned order[] = {6, 5, 4, 3, 2, 1, 0}, + dimen[] = {N0, N1, N2, 2, 2, 2, 2}; // LayoutRight equivalent + sdView d7("d7", Kokkos::LayoutStride::order_dimensions(7, order, dimen)); + ASSERT_EQ(d7.rank(), 7); + + sdView ds0 = Kokkos::subdynrankview(d7, 1, 1, 1, 1, 1, 1, 1); + ASSERT_EQ(ds0.rank(), 0); + + // Basic test - ALL + sdView dsALL = Kokkos::subdynrankview( + d7, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), + Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL()); + ASSERT_EQ(dsALL.rank(), 7); + + // Send a value to final rank returning rank 6 subview + sdView dsm1 = + Kokkos::subdynrankview(d7, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), + Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), 1); + ASSERT_EQ(dsm1.rank(), 6); + + // Send a std::pair as argument to a rank + sdView dssp = Kokkos::subdynrankview( + d7, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), + Kokkos::ALL(), Kokkos::ALL(), std::pair(1, 2)); + ASSERT_EQ(dssp.rank(), 7); + + // Send a kokkos::pair as argument to a rank; take default layout as input + dView0 dd0("dd0", N0, N1, N2, 2, 2, 2, 2); // default layout + ASSERT_EQ(dd0.rank(), 7); + sdView dtkp = Kokkos::subdynrankview( + dd0, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), + Kokkos::ALL(), Kokkos::ALL(), Kokkos::pair(0, 1)); + ASSERT_EQ(dtkp.rank(), 7); + + // Return rank 7 subview, taking a pair as one argument, layout stride input + sdView ds7 = Kokkos::subdynrankview( + d7, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), + Kokkos::ALL(), Kokkos::ALL(), Kokkos::pair(0, 1)); + ASSERT_EQ(ds7.rank(), 7); + + // Default Layout DynRankView + dView dv6("dv6", N0, N1, N2, N3, 2, 2); + ASSERT_EQ(dv6.rank(), 6); + + // DynRankView with LayoutRight + typedef Kokkos::DynRankView drView; + drView dr5("dr5", N0, N1, N2, 2, 2); + ASSERT_EQ(dr5.rank(), 5); + + // LayoutStride but arranged as LayoutRight + // NOTE: unused arg_layout dimensions must be set toKOKKOS_INVALID_INDEX so + // that + // rank deduction can properly take place + unsigned order5[] = {4, 3, 2, 1, 0}, dimen5[] = {N0, N1, N2, 2, 2}; + Kokkos::LayoutStride ls = + Kokkos::LayoutStride::order_dimensions(5, order5, dimen5); + ls.dimension[5] = KOKKOS_INVALID_INDEX; + ls.dimension[6] = KOKKOS_INVALID_INDEX; + ls.dimension[7] = KOKKOS_INVALID_INDEX; sdView d5("d5", ls); - ASSERT_EQ( d5.rank() , 5 ); - -// LayoutStride arranged as LayoutRight - commented out as example that fails unit test -// unsigned order5[] = { 4,3,2,1,0 }, dimen5[] = { N0, N1, N2, 2, 2 }; -// sdView d5( "d5" , Kokkos::LayoutStride::order_dimensions(5, order5, dimen5) ); -// -// Fails the following unit test: -// ASSERT_EQ( d5.rank() , dr5.rank() ); -// -// Explanation: In construction of the Kokkos::LayoutStride below, since the -// remaining dimensions are not specified, they will default to values of 0 -// rather thanKOKKOS_INVALID_INDEX. -// When passed to the DynRankView constructor the default dimensions (of 0) -// will be counted toward the dynamic rank and returning an incorrect value -// (i.e. rank 7 rather than 5). - -// Check LayoutRight dr5 and LayoutStride d5 dimensions agree (as they should) - ASSERT_EQ( d5.extent(0) , dr5.extent(0) ); - ASSERT_EQ( d5.extent(1) , dr5.extent(1) ); - ASSERT_EQ( d5.extent(2) , dr5.extent(2) ); - ASSERT_EQ( d5.extent(3) , dr5.extent(3) ); - ASSERT_EQ( d5.extent(4) , dr5.extent(4) ); - ASSERT_EQ( d5.extent(5) , dr5.extent(5) ); - ASSERT_EQ( d5.rank() , dr5.rank() ); - -// Rank 5 subview of rank 5 dynamic rank view, layout stride input - sdView ds5 = Kokkos::subdynrankview( d5 , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::pair(0,1) ); - ASSERT_EQ( ds5.rank() , 5 ); - -// Pass in extra ALL arguments beyond the rank of the DynRank View. -// This behavior is allowed - ignore the extra ALL arguments when -// the src.rank() < number of arguments, but be careful! - sdView ds5plus = Kokkos::subdynrankview( d5 , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::pair(0,1) , Kokkos::ALL() ); - - ASSERT_EQ( ds5.rank() , ds5plus.rank() ); - ASSERT_EQ( ds5.extent(0) , ds5plus.extent(0) ); - ASSERT_EQ( ds5.extent(4) , ds5plus.extent(4) ); - ASSERT_EQ( ds5.extent(5) , ds5plus.extent(5) ); - -#if ! defined( KOKKOS_ENABLE_CUDA ) || defined ( KOKKOS_ENABLE_CUDA_UVM ) - ASSERT_EQ( & ds5(1,1,1,1,0) - & ds5plus(1,1,1,1,0) , 0 ); - ASSERT_EQ( & ds5(1,1,1,1,0,0) - & ds5plus(1,1,1,1,0,0) , 0 ); // passing argument to rank beyond the view's rank is allowed iff it is a 0. + ASSERT_EQ(d5.rank(), 5); + + // LayoutStride arranged as LayoutRight - commented out as example that + // fails unit test + // unsigned order5[] = { 4,3,2,1,0 }, dimen5[] = { N0, N1, N2, 2, 2 }; + // sdView d5( "d5" , Kokkos::LayoutStride::order_dimensions(5, order5, + // dimen5) ); + // + // Fails the following unit test: + // ASSERT_EQ( d5.rank() , dr5.rank() ); + // + // Explanation: In construction of the Kokkos::LayoutStride below, since + // the + // remaining dimensions are not specified, they will default to values of + // 0 rather thanKOKKOS_INVALID_INDEX. + // When passed to the DynRankView constructor the default dimensions (of 0) + // will be counted toward the dynamic rank and returning an incorrect + // value (i.e. rank 7 rather than 5). + + // Check LayoutRight dr5 and LayoutStride d5 dimensions agree (as they + // should) + ASSERT_EQ(d5.extent(0), dr5.extent(0)); + ASSERT_EQ(d5.extent(1), dr5.extent(1)); + ASSERT_EQ(d5.extent(2), dr5.extent(2)); + ASSERT_EQ(d5.extent(3), dr5.extent(3)); + ASSERT_EQ(d5.extent(4), dr5.extent(4)); + ASSERT_EQ(d5.extent(5), dr5.extent(5)); + ASSERT_EQ(d5.rank(), dr5.rank()); + + // Rank 5 subview of rank 5 dynamic rank view, layout stride input + sdView ds5 = Kokkos::subdynrankview(d5, Kokkos::ALL(), Kokkos::ALL(), + Kokkos::ALL(), Kokkos::ALL(), + Kokkos::pair(0, 1)); + ASSERT_EQ(ds5.rank(), 5); + + // Pass in extra ALL arguments beyond the rank of the DynRank View. + // This behavior is allowed - ignore the extra ALL arguments when + // the src.rank() < number of arguments, but be careful! + sdView ds5plus = Kokkos::subdynrankview( + d5, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), + Kokkos::pair(0, 1), Kokkos::ALL()); + + ASSERT_EQ(ds5.rank(), ds5plus.rank()); + ASSERT_EQ(ds5.extent(0), ds5plus.extent(0)); + ASSERT_EQ(ds5.extent(4), ds5plus.extent(4)); + ASSERT_EQ(ds5.extent(5), ds5plus.extent(5)); + +#if !defined(KOKKOS_ENABLE_CUDA) || defined(KOKKOS_ENABLE_CUDA_UVM) + ASSERT_EQ(&ds5(1, 1, 1, 1, 0) - &ds5plus(1, 1, 1, 1, 0), 0); + ASSERT_EQ(&ds5(1, 1, 1, 1, 0, 0) - &ds5plus(1, 1, 1, 1, 0, 0), + 0); // passing argument to rank beyond the view's rank is allowed + // iff it is a 0. #endif -// Similar test to rank 5 above, but create rank 4 subview -// Check that the rank contracts (ds4 and ds4plus) and that subdynrankview can accept extra args (ds4plus) - sdView ds4 = Kokkos::subdynrankview( d5 , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , 0 ); - sdView ds4plus = Kokkos::subdynrankview( d5 , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , 0 , Kokkos::ALL() ); - - ASSERT_EQ( ds4.rank() , ds4plus.rank() ); - ASSERT_EQ( ds4.rank() , 4 ); - ASSERT_EQ( ds4.extent(0) , ds4plus.extent(0) ); - ASSERT_EQ( ds4.extent(4) , ds4plus.extent(4) ); - ASSERT_EQ( ds4.extent(5) , ds4plus.extent(5) ); + // Similar test to rank 5 above, but create rank 4 subview + // Check that the rank contracts (ds4 and ds4plus) and that subdynrankview + // can accept extra args (ds4plus) + sdView ds4 = Kokkos::subdynrankview(d5, Kokkos::ALL(), Kokkos::ALL(), + Kokkos::ALL(), Kokkos::ALL(), 0); + sdView ds4plus = + Kokkos::subdynrankview(d5, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), + Kokkos::ALL(), 0, Kokkos::ALL()); + + ASSERT_EQ(ds4.rank(), ds4plus.rank()); + ASSERT_EQ(ds4.rank(), 4); + ASSERT_EQ(ds4.extent(0), ds4plus.extent(0)); + ASSERT_EQ(ds4.extent(4), ds4plus.extent(4)); + ASSERT_EQ(ds4.extent(5), ds4plus.extent(5)); } - static void run_test_subview_strided() - { - typedef Kokkos::DynRankView < int , Kokkos::LayoutLeft , host_drv_space > drview_left ; - typedef Kokkos::DynRankView < int , Kokkos::LayoutRight , host_drv_space > drview_right ; - typedef Kokkos::DynRankView < int , Kokkos::LayoutStride , host_drv_space > drview_stride ; - - drview_left xl2( "xl2", 100 , 200 ); - drview_right xr2( "xr2", 100 , 200 ); - drview_stride yl1 = Kokkos::subdynrankview( xl2 , 0 , Kokkos::ALL() ); - drview_stride yl2 = Kokkos::subdynrankview( xl2 , 1 , Kokkos::ALL() ); - drview_stride ys1 = Kokkos::subdynrankview( xr2 , 0 , Kokkos::ALL() ); - drview_stride ys2 = Kokkos::subdynrankview( xr2 , 1 , Kokkos::ALL() ); - drview_stride yr1 = Kokkos::subdynrankview( xr2 , 0 , Kokkos::ALL() ); - drview_stride yr2 = Kokkos::subdynrankview( xr2 , 1 , Kokkos::ALL() ); - - ASSERT_EQ( yl1.extent(0) , xl2.extent(1) ); - ASSERT_EQ( yl2.extent(0) , xl2.extent(1) ); - - ASSERT_EQ( yr1.extent(0) , xr2.extent(1) ); - ASSERT_EQ( yr2.extent(0) , xr2.extent(1) ); - - ASSERT_EQ( & yl1(0) - & xl2(0,0) , 0 ); - ASSERT_EQ( & yl2(0) - & xl2(1,0) , 0 ); - ASSERT_EQ( & yr1(0) - & xr2(0,0) , 0 ); - ASSERT_EQ( & yr2(0) - & xr2(1,0) , 0 ); - - - drview_left xl4( "xl4", 10 , 20 , 30 , 40 ); - drview_right xr4( "xr4", 10 , 20 , 30 , 40 ); - - //Replace subdynrankview with subview - test - drview_stride yl4 = Kokkos::subview( xl4 , 1 , Kokkos::ALL() , 2 , Kokkos::ALL() ); - drview_stride yr4 = Kokkos::subview( xr4 , 1 , Kokkos::ALL() , 2 , Kokkos::ALL() ); - - ASSERT_EQ( yl4.extent(0) , xl4.extent(1) ); - ASSERT_EQ( yl4.extent(1) , xl4.extent(3) ); - ASSERT_EQ( yr4.extent(0) , xr4.extent(1) ); - ASSERT_EQ( yr4.extent(1) , xr4.extent(3) ); - ASSERT_EQ( yl4.rank() , 2); - ASSERT_EQ( yr4.rank() , 2); - - ASSERT_EQ( & yl4(4,4) - & xl4(1,4,2,4) , 0 ); - ASSERT_EQ( & yr4(4,4) - & xr4(1,4,2,4) , 0 ); + static void run_test_subview_strided() { + typedef Kokkos::DynRankView + drview_left; + typedef Kokkos::DynRankView + drview_right; + typedef Kokkos::DynRankView + drview_stride; + + drview_left xl2("xl2", 100, 200); + drview_right xr2("xr2", 100, 200); + drview_stride yl1 = Kokkos::subdynrankview(xl2, 0, Kokkos::ALL()); + drview_stride yl2 = Kokkos::subdynrankview(xl2, 1, Kokkos::ALL()); + drview_stride ys1 = Kokkos::subdynrankview(xr2, 0, Kokkos::ALL()); + drview_stride ys2 = Kokkos::subdynrankview(xr2, 1, Kokkos::ALL()); + drview_stride yr1 = Kokkos::subdynrankview(xr2, 0, Kokkos::ALL()); + drview_stride yr2 = Kokkos::subdynrankview(xr2, 1, Kokkos::ALL()); + + ASSERT_EQ(yl1.extent(0), xl2.extent(1)); + ASSERT_EQ(yl2.extent(0), xl2.extent(1)); + + ASSERT_EQ(yr1.extent(0), xr2.extent(1)); + ASSERT_EQ(yr2.extent(0), xr2.extent(1)); + + ASSERT_EQ(&yl1(0) - &xl2(0, 0), 0); + ASSERT_EQ(&yl2(0) - &xl2(1, 0), 0); + ASSERT_EQ(&yr1(0) - &xr2(0, 0), 0); + ASSERT_EQ(&yr2(0) - &xr2(1, 0), 0); + + drview_left xl4("xl4", 10, 20, 30, 40); + drview_right xr4("xr4", 10, 20, 30, 40); + + // Replace subdynrankview with subview - test + drview_stride yl4 = + Kokkos::subview(xl4, 1, Kokkos::ALL(), 2, Kokkos::ALL()); + drview_stride yr4 = + Kokkos::subview(xr4, 1, Kokkos::ALL(), 2, Kokkos::ALL()); + + ASSERT_EQ(yl4.extent(0), xl4.extent(1)); + ASSERT_EQ(yl4.extent(1), xl4.extent(3)); + ASSERT_EQ(yr4.extent(0), xr4.extent(1)); + ASSERT_EQ(yr4.extent(1), xr4.extent(3)); + ASSERT_EQ(yl4.rank(), 2); + ASSERT_EQ(yr4.rank(), 2); + + ASSERT_EQ(&yl4(4, 4) - &xl4(1, 4, 2, 4), 0); + ASSERT_EQ(&yr4(4, 4) - &xr4(1, 4, 2, 4), 0); } - static void run_test_vector() - { - static const unsigned Length = 1000 , Count = 8 ; - - typedef typename Kokkos::DynRankView< T , Kokkos::LayoutLeft , host_drv_space > multivector_type ; - - typedef typename Kokkos::DynRankView< T , Kokkos::LayoutRight , host_drv_space > multivector_right_type ; - - multivector_type mv = multivector_type( "mv" , Length , Count ); - multivector_right_type mv_right = multivector_right_type( "mv" , Length , Count ); - - typedef typename Kokkos::DynRankView< T , Kokkos::LayoutStride , host_drv_space > svector_type ; - typedef typename Kokkos::DynRankView< T , Kokkos::LayoutStride , host_drv_space > smultivector_type ; - typedef typename Kokkos::DynRankView< const T , Kokkos::LayoutStride , host_drv_space > const_svector_right_type ; - typedef typename Kokkos::DynRankView< const T , Kokkos::LayoutStride , host_drv_space > const_svector_type ; - typedef typename Kokkos::DynRankView< const T , Kokkos::LayoutStride , host_drv_space > const_smultivector_type ; - - svector_type v1 = Kokkos::subdynrankview( mv , Kokkos::ALL() , 0 ); - svector_type v2 = Kokkos::subdynrankview( mv , Kokkos::ALL() , 1 ); - svector_type v3 = Kokkos::subdynrankview( mv , Kokkos::ALL() , 2 ); - - svector_type rv1 = Kokkos::subdynrankview( mv_right , 0 , Kokkos::ALL() ); - svector_type rv2 = Kokkos::subdynrankview( mv_right , 1 , Kokkos::ALL() ); - svector_type rv3 = Kokkos::subdynrankview( mv_right , 2 , Kokkos::ALL() ); - - smultivector_type mv1 = Kokkos::subdynrankview( mv , std::make_pair( 1 , 998 ) , - std::make_pair( 2 , 5 ) ); - - smultivector_type mvr1 = - Kokkos::subdynrankview( mv_right , - std::make_pair( 1 , 998 ) , - std::make_pair( 2 , 5 ) ); - - const_svector_type cv1 = Kokkos::subdynrankview( mv , Kokkos::ALL(), 0 ); - const_svector_type cv2 = Kokkos::subdynrankview( mv , Kokkos::ALL(), 1 ); - const_svector_type cv3 = Kokkos::subdynrankview( mv , Kokkos::ALL(), 2 ); - - svector_type vr1 = Kokkos::subdynrankview( mv , Kokkos::ALL() , 0 ); - svector_type vr2 = Kokkos::subdynrankview( mv , Kokkos::ALL() , 1 ); - svector_type vr3 = Kokkos::subdynrankview( mv , Kokkos::ALL() , 2 ); - - const_svector_right_type cvr1 = Kokkos::subdynrankview( mv , Kokkos::ALL() , 0 ); - const_svector_right_type cvr2 = Kokkos::subdynrankview( mv , Kokkos::ALL() , 1 ); - const_svector_right_type cvr3 = Kokkos::subdynrankview( mv , Kokkos::ALL() , 2 ); - - - ASSERT_TRUE( & v1[0] == & v1(0) ); - ASSERT_TRUE( & v1[0] == & mv(0,0) ); - ASSERT_TRUE( & v2[0] == & mv(0,1) ); - ASSERT_TRUE( & v3[0] == & mv(0,2) ); - - ASSERT_TRUE( & cv1[0] == & mv(0,0) ); - ASSERT_TRUE( & cv2[0] == & mv(0,1) ); - ASSERT_TRUE( & cv3[0] == & mv(0,2) ); - - ASSERT_TRUE( & vr1[0] == & mv(0,0) ); - ASSERT_TRUE( & vr2[0] == & mv(0,1) ); - ASSERT_TRUE( & vr3[0] == & mv(0,2) ); - - ASSERT_TRUE( & cvr1[0] == & mv(0,0) ); - ASSERT_TRUE( & cvr2[0] == & mv(0,1) ); - ASSERT_TRUE( & cvr3[0] == & mv(0,2) ); - - - ASSERT_TRUE( & mv1(0,0) == & mv( 1 , 2 ) ); - ASSERT_TRUE( & mv1(1,1) == & mv( 2 , 3 ) ); - ASSERT_TRUE( & mv1(3,2) == & mv( 4 , 4 ) ); - ASSERT_TRUE( & mvr1(0,0) == & mv_right( 1 , 2 ) ); - ASSERT_TRUE( & mvr1(1,1) == & mv_right( 2 , 3 ) ); - ASSERT_TRUE( & mvr1(3,2) == & mv_right( 4 , 4 ) ); - - const_svector_type c_cv1( v1 ); - typename svector_type::const_type c_cv2( v2 ); - typename const_svector_type::const_type c_ccv2( v2 ); - - - const_smultivector_type cmv( mv ); - typename smultivector_type::const_type cmvX( cmv ); - typename const_smultivector_type::const_type ccmvX( cmv ); + static void run_test_vector() { + static const unsigned Length = 1000, Count = 8; + + typedef typename Kokkos::DynRankView + multivector_type; + + typedef typename Kokkos::DynRankView + multivector_right_type; + + multivector_type mv = multivector_type("mv", Length, Count); + multivector_right_type mv_right = + multivector_right_type("mv", Length, Count); + + typedef + typename Kokkos::DynRankView + svector_type; + typedef + typename Kokkos::DynRankView + smultivector_type; + typedef typename Kokkos::DynRankView + const_svector_right_type; + typedef typename Kokkos::DynRankView + const_svector_type; + typedef typename Kokkos::DynRankView + const_smultivector_type; + + svector_type v1 = Kokkos::subdynrankview(mv, Kokkos::ALL(), 0); + svector_type v2 = Kokkos::subdynrankview(mv, Kokkos::ALL(), 1); + svector_type v3 = Kokkos::subdynrankview(mv, Kokkos::ALL(), 2); + + svector_type rv1 = Kokkos::subdynrankview(mv_right, 0, Kokkos::ALL()); + svector_type rv2 = Kokkos::subdynrankview(mv_right, 1, Kokkos::ALL()); + svector_type rv3 = Kokkos::subdynrankview(mv_right, 2, Kokkos::ALL()); + + smultivector_type mv1 = Kokkos::subdynrankview(mv, std::make_pair(1, 998), + std::make_pair(2, 5)); + + smultivector_type mvr1 = Kokkos::subdynrankview( + mv_right, std::make_pair(1, 998), std::make_pair(2, 5)); + + const_svector_type cv1 = Kokkos::subdynrankview(mv, Kokkos::ALL(), 0); + const_svector_type cv2 = Kokkos::subdynrankview(mv, Kokkos::ALL(), 1); + const_svector_type cv3 = Kokkos::subdynrankview(mv, Kokkos::ALL(), 2); + + svector_type vr1 = Kokkos::subdynrankview(mv, Kokkos::ALL(), 0); + svector_type vr2 = Kokkos::subdynrankview(mv, Kokkos::ALL(), 1); + svector_type vr3 = Kokkos::subdynrankview(mv, Kokkos::ALL(), 2); + + const_svector_right_type cvr1 = + Kokkos::subdynrankview(mv, Kokkos::ALL(), 0); + const_svector_right_type cvr2 = + Kokkos::subdynrankview(mv, Kokkos::ALL(), 1); + const_svector_right_type cvr3 = + Kokkos::subdynrankview(mv, Kokkos::ALL(), 2); + + ASSERT_TRUE(&v1[0] == &v1(0)); + ASSERT_TRUE(&v1[0] == &mv(0, 0)); + ASSERT_TRUE(&v2[0] == &mv(0, 1)); + ASSERT_TRUE(&v3[0] == &mv(0, 2)); + + ASSERT_TRUE(&cv1[0] == &mv(0, 0)); + ASSERT_TRUE(&cv2[0] == &mv(0, 1)); + ASSERT_TRUE(&cv3[0] == &mv(0, 2)); + + ASSERT_TRUE(&vr1[0] == &mv(0, 0)); + ASSERT_TRUE(&vr2[0] == &mv(0, 1)); + ASSERT_TRUE(&vr3[0] == &mv(0, 2)); + + ASSERT_TRUE(&cvr1[0] == &mv(0, 0)); + ASSERT_TRUE(&cvr2[0] == &mv(0, 1)); + ASSERT_TRUE(&cvr3[0] == &mv(0, 2)); + + ASSERT_TRUE(&mv1(0, 0) == &mv(1, 2)); + ASSERT_TRUE(&mv1(1, 1) == &mv(2, 3)); + ASSERT_TRUE(&mv1(3, 2) == &mv(4, 4)); + ASSERT_TRUE(&mvr1(0, 0) == &mv_right(1, 2)); + ASSERT_TRUE(&mvr1(1, 1) == &mv_right(2, 3)); + ASSERT_TRUE(&mvr1(3, 2) == &mv_right(4, 4)); + + const_svector_type c_cv1(v1); + typename svector_type::const_type c_cv2(v2); + typename const_svector_type::const_type c_ccv2(v2); + + const_smultivector_type cmv(mv); + typename smultivector_type::const_type cmvX(cmv); + typename const_smultivector_type::const_type ccmvX(cmv); } }; -} // namespace Test +} // namespace Test /*--------------------------------------------------------------------------*/ - diff --git a/lib/kokkos/containers/unit_tests/TestDynViewAPI_generic.hpp b/lib/kokkos/containers/unit_tests/TestDynViewAPI_generic.hpp index 2909e8cc76..90ca5df194 100644 --- a/lib/kokkos/containers/unit_tests/TestDynViewAPI_generic.hpp +++ b/lib/kokkos/containers/unit_tests/TestDynViewAPI_generic.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,9 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( TEST_CATEGORY , dyn_rank_view_api_generic) { - TestDynViewAPI< double , TEST_EXECSPACE >::run_tests(); +TEST(TEST_CATEGORY, dyn_rank_view_api_generic) { + TestDynViewAPI::run_tests(); } -} - +} // namespace Test diff --git a/lib/kokkos/containers/unit_tests/TestDynViewAPI_rank12345.hpp b/lib/kokkos/containers/unit_tests/TestDynViewAPI_rank12345.hpp index 5b2c22440d..050ebbe35c 100644 --- a/lib/kokkos/containers/unit_tests/TestDynViewAPI_rank12345.hpp +++ b/lib/kokkos/containers/unit_tests/TestDynViewAPI_rank12345.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,11 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( TEST_CATEGORY , dyn_rank_view_api_operator_rank12345) { - TestDynViewAPI< double , TEST_EXECSPACE >::run_operator_test_rank12345(); +TEST(TEST_CATEGORY, dyn_rank_view_api_operator_rank12345) { + TestDynViewAPI::run_operator_test_rank12345(); } -} - +} // namespace Test diff --git a/lib/kokkos/containers/unit_tests/TestDynViewAPI_rank67.hpp b/lib/kokkos/containers/unit_tests/TestDynViewAPI_rank67.hpp index 45a49fb819..eb8df60a89 100644 --- a/lib/kokkos/containers/unit_tests/TestDynViewAPI_rank67.hpp +++ b/lib/kokkos/containers/unit_tests/TestDynViewAPI_rank67.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,9 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( TEST_CATEGORY , dyn_rank_view_api_operator_rank67) { - TestDynViewAPI< double , TEST_EXECSPACE >::run_operator_test_rank67(); +TEST(TEST_CATEGORY, dyn_rank_view_api_operator_rank67) { + TestDynViewAPI::run_operator_test_rank67(); } -} - +} // namespace Test diff --git a/lib/kokkos/containers/unit_tests/TestDynamicView.hpp b/lib/kokkos/containers/unit_tests/TestDynamicView.hpp index 9e87fdf5cc..235464ef07 100644 --- a/lib/kokkos/containers/unit_tests/TestDynamicView.hpp +++ b/lib/kokkos/containers/unit_tests/TestDynamicView.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -55,45 +56,43 @@ namespace Test { -template< typename Scalar , class Space > -struct TestDynamicView -{ - typedef typename Space::execution_space execution_space ; - typedef typename Space::memory_space memory_space ; +template +struct TestDynamicView { + typedef typename Space::execution_space execution_space; + typedef typename Space::memory_space memory_space; - typedef Kokkos::Experimental::DynamicView view_type; + typedef Kokkos::Experimental::DynamicView view_type; typedef double value_type; - static void run( unsigned arg_total_size ) - { - // Test: Create DynamicView, initialize size (via resize), run through parallel_for to set values, check values (via parallel_reduce); resize values and repeat + static void run(unsigned arg_total_size) { + // Test: Create DynamicView, initialize size (via resize), run through + // parallel_for to set values, check values (via parallel_reduce); resize + // values and repeat // Case 1: min_chunk_size is a power of 2 { - view_type da("da", 1024, arg_total_size ); - ASSERT_EQ( da.size(), 0 ); + view_type da("da", 1024, arg_total_size); + ASSERT_EQ(da.size(), 0); // Init unsigned da_size = arg_total_size / 8; da.resize_serial(da_size); - ASSERT_EQ( da.size(), da_size ); + ASSERT_EQ(da.size(), da_size); -#if defined( KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA ) -#if !defined(KOKKOS_ENABLE_CUDA) || ( 8000 <= CUDA_VERSION ) - Kokkos::parallel_for( Kokkos::RangePolicy(0, da_size), KOKKOS_LAMBDA ( const int i ) - { - da(i) = Scalar(i); - } - ); +#if defined(KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA) +#if !defined(KOKKOS_ENABLE_CUDA) || (8000 <= CUDA_VERSION) + Kokkos::parallel_for( + Kokkos::RangePolicy(0, da_size), + KOKKOS_LAMBDA(const int i) { da(i) = Scalar(i); }); value_type result_sum = 0.0; - Kokkos::parallel_reduce( Kokkos::RangePolicy(0, da_size), KOKKOS_LAMBDA ( const int i, value_type& partial_sum ) - { - partial_sum += (value_type)da(i); - } - , result_sum - ); - - ASSERT_EQ(result_sum, (value_type)( da_size * (da_size - 1) / 2 ) ); + Kokkos::parallel_reduce( + Kokkos::RangePolicy(0, da_size), + KOKKOS_LAMBDA(const int i, value_type& partial_sum) { + partial_sum += (value_type)da(i); + }, + result_sum); + + ASSERT_EQ(result_sum, (value_type)(da_size * (da_size - 1) / 2)); #endif #endif @@ -101,56 +100,55 @@ struct TestDynamicView // the first 1/4 should remain the same unsigned da_resize = arg_total_size / 2; da.resize_serial(da_resize); - ASSERT_EQ( da.size(), da_resize ); + ASSERT_EQ(da.size(), da_resize); -#if defined( KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA ) -#if !defined(KOKKOS_ENABLE_CUDA) || ( 8000 <= CUDA_VERSION ) - Kokkos::parallel_for( Kokkos::RangePolicy(da_size, da_resize), KOKKOS_LAMBDA ( const int i ) - { - da(i) = Scalar(i); - } - ); +#if defined(KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA) +#if !defined(KOKKOS_ENABLE_CUDA) || (8000 <= CUDA_VERSION) + Kokkos::parallel_for( + Kokkos::RangePolicy(da_size, da_resize), + KOKKOS_LAMBDA(const int i) { da(i) = Scalar(i); }); value_type new_result_sum = 0.0; - Kokkos::parallel_reduce( Kokkos::RangePolicy(da_size, da_resize), KOKKOS_LAMBDA ( const int i, value_type& partial_sum ) - { - partial_sum += (value_type)da(i); - } - , new_result_sum - ); - - ASSERT_EQ(new_result_sum+result_sum, (value_type)( da_resize * (da_resize - 1) / 2 ) ); + Kokkos::parallel_reduce( + Kokkos::RangePolicy(da_size, da_resize), + KOKKOS_LAMBDA(const int i, value_type& partial_sum) { + partial_sum += (value_type)da(i); + }, + new_result_sum); + + ASSERT_EQ(new_result_sum + result_sum, + (value_type)(da_resize * (da_resize - 1) / 2)); #endif #endif - } // end scope + } // end scope - // Test: Create DynamicView, initialize size (via resize), run through parallel_for to set values, check values (via parallel_reduce); resize values and repeat + // Test: Create DynamicView, initialize size (via resize), run through + // parallel_for to set values, check values (via parallel_reduce); resize + // values and repeat // Case 2: min_chunk_size is NOT a power of 2 { - view_type da("da", 1023, arg_total_size ); - ASSERT_EQ( da.size(), 0 ); + view_type da("da", 1023, arg_total_size); + ASSERT_EQ(da.size(), 0); // Init unsigned da_size = arg_total_size / 8; da.resize_serial(da_size); - ASSERT_EQ( da.size(), da_size ); + ASSERT_EQ(da.size(), da_size); -#if defined( KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA ) -#if !defined(KOKKOS_ENABLE_CUDA) || ( 8000 <= CUDA_VERSION ) - Kokkos::parallel_for( Kokkos::RangePolicy(0, da_size), KOKKOS_LAMBDA ( const int i ) - { - da(i) = Scalar(i); - } - ); +#if defined(KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA) +#if !defined(KOKKOS_ENABLE_CUDA) || (8000 <= CUDA_VERSION) + Kokkos::parallel_for( + Kokkos::RangePolicy(0, da_size), + KOKKOS_LAMBDA(const int i) { da(i) = Scalar(i); }); value_type result_sum = 0.0; - Kokkos::parallel_reduce( Kokkos::RangePolicy(0, da_size), KOKKOS_LAMBDA ( const int i, value_type& partial_sum ) - { - partial_sum += (value_type)da(i); - } - , result_sum - ); - - ASSERT_EQ(result_sum, (value_type)( da_size * (da_size - 1) / 2 ) ); + Kokkos::parallel_reduce( + Kokkos::RangePolicy(0, da_size), + KOKKOS_LAMBDA(const int i, value_type& partial_sum) { + partial_sum += (value_type)da(i); + }, + result_sum); + + ASSERT_EQ(result_sum, (value_type)(da_size * (da_size - 1) / 2)); #endif #endif @@ -158,99 +156,92 @@ struct TestDynamicView // the first 1/4 should remain the same unsigned da_resize = arg_total_size / 2; da.resize_serial(da_resize); - ASSERT_EQ( da.size(), da_resize ); + ASSERT_EQ(da.size(), da_resize); -#if defined( KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA ) -#if !defined(KOKKOS_ENABLE_CUDA) || ( 8000 <= CUDA_VERSION ) - Kokkos::parallel_for( Kokkos::RangePolicy(da_size, da_resize), KOKKOS_LAMBDA ( const int i ) - { - da(i) = Scalar(i); - } - ); +#if defined(KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA) +#if !defined(KOKKOS_ENABLE_CUDA) || (8000 <= CUDA_VERSION) + Kokkos::parallel_for( + Kokkos::RangePolicy(da_size, da_resize), + KOKKOS_LAMBDA(const int i) { da(i) = Scalar(i); }); value_type new_result_sum = 0.0; - Kokkos::parallel_reduce( Kokkos::RangePolicy(da_size, da_resize), KOKKOS_LAMBDA ( const int i, value_type& partial_sum ) - { - partial_sum += (value_type)da(i); - } - , new_result_sum - ); - - ASSERT_EQ(new_result_sum+result_sum, (value_type)( da_resize * (da_resize - 1) / 2 ) ); + Kokkos::parallel_reduce( + Kokkos::RangePolicy(da_size, da_resize), + KOKKOS_LAMBDA(const int i, value_type& partial_sum) { + partial_sum += (value_type)da(i); + }, + new_result_sum); + + ASSERT_EQ(new_result_sum + result_sum, + (value_type)(da_resize * (da_resize - 1) / 2)); #endif #endif - } // end scope + } // end scope - // Test: Create DynamicView, initialize size (via resize), run through parallel_for to set values, check values (via parallel_reduce); resize values and repeat + // Test: Create DynamicView, initialize size (via resize), run through + // parallel_for to set values, check values (via parallel_reduce); resize + // values and repeat // Case 3: resize reduces the size { - view_type da("da", 1023, arg_total_size ); - ASSERT_EQ( da.size(), 0 ); + view_type da("da", 1023, arg_total_size); + ASSERT_EQ(da.size(), 0); // Init unsigned da_size = arg_total_size / 2; da.resize_serial(da_size); - ASSERT_EQ( da.size(), da_size ); + ASSERT_EQ(da.size(), da_size); -#if defined( KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA ) -#if !defined(KOKKOS_ENABLE_CUDA) || ( 8000 <= CUDA_VERSION ) - Kokkos::parallel_for( Kokkos::RangePolicy(0, da_size), KOKKOS_LAMBDA ( const int i ) - { - da(i) = Scalar(i); - } - ); +#if defined(KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA) +#if !defined(KOKKOS_ENABLE_CUDA) || (8000 <= CUDA_VERSION) + Kokkos::parallel_for( + Kokkos::RangePolicy(0, da_size), + KOKKOS_LAMBDA(const int i) { da(i) = Scalar(i); }); value_type result_sum = 0.0; - Kokkos::parallel_reduce( Kokkos::RangePolicy(0, da_size), KOKKOS_LAMBDA ( const int i, value_type& partial_sum ) - { - partial_sum += (value_type)da(i); - } - , result_sum - ); - - ASSERT_EQ(result_sum, (value_type)( da_size * (da_size - 1) / 2 ) ); + Kokkos::parallel_reduce( + Kokkos::RangePolicy(0, da_size), + KOKKOS_LAMBDA(const int i, value_type& partial_sum) { + partial_sum += (value_type)da(i); + }, + result_sum); + + ASSERT_EQ(result_sum, (value_type)(da_size * (da_size - 1) / 2)); #endif #endif // remove the final 3/4 entries i.e. first 1/4 remain unsigned da_resize = arg_total_size / 8; da.resize_serial(da_resize); - ASSERT_EQ( da.size(), da_resize ); + ASSERT_EQ(da.size(), da_resize); -#if defined( KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA ) -#if !defined(KOKKOS_ENABLE_CUDA) || ( 8000 <= CUDA_VERSION ) - Kokkos::parallel_for( Kokkos::RangePolicy(0, da_resize), KOKKOS_LAMBDA ( const int i ) - { - da(i) = Scalar(i); - } - ); +#if defined(KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA) +#if !defined(KOKKOS_ENABLE_CUDA) || (8000 <= CUDA_VERSION) + Kokkos::parallel_for( + Kokkos::RangePolicy(0, da_resize), + KOKKOS_LAMBDA(const int i) { da(i) = Scalar(i); }); value_type new_result_sum = 0.0; - Kokkos::parallel_reduce( Kokkos::RangePolicy(0, da_resize), KOKKOS_LAMBDA ( const int i, value_type& partial_sum ) - { - partial_sum += (value_type)da(i); - } - , new_result_sum - ); - - ASSERT_EQ(new_result_sum, (value_type)( da_resize * (da_resize - 1) / 2 ) ); + Kokkos::parallel_reduce( + Kokkos::RangePolicy(0, da_resize), + KOKKOS_LAMBDA(const int i, value_type& partial_sum) { + partial_sum += (value_type)da(i); + }, + new_result_sum); + + ASSERT_EQ(new_result_sum, (value_type)(da_resize * (da_resize - 1) / 2)); #endif #endif - } // end scope - + } // end scope } }; -TEST_F( TEST_CATEGORY , dynamic_view ) -{ - typedef TestDynamicView< double , TEST_EXECSPACE > - TestDynView ; +TEST(TEST_CATEGORY, dynamic_view) { + typedef TestDynamicView TestDynView; - for ( int i = 0 ; i < 10 ; ++i ) { - TestDynView::run( 100000 + 100 * i ); + for (int i = 0; i < 10; ++i) { + TestDynView::run(100000 + 100 * i); } } -} // namespace Test +} // namespace Test #endif /* #ifndef KOKKOS_TEST_DYNAMICVIEW_HPP */ - diff --git a/lib/kokkos/containers/unit_tests/TestErrorReporter.hpp b/lib/kokkos/containers/unit_tests/TestErrorReporter.hpp index 7e48089b43..49b71cdea7 100644 --- a/lib/kokkos/containers/unit_tests/TestErrorReporter.hpp +++ b/lib/kokkos/containers/unit_tests/TestErrorReporter.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -51,47 +52,47 @@ namespace Test { -// Just save the data in the report. Informative text goies in the operator<<(..). +// Just save the data in the report. Informative text goies in the +// operator<<(..). template -struct ThreeValReport -{ +struct ThreeValReport { DataType1 m_data1; DataType2 m_data2; DataType3 m_data3; - }; template -std::ostream &operator<<(std::ostream & os, const ThreeValReport &val) -{ - return os << "{" << val.m_data1 << " " << val.m_data2 << " " << val.m_data3 << "}"; +std::ostream &operator<<( + std::ostream &os, + const ThreeValReport &val) { + return os << "{" << val.m_data1 << " " << val.m_data2 << " " << val.m_data3 + << "}"; } -template +template void checkReportersAndReportsAgree(const std::vector &reporters, - const std::vector &reports) -{ + const std::vector &reports) { for (size_t i = 0; i < reports.size(); ++i) { EXPECT_EQ(1, reporters[i] % 2); EXPECT_EQ(reporters[i], reports[i].m_data1); } } - template struct ErrorReporterDriverBase { - - typedef ThreeValReport report_type; - typedef Kokkos::Experimental::ErrorReporter error_reporter_type; + typedef ThreeValReport report_type; + typedef Kokkos::Experimental::ErrorReporter + error_reporter_type; error_reporter_type m_errorReporter; ErrorReporterDriverBase(int reporter_capacity, int test_size) - : m_errorReporter(reporter_capacity) { } + : m_errorReporter(reporter_capacity) {} - KOKKOS_INLINE_FUNCTION bool error_condition(const int work_idx) const { return (work_idx % 2 != 0); } + KOKKOS_INLINE_FUNCTION bool error_condition(const int work_idx) const { + return (work_idx % 2 != 0); + } - void check_expectations(int reporter_capacity, int test_size) - { + void check_expectations(int reporter_capacity, int test_size) { int num_reported = m_errorReporter.getNumReports(); int num_attempts = m_errorReporter.getNumReportAttempts(); @@ -99,15 +100,14 @@ struct ErrorReporterDriverBase { EXPECT_EQ(expected_num_reports, num_reported); EXPECT_EQ(test_size / 2, num_attempts); - bool expect_full = (reporter_capacity <= (test_size / 2)); + bool expect_full = (reporter_capacity <= (test_size / 2)); bool reported_full = m_errorReporter.full(); EXPECT_EQ(expect_full, reported_full); } }; template -void TestErrorReporter() -{ +void TestErrorReporter() { typedef ErrorReporterDriverType tester_type; std::vector reporters; std::vector reports; @@ -120,9 +120,12 @@ void TestErrorReporter() test2.m_errorReporter.getReports(reporters, reports); checkReportersAndReportsAgree(reporters, reports); - typename Kokkos::View::HostMirror view_reporters; - typename Kokkos::View::HostMirror - view_reports; + typename Kokkos::View< + int *, typename ErrorReporterDriverType::execution_space>::HostMirror + view_reporters; + typename Kokkos::View:: + HostMirror view_reports; test2.m_errorReporter.getReports(view_reporters, view_reports); int num_reports = view_reporters.extent(0); @@ -136,19 +139,16 @@ void TestErrorReporter() reports.push_back(view_reports(i)); } checkReportersAndReportsAgree(reporters, reports); - } - template -struct ErrorReporterDriver : public ErrorReporterDriverBase -{ - typedef ErrorReporterDriverBase driver_base; - typedef typename driver_base::error_reporter_type::execution_space execution_space; +struct ErrorReporterDriver : public ErrorReporterDriverBase { + typedef ErrorReporterDriverBase driver_base; + typedef typename driver_base::error_reporter_type::execution_space + execution_space; ErrorReporterDriver(int reporter_capacity, int test_size) - : driver_base(reporter_capacity, test_size) - { + : driver_base(reporter_capacity, test_size) { execute(reporter_capacity, test_size); // Test that clear() and resize() work across memory spaces. @@ -159,19 +159,18 @@ struct ErrorReporterDriver : public ErrorReporterDriverBase } } - void execute(int reporter_capacity, int test_size) - { - Kokkos::parallel_for(Kokkos::RangePolicy(0,test_size), *this); + void execute(int reporter_capacity, int test_size) { + Kokkos::parallel_for(Kokkos::RangePolicy(0, test_size), + *this); Kokkos::fence(); driver_base::check_expectations(reporter_capacity, test_size); } KOKKOS_INLINE_FUNCTION - void operator()(const int work_idx) const - { + void operator()(const int work_idx) const { if (driver_base::error_condition(work_idx)) { double val = M_PI * static_cast(work_idx); - typename driver_base::report_type report = {work_idx, -2*work_idx, val}; + typename driver_base::report_type report = {work_idx, -2 * work_idx, val}; driver_base::m_errorReporter.add_report(work_idx, report); } } @@ -179,45 +178,45 @@ struct ErrorReporterDriver : public ErrorReporterDriverBase #if defined(KOKKOS_CLASS_LAMBDA) template -struct ErrorReporterDriverUseLambda : public ErrorReporterDriverBase -{ - - typedef ErrorReporterDriverBase driver_base; - typedef typename driver_base::error_reporter_type::execution_space execution_space; +struct ErrorReporterDriverUseLambda + : public ErrorReporterDriverBase { + typedef ErrorReporterDriverBase driver_base; + typedef typename driver_base::error_reporter_type::execution_space + execution_space; ErrorReporterDriverUseLambda(int reporter_capacity, int test_size) - : driver_base(reporter_capacity, test_size) - { - Kokkos::parallel_for(Kokkos::RangePolicy(0,test_size), KOKKOS_CLASS_LAMBDA (const int work_idx) { - if (driver_base::error_condition(work_idx)) { - double val = M_PI * static_cast(work_idx); - typename driver_base::report_type report = {work_idx, -2*work_idx, val}; - driver_base::m_errorReporter.add_report(work_idx, report); - } - }); + : driver_base(reporter_capacity, test_size) { + Kokkos::parallel_for( + Kokkos::RangePolicy(0, test_size), + KOKKOS_CLASS_LAMBDA(const int work_idx) { + if (driver_base::error_condition(work_idx)) { + double val = M_PI * static_cast(work_idx); + typename driver_base::report_type report = {work_idx, -2 * work_idx, + val}; + driver_base::m_errorReporter.add_report(work_idx, report); + } + }); Kokkos::fence(); driver_base::check_expectations(reporter_capacity, test_size); } - }; #endif - #ifdef KOKKOS_ENABLE_OPENMP -struct ErrorReporterDriverNativeOpenMP : public ErrorReporterDriverBase -{ - typedef ErrorReporterDriverBase driver_base; - typedef typename driver_base::error_reporter_type::execution_space execution_space; +struct ErrorReporterDriverNativeOpenMP + : public ErrorReporterDriverBase { + typedef ErrorReporterDriverBase driver_base; + typedef typename driver_base::error_reporter_type::execution_space + execution_space; ErrorReporterDriverNativeOpenMP(int reporter_capacity, int test_size) - : driver_base(reporter_capacity, test_size) - { + : driver_base(reporter_capacity, test_size) { #pragma omp parallel for - for(int work_idx = 0; work_idx < test_size; ++work_idx) - { + for (int work_idx = 0; work_idx < test_size; ++work_idx) { if (driver_base::error_condition(work_idx)) { double val = M_PI * static_cast(work_idx); - typename driver_base::report_type report = {work_idx, -2*work_idx, val}; + typename driver_base::report_type report = {work_idx, -2 * work_idx, + val}; driver_base::m_errorReporter.add_report(work_idx, report); } }; @@ -227,17 +226,14 @@ struct ErrorReporterDriverNativeOpenMP : public ErrorReporterDriverBase>(); } #endif -TEST_F(TEST_CATEGORY, ErrorReporter) -{ +TEST(TEST_CATEGORY, ErrorReporter) { TestErrorReporter>(); } -} // namespace Test -#endif // #ifndef KOKKOS_TEST_ERROR_REPORTING_HPP - +} // namespace Test +#endif // #ifndef KOKKOS_TEST_ERROR_REPORTING_HPP diff --git a/lib/kokkos/containers/unit_tests/TestOffsetView.hpp b/lib/kokkos/containers/unit_tests/TestOffsetView.hpp index 6965199d45..12bcda9524 100644 --- a/lib/kokkos/containers/unit_tests/TestOffsetView.hpp +++ b/lib/kokkos/containers/unit_tests/TestOffsetView.hpp @@ -1,10 +1,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -22,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,8 +46,6 @@ #ifndef CONTAINERS_UNIT_TESTS_TESTOFFSETVIEW_HPP_ #define CONTAINERS_UNIT_TESTS_TESTOFFSETVIEW_HPP_ - - #include #include #include @@ -55,372 +54,652 @@ #include #include -using std::endl; using std::cout; +using std::endl; -namespace Test{ - - template - void test_offsetview_construction(unsigned int size) - { - - typedef Kokkos::Experimental::OffsetView offset_view_type; - typedef Kokkos::View view_type; +namespace Test { - Kokkos::Experimental::index_list_type range0 = {-1, 3}; - Kokkos::Experimental::index_list_type range1 = {-2, 2}; +template +void test_offsetview_construction(unsigned int size) { + typedef Kokkos::Experimental::OffsetView offset_view_type; + typedef Kokkos::View view_type; - offset_view_type ov("firstOV", range0, range1); + Kokkos::Experimental::index_list_type range0 = {-1, 3}; + Kokkos::Experimental::index_list_type range1 = {-2, 2}; - ASSERT_EQ("firstOV", ov.label()); - ASSERT_EQ(2, ov.Rank); + offset_view_type ov("firstOV", range0, range1); - ASSERT_EQ(ov.begin(0), -1); - ASSERT_EQ(ov.end(0), 4); + ASSERT_EQ("firstOV", ov.label()); + ASSERT_EQ(2, ov.Rank); - ASSERT_EQ(ov.begin(1), -2); - ASSERT_EQ(ov.end(1), 3); + ASSERT_EQ(ov.begin(0), -1); + ASSERT_EQ(ov.end(0), 4); - ASSERT_EQ(ov.extent(0), 5); - ASSERT_EQ(ov.extent(1), 5); + ASSERT_EQ(ov.begin(1), -2); + ASSERT_EQ(ov.end(1), 3); - const int ovmin0 = ov.begin(0); - const int ovend0 = ov.end(0); - const int ovmin1 = ov.begin(1); - const int ovend1 = ov.end(1); + ASSERT_EQ(ov.extent(0), 5); + ASSERT_EQ(ov.extent(1), 5); #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) - { - Kokkos::Experimental::OffsetView offsetV1("OneDOffsetView", range0); - - Kokkos::RangePolicy rangePolicy1(offsetV1.begin(0), offsetV1.end(0)); - Kokkos::parallel_for(rangePolicy1, KOKKOS_LAMBDA (const int i){ - offsetV1(i) = 1; - } - ); - Kokkos::fence(); - - int OVResult = 0; - Kokkos::parallel_reduce(rangePolicy1, KOKKOS_LAMBDA(const int i, int & updateMe){ - updateMe += offsetV1(i); - }, OVResult); - - Kokkos::fence(); - ASSERT_EQ(OVResult, offsetV1.end(0) - offsetV1.begin(0)) << "found wrong number of elements in OffsetView that was summed."; - - } - { //test deep copy of scalar const value into mirro - const int constVal = 6; - typename offset_view_type::HostMirror hostOffsetView = - Kokkos::Experimental::create_mirror_view(ov); - - Kokkos::Experimental::deep_copy(hostOffsetView, constVal); - - for(int i = hostOffsetView.begin(0); i < hostOffsetView.end(0); ++i) { - for(int j = hostOffsetView.begin(1); j < hostOffsetView.end(1); ++j) { - ASSERT_EQ(hostOffsetView(i,j), constVal) << "Bad data found in OffsetView"; - } - } - } - - typedef Kokkos::MDRangePolicy, Kokkos::IndexType > range_type; - typedef typename range_type::point_type point_type; - - range_type rangePolicy2D(point_type{ {ovmin0, ovmin1 } }, - point_type{ { ovend0, ovend1 } }); - - const int constValue = 9; - Kokkos::parallel_for(rangePolicy2D, KOKKOS_LAMBDA (const int i, const int j) { - ov(i,j) = constValue; - } - ); - - //test offsetview to offsetviewmirror deep copy - typename offset_view_type::HostMirror hostOffsetView = - Kokkos::Experimental::create_mirror_view(ov); - - Kokkos::Experimental::deep_copy(hostOffsetView, ov); - - for(int i = hostOffsetView.begin(0); i < hostOffsetView.end(0); ++i) { - for(int j = hostOffsetView.begin(1); j < hostOffsetView.end(1); ++j) { - ASSERT_EQ(hostOffsetView(i,j), constValue) << "Bad data found in OffsetView"; - } - } - - int OVResult = 0; - Kokkos::parallel_reduce(rangePolicy2D, KOKKOS_LAMBDA(const int i, const int j, int & updateMe){ - updateMe += ov(i, j); - }, OVResult); - - int answer = 0; - for(int i = ov.begin(0); i < ov.end(0); ++i) { - for(int j = ov.begin(1); j < ov.end(1); ++j) { - answer += constValue; - } + const int ovmin0 = ov.begin(0); + const int ovend0 = ov.end(0); + const int ovmin1 = ov.begin(1); + const int ovend1 = ov.end(1); + { + Kokkos::Experimental::OffsetView offsetV1("OneDOffsetView", + range0); + + Kokkos::RangePolicy rangePolicy1(offsetV1.begin(0), + offsetV1.end(0)); + Kokkos::parallel_for( + rangePolicy1, KOKKOS_LAMBDA(const int i) { offsetV1(i) = 1; }); + Kokkos::fence(); + + int OVResult = 0; + Kokkos::parallel_reduce( + rangePolicy1, + KOKKOS_LAMBDA(const int i, int& updateMe) { updateMe += offsetV1(i); }, + OVResult); + + Kokkos::fence(); + ASSERT_EQ(OVResult, offsetV1.end(0) - offsetV1.begin(0)) + << "found wrong number of elements in OffsetView that was summed."; + } + { // test deep copy of scalar const value into mirro + const int constVal = 6; + typename offset_view_type::HostMirror hostOffsetView = + Kokkos::Experimental::create_mirror_view(ov); + + Kokkos::Experimental::deep_copy(hostOffsetView, constVal); + + for (int i = hostOffsetView.begin(0); i < hostOffsetView.end(0); ++i) { + for (int j = hostOffsetView.begin(1); j < hostOffsetView.end(1); ++j) { + ASSERT_EQ(hostOffsetView(i, j), constVal) + << "Bad data found in OffsetView"; } - - ASSERT_EQ(OVResult, answer) << "Bad data found in OffsetView"; + } + } + + typedef Kokkos::MDRangePolicy, + Kokkos::IndexType > + range_type; + typedef typename range_type::point_type point_type; + + range_type rangePolicy2D(point_type{{ovmin0, ovmin1}}, + point_type{{ovend0, ovend1}}); + + const int constValue = 9; + Kokkos::parallel_for( + rangePolicy2D, + KOKKOS_LAMBDA(const int i, const int j) { ov(i, j) = constValue; }); + + // test offsetview to offsetviewmirror deep copy + typename offset_view_type::HostMirror hostOffsetView = + Kokkos::Experimental::create_mirror_view(ov); + + Kokkos::Experimental::deep_copy(hostOffsetView, ov); + + for (int i = hostOffsetView.begin(0); i < hostOffsetView.end(0); ++i) { + for (int j = hostOffsetView.begin(1); j < hostOffsetView.end(1); ++j) { + ASSERT_EQ(hostOffsetView(i, j), constValue) + << "Bad data found in OffsetView"; + } + } + + int OVResult = 0; + Kokkos::parallel_reduce( + rangePolicy2D, + KOKKOS_LAMBDA(const int i, const int j, int& updateMe) { + updateMe += ov(i, j); + }, + OVResult); + + int answer = 0; + for (int i = ov.begin(0); i < ov.end(0); ++i) { + for (int j = ov.begin(1); j < ov.end(1); ++j) { + answer += constValue; + } + } + + ASSERT_EQ(OVResult, answer) << "Bad data found in OffsetView"; #endif - { - offset_view_type ovCopy(ov); - ASSERT_EQ(ovCopy==ov, true) << - "Copy constructor or equivalence operator broken"; - } - - { - offset_view_type ovAssigned = ov; - ASSERT_EQ(ovAssigned==ov, true) << - "Assignment operator or equivalence operator broken"; - } - - { //construct OffsetView from a View plus begins array - const int extent0 = 100; - const int extent1 = 200; - const int extent2 = 300; - Kokkos::View view3D("view3D", extent0, extent1, extent2); - - Kokkos::deep_copy(view3D, 1); + { + offset_view_type ovCopy(ov); + ASSERT_EQ(ovCopy == ov, true) + << "Copy constructor or equivalence operator broken"; + } - Kokkos::Array begins = {{-10, -20, -30}}; - Kokkos::Experimental::OffsetView offsetView3D(view3D, begins); + { + offset_view_type ovAssigned = ov; + ASSERT_EQ(ovAssigned == ov, true) + << "Assignment operator or equivalence operator broken"; + } - typedef Kokkos::MDRangePolicy, Kokkos::IndexType > range3_type; - typedef typename range3_type::point_type point3_type; + { // construct OffsetView from a View plus begins array + const int extent0 = 100; + const int extent1 = 200; + const int extent2 = 300; + Kokkos::View view3D("view3D", extent0, extent1, extent2); - range3_type rangePolicy3DZero(point3_type{ {0, 0, 0 } }, - point3_type{ { extent0, extent1, extent2 } }); + Kokkos::deep_copy(view3D, 1); -#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) - int view3DSum = 0; - Kokkos::parallel_reduce(rangePolicy3DZero, KOKKOS_LAMBDA(const int i, const int j, int k, int & updateMe){ - updateMe += view3D(i, j, k); - }, view3DSum); + Kokkos::Array begins = {{-10, -20, -30}}; + Kokkos::Experimental::OffsetView offsetView3D(view3D, + begins); - range3_type rangePolicy3D(point3_type{ {begins[0], begins[1], begins[2] } }, - point3_type{ { begins[0] + extent0, begins[1] + extent1, begins[2] + extent2 } }); - int offsetView3DSum = 0; + typedef Kokkos::MDRangePolicy, + Kokkos::IndexType > + range3_type; + typedef typename range3_type::point_type point3_type; - Kokkos::parallel_reduce(rangePolicy3D, KOKKOS_LAMBDA(const int i, const int j, int k, int & updateMe){ - updateMe += offsetView3D(i, j, k); - }, offsetView3DSum); + range3_type rangePolicy3DZero(point3_type{{0, 0, 0}}, + point3_type{{extent0, extent1, extent2}}); - ASSERT_EQ(view3DSum, offsetView3DSum) << "construction of OffsetView from View and begins array broken."; +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) + int view3DSum = 0; + Kokkos::parallel_reduce( + rangePolicy3DZero, + KOKKOS_LAMBDA(const int i, const int j, int k, int& updateMe) { + updateMe += view3D(i, j, k); + }, + view3DSum); + + range3_type rangePolicy3D( + point3_type{{begins[0], begins[1], begins[2]}}, + point3_type{ + {begins[0] + extent0, begins[1] + extent1, begins[2] + extent2}}); + int offsetView3DSum = 0; + + Kokkos::parallel_reduce( + rangePolicy3D, + KOKKOS_LAMBDA(const int i, const int j, int k, int& updateMe) { + updateMe += offsetView3D(i, j, k); + }, + offsetView3DSum); + + ASSERT_EQ(view3DSum, offsetView3DSum) + << "construction of OffsetView from View and begins array broken."; #endif - } - view_type viewFromOV = ov.view(); - - ASSERT_EQ(viewFromOV == ov, true) << - "OffsetView::view() or equivalence operator View == OffsetView broken"; - - { - offset_view_type ovFromV(viewFromOV, {-1, -2}); - - ASSERT_EQ(ovFromV == viewFromOV , true) << - "Construction of OffsetView from View or equivalence operator OffsetView == View broken"; - } - { - offset_view_type ovFromV = viewFromOV; - ASSERT_EQ(ovFromV == viewFromOV , true) << - "Construction of OffsetView from View by assignment (implicit conversion) or equivalence operator OffsetView == View broken"; - } - - {// test offsetview to view deep copy - view_type aView("aView", ov.extent(0), ov.extent(1)); - Kokkos::Experimental::deep_copy(aView, ov); + } + view_type viewFromOV = ov.view(); + + ASSERT_EQ(viewFromOV == ov, true) + << "OffsetView::view() or equivalence operator View == OffsetView broken"; + + { + offset_view_type ovFromV(viewFromOV, {-1, -2}); + + ASSERT_EQ(ovFromV == viewFromOV, true) + << "Construction of OffsetView from View or equivalence operator " + "OffsetView == View broken"; + } + { + offset_view_type ovFromV = viewFromOV; + ASSERT_EQ(ovFromV == viewFromOV, true) + << "Construction of OffsetView from View by assignment (implicit " + "conversion) or equivalence operator OffsetView == View broken"; + } + + { // test offsetview to view deep copy + view_type aView("aView", ov.extent(0), ov.extent(1)); + Kokkos::Experimental::deep_copy(aView, ov); #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) - int sum = 0; - Kokkos::parallel_reduce(rangePolicy2D, KOKKOS_LAMBDA(const int i, const int j, int & updateMe){ - updateMe += ov(i, j) - aView(i- ov.begin(0), j-ov.begin(1)); - }, sum); - - ASSERT_EQ(sum, 0) << "deep_copy(view, offsetView) broken."; + int sum = 0; + Kokkos::parallel_reduce( + rangePolicy2D, + KOKKOS_LAMBDA(const int i, const int j, int& updateMe) { + updateMe += ov(i, j) - aView(i - ov.begin(0), j - ov.begin(1)); + }, + sum); + + ASSERT_EQ(sum, 0) << "deep_copy(view, offsetView) broken."; #endif - } + } - {// test view to offsetview deep copy - view_type aView("aView", ov.extent(0), ov.extent(1)); + { // test view to offsetview deep copy + view_type aView("aView", ov.extent(0), ov.extent(1)); - Kokkos::deep_copy(aView, 99); - Kokkos::Experimental::deep_copy(ov, aView); - + Kokkos::deep_copy(aView, 99); + Kokkos::Experimental::deep_copy(ov, aView); #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) - int sum = 0; - Kokkos::parallel_reduce(rangePolicy2D, KOKKOS_LAMBDA(const int i, const int j, int & updateMe){ - updateMe += ov(i, j) - aView(i- ov.begin(0), j-ov.begin(1)); - }, sum); - - ASSERT_EQ(sum, 0) << "deep_copy(offsetView, view) broken."; + int sum = 0; + Kokkos::parallel_reduce( + rangePolicy2D, + KOKKOS_LAMBDA(const int i, const int j, int& updateMe) { + updateMe += ov(i, j) - aView(i - ov.begin(0), j - ov.begin(1)); + }, + sum); + + ASSERT_EQ(sum, 0) << "deep_copy(offsetView, view) broken."; #endif - } - } - template - void test_offsetview_subview(unsigned int size) - { - {//test subview 1 - Kokkos::Experimental::OffsetView sliceMe("offsetToSlice", {-10, 20}); - { - auto offsetSubviewa = Kokkos::Experimental::subview(sliceMe, 0); - ASSERT_EQ(offsetSubviewa.Rank, 0) << "subview of offset is broken."; - } - - } - {//test subview 2 - Kokkos::Experimental::OffsetView sliceMe("offsetToSlice", {-10,20}, {-20,30}); - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(),-2); - ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; - } - - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe, 0, Kokkos::ALL()); - ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; - } - } + } +} + +template +void test_offsetview_unmanaged_construction() { + // Preallocated memory (Only need a valid address for this test) + Scalar s; + + { + // Constructing an OffsetView directly around our preallocated memory + Kokkos::Array begins1{{2}}; + Kokkos::Array ends1{{3}}; + Kokkos::Experimental::OffsetView ov1(&s, begins1, ends1); + + // Constructing an OffsetView around an unmanaged View of our preallocated + // memory + Kokkos::View v1(&s, ends1[0] - begins1[0]); + Kokkos::Experimental::OffsetView ovv1(v1, begins1); + + // They should match + ASSERT_EQ(ovv1, ov1) + << "OffsetView unmanaged construction fails for rank 1"; + } + + { + Kokkos::Array begins2{{-2, -7}}; + Kokkos::Array ends2{{5, -3}}; + Kokkos::Experimental::OffsetView ov2(&s, begins2, ends2); + + Kokkos::View v2(&s, ends2[0] - begins2[0], + ends2[1] - begins2[1]); + Kokkos::Experimental::OffsetView ovv2(v2, begins2); + + ASSERT_EQ(ovv2, ov2) + << "OffsetView unmanaged construction fails for rank 2"; + } + + { + Kokkos::Array begins3{{2, 3, 5}}; + Kokkos::Array ends3{{7, 11, 13}}; + Kokkos::Experimental::OffsetView ovv3(&s, begins3, + ends3); + + Kokkos::View v3(&s, ends3[0] - begins3[0], + ends3[1] - begins3[1], + ends3[2] - begins3[2]); + Kokkos::Experimental::OffsetView ov3(v3, begins3); + + ASSERT_EQ(ovv3, ov3) + << "OffsetView unmanaged construction fails for rank 3"; + } + + { + // Test all four public constructor overloads (begins_type x + // index_list_type) + Kokkos::Array begins{{-3}}; + Kokkos::Array ends{{2}}; + + Kokkos::Experimental::OffsetView bb(&s, begins, ends); + Kokkos::Experimental::OffsetView bi(&s, begins, {2}); + Kokkos::Experimental::OffsetView ib(&s, {-3}, ends); + Kokkos::Experimental::OffsetView ii(&s, {-3}, {2}); + + ASSERT_EQ(bb, bi); + ASSERT_EQ(bb, ib); + ASSERT_EQ(bb, ii); + } + +#ifdef KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST + { + using offset_view_type = Kokkos::Experimental::OffsetView; + + // Range calculations must be positive + ASSERT_NO_THROW(offset_view_type(&s, {0}, {1})); + ASSERT_NO_THROW(offset_view_type(&s, {0}, {0})); + ASSERT_THROW(offset_view_type(&s, {0}, {-1}), std::runtime_error); + } + + { + using offset_view_type = Kokkos::Experimental::OffsetView; + + // Range calculations must not overflow + ASSERT_NO_THROW(offset_view_type(&s, {0}, {0x7fffffffffffffffl})); + ASSERT_THROW(offset_view_type(&s, {-1}, {0x7fffffffffffffffl}), + std::runtime_error); + ASSERT_THROW( + offset_view_type(&s, {-0x7fffffffffffffffl - 1}, {0x7fffffffffffffffl}), + std::runtime_error); + ASSERT_THROW(offset_view_type(&s, {-0x7fffffffffffffffl - 1}, {0}), + std::runtime_error); + } + + { + using offset_view_type = Kokkos::Experimental::OffsetView; + + // Should throw when the rank of begins and/or ends doesn't match that of + // OffsetView + ASSERT_THROW(offset_view_type(&s, {0}, {1}), std::runtime_error); + ASSERT_THROW(offset_view_type(&s, {0}, {1, 1}), std::runtime_error); + ASSERT_THROW(offset_view_type(&s, {0}, {1, 1, 1}), std::runtime_error); + ASSERT_THROW(offset_view_type(&s, {0, 0}, {1}), std::runtime_error); + ASSERT_NO_THROW(offset_view_type(&s, {0, 0}, {1, 1})); + ASSERT_THROW(offset_view_type(&s, {0, 0}, {1, 1, 1}), std::runtime_error); + ASSERT_THROW(offset_view_type(&s, {0, 0, 0}, {1}), std::runtime_error); + ASSERT_THROW(offset_view_type(&s, {0, 0, 0}, {1, 1}), std::runtime_error); + ASSERT_THROW(offset_view_type(&s, {0, 0, 0}, {1, 1, 1}), + std::runtime_error); + } +#endif // KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST +} + +template +void test_offsetview_subview(unsigned int size) { + { // test subview 1 + Kokkos::Experimental::OffsetView sliceMe("offsetToSlice", + {-10, 20}); + { + auto offsetSubviewa = Kokkos::Experimental::subview(sliceMe, 0); + ASSERT_EQ(offsetSubviewa.Rank, 0) << "subview of offset is broken."; + } + } + { // test subview 2 + Kokkos::Experimental::OffsetView sliceMe( + "offsetToSlice", {-10, 20}, {-20, 30}); + { + auto offsetSubview = + Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), -2); + ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; + } + + { + auto offsetSubview = + Kokkos::Experimental::subview(sliceMe, 0, Kokkos::ALL()); + ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; + } + } + + { // test subview rank 3 + + Kokkos::Experimental::OffsetView sliceMe( + "offsetToSlice", {-10, 20}, {-20, 30}, {-30, 40}); + + // slice 1 + { + auto offsetSubview = Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), + Kokkos::ALL(), 0); + ASSERT_EQ(offsetSubview.Rank, 2) << "subview of offset is broken."; + } + { + auto offsetSubview = Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), + 0, Kokkos::ALL()); + ASSERT_EQ(offsetSubview.Rank, 2) << "subview of offset is broken."; + } + + { + auto offsetSubview = Kokkos::Experimental::subview( + sliceMe, 0, Kokkos::ALL(), Kokkos::ALL()); + ASSERT_EQ(offsetSubview.Rank, 2) << "subview of offset is broken."; + } + { + auto offsetSubview = Kokkos::Experimental::subview( + sliceMe, 0, Kokkos::ALL(), Kokkos::make_pair(-30, -21)); + ASSERT_EQ(offsetSubview.Rank, 2) << "subview of offset is broken."; + + ASSERT_EQ(offsetSubview.begin(0), -20); + ASSERT_EQ(offsetSubview.end(0), 31); + ASSERT_EQ(offsetSubview.begin(1), 0); + ASSERT_EQ(offsetSubview.end(1), 9); +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) + typedef Kokkos::MDRangePolicy, + Kokkos::IndexType > + range_type; + typedef typename range_type::point_type point_type; - {//test subview rank 3 + const int b0 = offsetSubview.begin(0); + const int b1 = offsetSubview.begin(1); - Kokkos::Experimental::OffsetView sliceMe("offsetToSlice", {-10,20}, {-20,30}, {-30,40}); + const int e0 = offsetSubview.end(0); + const int e1 = offsetSubview.end(1); - //slice 1 - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe,Kokkos::ALL(),Kokkos::ALL(), 0); - ASSERT_EQ(offsetSubview.Rank, 2) << "subview of offset is broken."; - } - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe,Kokkos::ALL(), 0,Kokkos::ALL()); - ASSERT_EQ(offsetSubview.Rank, 2) << "subview of offset is broken."; - } + range_type rangeP2D(point_type{{b0, b1}}, point_type{{e0, e1}}); - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe,0, Kokkos::ALL(),Kokkos::ALL()); - ASSERT_EQ(offsetSubview.Rank, 2) << "subview of offset is broken."; + Kokkos::parallel_for( + rangeP2D, + KOKKOS_LAMBDA(const int i, const int j) { offsetSubview(i, j) = 6; }); - } - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe,0, Kokkos::ALL(), Kokkos::make_pair(-30, -21)); - ASSERT_EQ(offsetSubview.Rank, 2) << "subview of offset is broken."; + int sum = 0; + Kokkos::parallel_reduce( + rangeP2D, + KOKKOS_LAMBDA(const int i, const int j, int& updateMe) { + updateMe += offsetSubview(i, j); + }, + sum); - ASSERT_EQ(offsetSubview.begin(0) , -20); - ASSERT_EQ(offsetSubview.end(0) , 31); - ASSERT_EQ(offsetSubview.begin(1) , 0); - ASSERT_EQ(offsetSubview.end(1) , 9); + ASSERT_EQ(sum, 6 * (e0 - b0) * (e1 - b1)); +#endif + } + + // slice 2 + { + auto offsetSubview = + Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), 0, 0); + ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; + } + { + auto offsetSubview = + Kokkos::Experimental::subview(sliceMe, 0, 0, Kokkos::ALL()); + ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; + } + + { + auto offsetSubview = + Kokkos::Experimental::subview(sliceMe, 0, Kokkos::ALL(), 0); + ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; + } + } + + { // test subview rank 4 + + Kokkos::Experimental::OffsetView sliceMe( + "offsetToSlice", {-10, 20}, {-20, 30}, {-30, 40}, {-40, 50}); + + // slice 1 + { + auto offsetSubview = Kokkos::Experimental::subview( + sliceMe, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), 0); + ASSERT_EQ(offsetSubview.Rank, 3) << "subview of offset is broken."; + } + { + auto offsetSubview = Kokkos::Experimental::subview( + sliceMe, Kokkos::ALL(), Kokkos::ALL(), 0, Kokkos::ALL()); + ASSERT_EQ(offsetSubview.Rank, 3) << "subview of offset is broken."; + } + { + auto offsetSubview = Kokkos::Experimental::subview( + sliceMe, Kokkos::ALL(), 0, Kokkos::ALL(), Kokkos::ALL()); + ASSERT_EQ(offsetSubview.Rank, 3) << "subview of offset is broken."; + } + { + auto offsetSubview = Kokkos::Experimental::subview( + sliceMe, 0, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL()); + ASSERT_EQ(offsetSubview.Rank, 3) << "subview of offset is broken."; + } + + // slice 2 + auto offsetSubview2a = Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), + Kokkos::ALL(), 0, 0); + ASSERT_EQ(offsetSubview2a.Rank, 2) << "subview of offset is broken."; + { + auto offsetSubview2b = Kokkos::Experimental::subview( + sliceMe, Kokkos::ALL(), 0, Kokkos::ALL(), 0); + ASSERT_EQ(offsetSubview2b.Rank, 2) << "subview of offset is broken."; + } + { + auto offsetSubview2b = Kokkos::Experimental::subview( + sliceMe, Kokkos::ALL(), 0, 0, Kokkos::ALL()); + ASSERT_EQ(offsetSubview2b.Rank, 2) << "subview of offset is broken."; + } + { + auto offsetSubview2b = Kokkos::Experimental::subview( + sliceMe, 0, Kokkos::ALL(), 0, Kokkos::ALL()); + ASSERT_EQ(offsetSubview2b.Rank, 2) << "subview of offset is broken."; + } + { + auto offsetSubview2b = Kokkos::Experimental::subview( + sliceMe, 0, 0, Kokkos::ALL(), Kokkos::ALL()); + ASSERT_EQ(offsetSubview2b.Rank, 2) << "subview of offset is broken."; + } + // slice 3 + { + auto offsetSubview = + Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), 0, 0, 0); + ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; + } + { + auto offsetSubview = + Kokkos::Experimental::subview(sliceMe, 0, Kokkos::ALL(), 0, 0); + ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; + } + { + auto offsetSubview = + Kokkos::Experimental::subview(sliceMe, 0, 0, Kokkos::ALL(), 0); + ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; + } + { + auto offsetSubview = + Kokkos::Experimental::subview(sliceMe, 0, 0, 0, Kokkos::ALL()); + ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; + } + } +} #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) - typedef Kokkos::MDRangePolicy, Kokkos::IndexType > range_type; - typedef typename range_type::point_type point_type; - - const int b0 = offsetSubview.begin(0); - const int b1 = offsetSubview.begin(1); - - const int e0 = offsetSubview.end(0); - const int e1 = offsetSubview.end(1); - - range_type rangeP2D(point_type{ {b0, b1 } }, point_type{ { e0, e1} }); +template +KOKKOS_INLINE_FUNCTION T std_accumulate(InputIt first, InputIt last, T init, + BinaryOperation op) { + for (; first != last; ++first) { + init = op(std::move(init), *first); + } + return init; +} + +KOKKOS_INLINE_FUNCTION int element(std::initializer_list il) { + return std_accumulate(il.begin(), il.end(), 0, + [](int l, int r) { return l * 10 + r; }); +} + +template +void test_offsetview_offsets_rank1() { + using data_type = int*; + using view_type = Kokkos::View; + using index_type = Kokkos::IndexType; + using execution_policy = Kokkos::RangePolicy; + using offset_view_type = Kokkos::Experimental::OffsetView; + + view_type v("View1", 10); + Kokkos::parallel_for( + "For1", execution_policy(0, v.extent_int(0)), + KOKKOS_LAMBDA(const int i) { v(i) = element({i}); }); + + int errors; + Kokkos::parallel_reduce( + "Reduce1", execution_policy(-3, 4), + KOKKOS_LAMBDA(const int ii, int& lerrors) { + offset_view_type ov(v, {ii}); + lerrors += (ov(3) != element({3 - ii})); + }, + errors); + + ASSERT_EQ(0, errors); +} + +template +void test_offsetview_offsets_rank2() { + using data_type = int**; + using view_type = Kokkos::View; + using index_type = Kokkos::IndexType; + using execution_policy = Kokkos::RangePolicy; + using offset_view_type = Kokkos::Experimental::OffsetView; + + view_type v("View2", 10, 10); + Kokkos::parallel_for( + "For2", execution_policy(0, v.extent_int(0)), KOKKOS_LAMBDA(const int i) { + for (int j = 0; j != v.extent_int(1); ++j) { + v(i, j) = element({i, j}); + } + }); + + int errors; + Kokkos::parallel_reduce( + "Reduce2", execution_policy(-3, 4), + KOKKOS_LAMBDA(const int ii, int& lerrors) { + for (int jj = -3; jj <= 3; ++jj) { + offset_view_type ov(v, {ii, jj}); + lerrors += (ov(3, 3) != element({3 - ii, 3 - jj})); + } + }, + errors); + + ASSERT_EQ(0, errors); +} + +template +void test_offsetview_offsets_rank3() { + using data_type = int***; + using view_type = Kokkos::View; + using index_type = Kokkos::IndexType; + using execution_policy = Kokkos::RangePolicy; + using offset_view_type = Kokkos::Experimental::OffsetView; + + view_type v("View3", 10, 10, 10); + Kokkos::parallel_for( + "For3", execution_policy(0, v.extent_int(0)), KOKKOS_LAMBDA(const int i) { + for (int j = 0; j != v.extent_int(1); ++j) { + for (int k = 0; k != v.extent_int(2); ++k) { + v(i, j, k) = element({i, j, k}); + } + } + }); + + int errors; + Kokkos::parallel_reduce( + "Reduce3", execution_policy(-3, 4), + KOKKOS_LAMBDA(const int ii, int& lerrors) { + for (int jj = -3; jj <= 3; ++jj) { + for (int kk = -3; kk <= 3; ++kk) { + offset_view_type ov(v, {ii, jj, kk}); + lerrors += (ov(3, 3, 3) != element({3 - ii, 3 - jj, 3 - kk})); + } + } + }, + errors); - Kokkos::parallel_for(rangeP2D, KOKKOS_LAMBDA(const int i, const int j) { - offsetSubview(i,j) = 6; - } - ); + ASSERT_EQ(0, errors); +} +#endif - int sum = 0; - Kokkos::parallel_reduce(rangeP2D, KOKKOS_LAMBDA(const int i, const int j, int & updateMe){ - updateMe += offsetSubview(i, j); - }, sum); +TEST(TEST_CATEGORY, offsetview_construction) { + test_offsetview_construction(10); +} - ASSERT_EQ(sum, 6*(e0-b0)*(e1-b1)); -#endif - } - - // slice 2 - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), 0, 0); - ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; - } - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe, 0, 0, Kokkos::ALL()); - ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; - } - - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe, 0, Kokkos::ALL(), 0); - ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; - } - } +TEST(TEST_CATEGORY, offsetview_unmanaged_construction) { + test_offsetview_unmanaged_construction(); +} - {//test subview rank 4 - - Kokkos::Experimental::OffsetView sliceMe("offsetToSlice", {-10,20}, {-20,30}, {-30,40}, {-40, 50}); - - //slice 1 - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(),Kokkos::ALL(), Kokkos::ALL(), 0); - ASSERT_EQ(offsetSubview.Rank, 3) << "subview of offset is broken."; - } - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), Kokkos::ALL(), 0, Kokkos::ALL()); - ASSERT_EQ(offsetSubview.Rank, 3) << "subview of offset is broken."; - } - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe ,Kokkos::ALL(), 0, Kokkos::ALL(),Kokkos::ALL()); - ASSERT_EQ(offsetSubview.Rank, 3) << "subview of offset is broken."; - } - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe , 0, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL() ); - ASSERT_EQ(offsetSubview.Rank, 3) << "subview of offset is broken."; - } - - // slice 2 - auto offsetSubview2a = Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), Kokkos::ALL(), 0, 0); - ASSERT_EQ(offsetSubview2a.Rank, 2) << "subview of offset is broken."; - { - auto offsetSubview2b = Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), 0, Kokkos::ALL(), 0); - ASSERT_EQ(offsetSubview2b.Rank, 2) << "subview of offset is broken."; - } - { - auto offsetSubview2b = Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), 0, 0, Kokkos::ALL()); - ASSERT_EQ(offsetSubview2b.Rank, 2) << "subview of offset is broken."; - } - { - auto offsetSubview2b = Kokkos::Experimental::subview(sliceMe, 0, Kokkos::ALL(), 0, Kokkos::ALL()); - ASSERT_EQ(offsetSubview2b.Rank, 2) << "subview of offset is broken."; - } - { - auto offsetSubview2b = Kokkos::Experimental::subview(sliceMe, 0, 0, Kokkos::ALL(), Kokkos::ALL()); - ASSERT_EQ(offsetSubview2b.Rank, 2) << "subview of offset is broken."; - } - // slice 3 - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), 0, 0, 0); - ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; - } - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe, 0, Kokkos::ALL(), 0, 0); - ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; - } - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe, 0, 0, Kokkos::ALL(), 0); - ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; - } - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe, 0, 0, 0, Kokkos::ALL()); - ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; - } +TEST(TEST_CATEGORY, offsetview_subview) { + test_offsetview_subview(10); +} - } +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +TEST(TEST_CATEGORY, offsetview_offsets_rank1) { + test_offsetview_offsets_rank1(); +} - } +TEST(TEST_CATEGORY, offsetview_offsets_rank2) { + test_offsetview_offsets_rank2(); +} - TEST_F( TEST_CATEGORY, offsetview_construction) { - test_offsetview_construction(10); - } - TEST_F( TEST_CATEGORY, offsetview_subview) { - test_offsetview_subview(10); - } +TEST(TEST_CATEGORY, offsetview_offsets_rank3) { + test_offsetview_offsets_rank3(); +} +#endif -} // namespace Test +} // namespace Test #endif /* CONTAINERS_UNIT_TESTS_TESTOFFSETVIEW_HPP_ */ diff --git a/lib/kokkos/containers/unit_tests/TestScatterView.hpp b/lib/kokkos/containers/unit_tests/TestScatterView.hpp index a9d97b32f3..93b69cc769 100644 --- a/lib/kokkos/containers/unit_tests/TestScatterView.hpp +++ b/lib/kokkos/containers/unit_tests/TestScatterView.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,381 +46,378 @@ #define KOKKOS_TEST_SCATTER_VIEW_HPP #include +#include namespace Test { -template +template struct test_scatter_view_impl_cls; -template -struct test_scatter_view_impl_cls -{ -public: +template +struct test_scatter_view_impl_cls { + public: + typedef Kokkos::Experimental::ScatterView + scatter_view_type; - typedef Kokkos::Experimental::ScatterView - < double*[3] - , Layout - , ExecSpace - , Kokkos::Experimental::ScatterSum - , duplication - , contribution - > scatter_view_type; + typedef Kokkos::View orig_view_type; - typedef Kokkos::View orig_view_type; + scatter_view_type scatter_view; + int scatterSize; + test_scatter_view_impl_cls(const scatter_view_type& view) { + scatter_view = view; + scatterSize = 0; + } - scatter_view_type scatter_view; - int scatterSize; + void initialize(orig_view_type orig) { + auto host_view = + Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); + Kokkos::fence(); + for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); + ++i) { + host_view(i, 0) = 0.0; + host_view(i, 1) = 0.0; + host_view(i, 2) = 0.0; + } + Kokkos::fence(); + Kokkos::deep_copy(orig, host_view); + } - test_scatter_view_impl_cls(const scatter_view_type& view){ - scatter_view = view; - scatterSize = 0; - } + void run_parallel(int n) { + scatterSize = n; + auto policy = Kokkos::RangePolicy(0, n); + Kokkos::parallel_for(policy, *this, "scatter_view_test: Sum"); + } - void initialize(orig_view_type orig) { - auto host_view = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); - Kokkos::fence(); - for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); ++i) { - host_view(i, 0) = 0.0; - host_view(i, 1) = 0.0; - host_view(i, 2) = 0.0; - } - Kokkos::fence(); - Kokkos::deep_copy(orig, host_view); - } - - void run_parallel(int n) { - scatterSize = n; - auto policy = Kokkos::RangePolicy(0, n); - Kokkos::parallel_for(policy, *this, "scatter_view_test: Sum"); - } - - KOKKOS_INLINE_FUNCTION - void operator()(int i) const { - auto scatter_access = scatter_view.access(); - auto scatter_access_atomic = scatter_view.template access(); - for (int j = 0; j < 10; ++j) { - auto k = (i + j) % scatterSize; - scatter_access(k, 0) += 4.2; - scatter_access_atomic(k, 1) += 2.0; - scatter_access(k, 2) += 1.0; - } + KOKKOS_INLINE_FUNCTION + void operator()(int i) const { + auto scatter_access = scatter_view.access(); + auto scatter_access_atomic = + scatter_view.template access(); + for (int j = 0; j < 10; ++j) { + auto k = (i + j) % scatterSize; + scatter_access(k, 0) += 4.2; + scatter_access_atomic(k, 1) += 2.0; + scatter_access(k, 2) += 1.0; } + } - void validateResults(orig_view_type orig) { - auto host_view = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); - Kokkos::fence(); - for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); ++i) { - auto val0 = host_view(i, 0); - auto val1 = host_view(i, 1); - auto val2 = host_view(i, 2); - EXPECT_TRUE(std::fabs((val0 - 84.0) / 84.0) < 1e-14); - EXPECT_TRUE(std::fabs((val1 - 40.0) / 40.0) < 1e-14); - EXPECT_TRUE(std::fabs((val2 - 20.0) / 20.0) < 1e-14); - } + void validateResults(orig_view_type orig) { + auto host_view = + Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); + Kokkos::fence(); + for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); + ++i) { + auto val0 = host_view(i, 0); + auto val1 = host_view(i, 1); + auto val2 = host_view(i, 2); + EXPECT_TRUE(std::fabs((val0 - 84.0) / 84.0) < 1e-14); + EXPECT_TRUE(std::fabs((val1 - 40.0) / 40.0) < 1e-14); + EXPECT_TRUE(std::fabs((val2 - 20.0) / 20.0) < 1e-14); } + } }; +template +struct test_scatter_view_impl_cls { + public: + typedef Kokkos::Experimental::ScatterView + scatter_view_type; -template -struct test_scatter_view_impl_cls -{ -public: - - typedef Kokkos::Experimental::ScatterView - < double*[3] - , Layout - , ExecSpace - , Kokkos::Experimental::ScatterProd - , duplication - , contribution - > scatter_view_type; + typedef Kokkos::View orig_view_type; - typedef Kokkos::View orig_view_type; + scatter_view_type scatter_view; + int scatterSize; + test_scatter_view_impl_cls(const scatter_view_type& view) { + scatter_view = view; + scatterSize = 0; + } - scatter_view_type scatter_view; - int scatterSize; + void initialize(orig_view_type orig) { + auto host_view = + Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); + Kokkos::fence(); + for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); + ++i) { + host_view(i, 0) = 1.0; + host_view(i, 1) = 1.0; + host_view(i, 2) = 1.0; + } + Kokkos::fence(); + Kokkos::deep_copy(orig, host_view); + } - test_scatter_view_impl_cls(const scatter_view_type& view){ - scatter_view = view; - scatterSize = 0; - } + void run_parallel(int n) { + scatterSize = n; + auto policy = Kokkos::RangePolicy(0, n); + Kokkos::parallel_for(policy, *this, "scatter_view_test: Prod"); + } - void initialize(orig_view_type orig) { - auto host_view = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); - Kokkos::fence(); - for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); ++i) { - host_view(i, 0) = 1.0; - host_view(i, 1) = 1.0; - host_view(i, 2) = 1.0; - } - Kokkos::fence(); - Kokkos::deep_copy(orig, host_view); - } - - void run_parallel(int n) { - scatterSize = n; - auto policy = Kokkos::RangePolicy(0, n); - Kokkos::parallel_for(policy, *this, "scatter_view_test: Prod"); - } - - KOKKOS_INLINE_FUNCTION - void operator()(int i) const { - auto scatter_access = scatter_view.access(); - auto scatter_access_atomic = scatter_view.template access(); - for (int j = 0; j < 4; ++j) { - auto k = (i + j) % scatterSize; - scatter_access(k, 0) *= 4.0; - scatter_access_atomic(k, 1) *= 2.0; - scatter_access(k, 2) *= 1.0; - } + KOKKOS_INLINE_FUNCTION + void operator()(int i) const { + auto scatter_access = scatter_view.access(); + auto scatter_access_atomic = + scatter_view.template access(); + for (int j = 0; j < 4; ++j) { + auto k = (i + j) % scatterSize; + scatter_access(k, 0) *= 4.0; + scatter_access_atomic(k, 1) *= 2.0; + scatter_access(k, 2) *= 1.0; } + } - void validateResults(orig_view_type orig) { - auto host_view = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); - Kokkos::fence(); - for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); ++i) { - auto val0 = host_view(i, 0); - auto val1 = host_view(i, 1); - auto val2 = host_view(i, 2); - EXPECT_TRUE(std::fabs((val0 - 65536.0) / 65536.0) < 1e-14); - EXPECT_TRUE(std::fabs((val1 - 256.0) / 256.0) < 1e-14); - EXPECT_TRUE(std::fabs((val2 - 1.0) / 1.0) < 1e-14); - } + void validateResults(orig_view_type orig) { + auto host_view = + Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); + Kokkos::fence(); + for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); + ++i) { + auto val0 = host_view(i, 0); + auto val1 = host_view(i, 1); + auto val2 = host_view(i, 2); + EXPECT_TRUE(std::fabs((val0 - 65536.0) / 65536.0) < 1e-14); + EXPECT_TRUE(std::fabs((val1 - 256.0) / 256.0) < 1e-14); + EXPECT_TRUE(std::fabs((val2 - 1.0) / 1.0) < 1e-14); } + } }; +template +struct test_scatter_view_impl_cls { + public: + typedef Kokkos::Experimental::ScatterView + scatter_view_type; -template -struct test_scatter_view_impl_cls -{ -public: - - typedef Kokkos::Experimental::ScatterView - < double*[3] - , Layout - , ExecSpace - , Kokkos::Experimental::ScatterMin - , duplication - , contribution - > scatter_view_type; + typedef Kokkos::View orig_view_type; - typedef Kokkos::View orig_view_type; + scatter_view_type scatter_view; + int scatterSize; + test_scatter_view_impl_cls(const scatter_view_type& view) { + scatter_view = view; + scatterSize = 0; + } - scatter_view_type scatter_view; - int scatterSize; + void initialize(orig_view_type orig) { + auto host_view = + Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); + Kokkos::fence(); + for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); + ++i) { + host_view(i, 0) = 999999.0; + host_view(i, 1) = 999999.0; + host_view(i, 2) = 999999.0; + } + Kokkos::fence(); + Kokkos::deep_copy(orig, host_view); + } - test_scatter_view_impl_cls(const scatter_view_type& view){ - scatter_view = view; - scatterSize = 0; - } + void run_parallel(int n) { + scatterSize = n; + auto policy = Kokkos::RangePolicy(0, n); + Kokkos::parallel_for(policy, *this, "scatter_view_test: Prod"); + } - void initialize(orig_view_type orig) { - auto host_view = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); - Kokkos::fence(); - for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); ++i) { - host_view(i, 0) = 999999.0; - host_view(i, 1) = 999999.0; - host_view(i, 2) = 999999.0; - } - Kokkos::fence(); - Kokkos::deep_copy(orig, host_view); - } - - void run_parallel(int n) { - scatterSize = n; - auto policy = Kokkos::RangePolicy(0, n); - Kokkos::parallel_for(policy, *this, "scatter_view_test: Prod"); - } - - KOKKOS_INLINE_FUNCTION - void operator()(int i) const { - auto scatter_access = scatter_view.access(); - auto scatter_access_atomic = scatter_view.template access(); - for (int j = 0; j < 4; ++j) { - auto k = (i + j) % scatterSize; - scatter_access(k, 0).update((double)(j+1)*4); - scatter_access_atomic(k, 1).update((double)(j+1)*2.0); - scatter_access(k, 2).update((double)(j+1)*1.0); - } + KOKKOS_INLINE_FUNCTION + void operator()(int i) const { + auto scatter_access = scatter_view.access(); + auto scatter_access_atomic = + scatter_view.template access(); + for (int j = 0; j < 4; ++j) { + auto k = (i + j) % scatterSize; + scatter_access(k, 0).update((double)(j + 1) * 4); + scatter_access_atomic(k, 1).update((double)(j + 1) * 2.0); + scatter_access(k, 2).update((double)(j + 1) * 1.0); } + } - void validateResults(orig_view_type orig) { - auto host_view = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); - Kokkos::fence(); - for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); ++i) { - auto val0 = host_view(i, 0); - auto val1 = host_view(i, 1); - auto val2 = host_view(i, 2); - EXPECT_TRUE(std::fabs((val0 - 4.0) / 4.0) < 1e-14); - EXPECT_TRUE(std::fabs((val1 - 2.0) / 2.0) < 1e-14); - EXPECT_TRUE(std::fabs((val2 - 1.0) / 1.0) < 1e-14); - } + void validateResults(orig_view_type orig) { + auto host_view = + Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); + Kokkos::fence(); + for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); + ++i) { + auto val0 = host_view(i, 0); + auto val1 = host_view(i, 1); + auto val2 = host_view(i, 2); + EXPECT_TRUE(std::fabs((val0 - 4.0) / 4.0) < 1e-14); + EXPECT_TRUE(std::fabs((val1 - 2.0) / 2.0) < 1e-14); + EXPECT_TRUE(std::fabs((val2 - 1.0) / 1.0) < 1e-14); } + } }; +template +struct test_scatter_view_impl_cls { + public: + typedef Kokkos::Experimental::ScatterView + scatter_view_type; -template -struct test_scatter_view_impl_cls -{ -public: - - typedef Kokkos::Experimental::ScatterView - < double*[3] - , Layout - , ExecSpace - , Kokkos::Experimental::ScatterMax - , duplication - , contribution - > scatter_view_type; + typedef Kokkos::View orig_view_type; - typedef Kokkos::View orig_view_type; + scatter_view_type scatter_view; + int scatterSize; + test_scatter_view_impl_cls(const scatter_view_type& view) { + scatter_view = view; + scatterSize = 0; + } - scatter_view_type scatter_view; - int scatterSize; + void initialize(orig_view_type orig) { + auto host_view = + Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); + Kokkos::fence(); + for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); + ++i) { + host_view(i, 0) = 0.0; + host_view(i, 1) = 0.0; + host_view(i, 2) = 0.0; + } + Kokkos::fence(); + Kokkos::deep_copy(orig, host_view); + } - test_scatter_view_impl_cls(const scatter_view_type& view){ - scatter_view = view; - scatterSize = 0; - } + void run_parallel(int n) { + scatterSize = n; + auto policy = Kokkos::RangePolicy(0, n); + Kokkos::parallel_for(policy, *this, "scatter_view_test: Prod"); + } - void initialize(orig_view_type orig) { - auto host_view = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); - Kokkos::fence(); - for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); ++i) { - host_view(i, 0) = 0.0; - host_view(i, 1) = 0.0; - host_view(i, 2) = 0.0; - } - Kokkos::fence(); - Kokkos::deep_copy(orig, host_view); - } - - void run_parallel(int n) { - scatterSize = n; - auto policy = Kokkos::RangePolicy(0, n); - Kokkos::parallel_for(policy, *this, "scatter_view_test: Prod"); - } - - KOKKOS_INLINE_FUNCTION - void operator()(int i) const { - auto scatter_access = scatter_view.access(); - auto scatter_access_atomic = scatter_view.template access(); - for (int j = 0; j < 4; ++j) { - auto k = (i + j) % scatterSize; - scatter_access(k, 0).update((double)(j+1)*4); - scatter_access_atomic(k, 1).update((double)(j+1)*2.0); - scatter_access(k, 2).update((double)(j+1)*1.0); - } + KOKKOS_INLINE_FUNCTION + void operator()(int i) const { + auto scatter_access = scatter_view.access(); + auto scatter_access_atomic = + scatter_view.template access(); + for (int j = 0; j < 4; ++j) { + auto k = (i + j) % scatterSize; + scatter_access(k, 0).update((double)(j + 1) * 4); + scatter_access_atomic(k, 1).update((double)(j + 1) * 2.0); + scatter_access(k, 2).update((double)(j + 1) * 1.0); } + } - void validateResults(orig_view_type orig) { - auto host_view = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); - Kokkos::fence(); - for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); ++i) { - auto val0 = host_view(i, 0); - auto val1 = host_view(i, 1); - auto val2 = host_view(i, 2); - EXPECT_TRUE(std::fabs((val0 - 16.0) / 16.0) < 1e-14); - EXPECT_TRUE(std::fabs((val1 - 8.0) / 8.0) < 1e-14); - EXPECT_TRUE(std::fabs((val2 - 4.0) / 4.0) < 1e-14); - } + void validateResults(orig_view_type orig) { + auto host_view = + Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); + Kokkos::fence(); + for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); + ++i) { + auto val0 = host_view(i, 0); + auto val1 = host_view(i, 1); + auto val2 = host_view(i, 2); + EXPECT_TRUE(std::fabs((val0 - 16.0) / 16.0) < 1e-14); + EXPECT_TRUE(std::fabs((val1 - 8.0) / 8.0) < 1e-14); + EXPECT_TRUE(std::fabs((val2 - 4.0) / 4.0) < 1e-14); } + } }; - - -template -struct test_scatter_view_config -{ +template +struct test_scatter_view_config { public: - typedef typename test_scatter_view_impl_cls::scatter_view_type scatter_view_def; - typedef typename test_scatter_view_impl_cls::orig_view_type orig_view_def; - - test_scatter_view_config() { - } - - void run_test(int n) - { - //Test creation via create_scatter_view - { - orig_view_def original_view("original_view", n); - scatter_view_def scatter_view = Kokkos::Experimental::create_scatter_view - < op - , duplication - , contribution - > (original_view); - - test_scatter_view_impl_cls scatter_view_test_impl(scatter_view); - scatter_view_test_impl.initialize(original_view); - scatter_view_test_impl.run_parallel(n); - - Kokkos::Experimental::contribute(original_view, scatter_view); - scatter_view.reset_except(original_view); - - scatter_view_test_impl.run_parallel(n); - - Kokkos::Experimental::contribute(original_view, scatter_view); - Kokkos::fence(); + typedef + typename test_scatter_view_impl_cls::scatter_view_type + scatter_view_def; + typedef typename test_scatter_view_impl_cls::orig_view_type + orig_view_def; + + test_scatter_view_config() {} + + void run_test(int n) { + // Test creation via create_scatter_view + { + orig_view_def original_view("original_view", n); + scatter_view_def scatter_view = Kokkos::Experimental::create_scatter_view< + op, duplication, contribution>(original_view); + + test_scatter_view_impl_cls + scatter_view_test_impl(scatter_view); + scatter_view_test_impl.initialize(original_view); + scatter_view_test_impl.run_parallel(n); + + Kokkos::Experimental::contribute(original_view, scatter_view); + scatter_view.reset_except(original_view); + + scatter_view_test_impl.run_parallel(n); + + Kokkos::Experimental::contribute(original_view, scatter_view); + Kokkos::fence(); - scatter_view_test_impl.validateResults(original_view); + scatter_view_test_impl.validateResults(original_view); - { + { scatter_view_def persistent_view("persistent", n); auto result_view = persistent_view.subview(); contribute(result_view, persistent_view); Kokkos::fence(); - } - } - //Test creation via constructor - { - orig_view_def original_view("original_view", n); - scatter_view_def scatter_view(original_view); + } + } + // Test creation via constructor + { + orig_view_def original_view("original_view", n); + scatter_view_def scatter_view(original_view); - test_scatter_view_impl_cls scatter_view_test_impl(scatter_view); - scatter_view_test_impl.initialize(original_view); - scatter_view_test_impl.run_parallel(n); + test_scatter_view_impl_cls + scatter_view_test_impl(scatter_view); + scatter_view_test_impl.initialize(original_view); + scatter_view_test_impl.run_parallel(n); - Kokkos::Experimental::contribute(original_view, scatter_view); - scatter_view.reset_except(original_view); + Kokkos::Experimental::contribute(original_view, scatter_view); + scatter_view.reset_except(original_view); - scatter_view_test_impl.run_parallel(n); + scatter_view_test_impl.run_parallel(n); - Kokkos::Experimental::contribute(original_view, scatter_view); - Kokkos::fence(); + Kokkos::Experimental::contribute(original_view, scatter_view); + Kokkos::fence(); - scatter_view_test_impl.validateResults(original_view); + scatter_view_test_impl.validateResults(original_view); - { + { scatter_view_def persistent_view("persistent", n); auto result_view = persistent_view.subview(); contribute(result_view, persistent_view); Kokkos::fence(); - } - } - } - + } + } + } }; - template struct TestDuplicatedScatterView { TestDuplicatedScatterView(int n) { // ScatterSum test - test_scatter_view_config test_sv_right_config; + test_scatter_view_config< + ExecSpace, Kokkos::LayoutRight, Kokkos::Experimental::ScatterDuplicated, + Kokkos::Experimental::ScatterNonAtomic, ScatterType> + test_sv_right_config; test_sv_right_config.run_test(n); - test_scatter_view_config test_sv_left_config; + test_scatter_view_config< + ExecSpace, Kokkos::LayoutLeft, Kokkos::Experimental::ScatterDuplicated, + Kokkos::Experimental::ScatterNonAtomic, ScatterType> + test_sv_left_config; test_sv_left_config.run_test(n); } }; @@ -429,8 +427,7 @@ struct TestDuplicatedScatterView { // UniqueToken can support it template struct TestDuplicatedScatterView { - TestDuplicatedScatterView(int) { - } + TestDuplicatedScatterView(int) {} }; #endif @@ -439,14 +436,12 @@ struct TestDuplicatedScatterView { // UniqueToken can support it template struct TestDuplicatedScatterView { - TestDuplicatedScatterView(int) { - } + TestDuplicatedScatterView(int) {} }; #endif template -void test_scatter_view(int n) -{ +void test_scatter_view(int n) { // all of these configurations should compile okay, but only some of them are // correct and/or sensible in terms of memory use Kokkos::Experimental::UniqueToken unique_token{ExecSpace()}; @@ -456,33 +451,37 @@ void test_scatter_view(int n) // we also test OpenMP with one thread: LAMMPS cares about that) if (unique_token.size() == 1) { test_scatter_view_config test_sv_config; + Kokkos::Experimental::ScatterNonDuplicated, + Kokkos::Experimental::ScatterNonAtomic, + ScatterType> + test_sv_config; test_sv_config.run_test(n); } #ifdef KOKKOS_ENABLE_SERIAL if (!std::is_same::value) { #endif - test_scatter_view_config test_sv_config; - test_sv_config.run_test(n); + test_scatter_view_config + test_sv_config; + test_sv_config.run_test(n); #ifdef KOKKOS_ENABLE_SERIAL } #endif // with hundreds of threads we were running out of memory. // limit (n) so that duplication doesn't exceed 8GB - constexpr std::size_t maximum_allowed_total_bytes = 8ull * 1024ull * 1024ull * 1024ull; - std::size_t const maximum_allowed_copy_bytes = maximum_allowed_total_bytes / std::size_t(unique_token.size()); + constexpr std::size_t maximum_allowed_total_bytes = + 8ull * 1024ull * 1024ull * 1024ull; + std::size_t const maximum_allowed_copy_bytes = + maximum_allowed_total_bytes / std::size_t(unique_token.size()); constexpr std::size_t bytes_per_value = sizeof(double) * 3; - std::size_t const maximum_allowed_copy_values = maximum_allowed_copy_bytes / bytes_per_value; + std::size_t const maximum_allowed_copy_values = + maximum_allowed_copy_bytes / bytes_per_value; n = std::min(n, int(maximum_allowed_copy_values)); TestDuplicatedScatterView duptest(n); } -TEST_F( TEST_CATEGORY, scatterview) { +TEST(TEST_CATEGORY, scatterview) { #ifndef KOKKOS_ENABLE_ROCM test_scatter_view(10); test_scatter_view(10); @@ -492,17 +491,22 @@ TEST_F( TEST_CATEGORY, scatterview) { #ifdef KOKKOS_ENABLE_DEBUG int big_n = 100 * 1000; #else - int big_n = 10 * 1000 * 1000; + +#ifdef KOKKOS_ENABLE_SERIAL + bool is_serial = std::is_same::value; + int big_n = is_serial ? 100 * 1000 : 10000 * 1000; +#else + int big_n = 10000 * 1000; +#endif + #endif - test_scatter_view(big_n); - test_scatter_view(big_n); - test_scatter_view(big_n); - test_scatter_view(big_n); + test_scatter_view(big_n); + test_scatter_view(big_n); + test_scatter_view(big_n); + test_scatter_view(big_n); #endif } -} // namespace Test - -#endif //KOKKOS_TEST_UNORDERED_MAP_HPP - +} // namespace Test +#endif // KOKKOS_TEST_UNORDERED_MAP_HPP diff --git a/lib/kokkos/containers/unit_tests/TestStaticCrsGraph.hpp b/lib/kokkos/containers/unit_tests/TestStaticCrsGraph.hpp index 7ba307079f..15c190242c 100644 --- a/lib/kokkos/containers/unit_tests/TestStaticCrsGraph.hpp +++ b/lib/kokkos/containers/unit_tests/TestStaticCrsGraph.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -52,233 +53,244 @@ namespace Test { namespace TestStaticCrsGraph { -template< class Space > -void run_test_graph() -{ - typedef Kokkos::StaticCrsGraph< unsigned , Space > dView ; - typedef typename dView::HostMirror hView ; +template +void run_test_graph() { + typedef Kokkos::StaticCrsGraph dView; + typedef typename dView::HostMirror hView; - const unsigned LENGTH = 1000 ; - dView dx ; - hView hx ; + const unsigned LENGTH = 1000; + dView dx; + hView hx; - std::vector< std::vector< int > > graph( LENGTH ); + std::vector > graph(LENGTH); - for ( size_t i = 0 ; i < LENGTH ; ++i ) { + for (size_t i = 0; i < LENGTH; ++i) { graph[i].reserve(8); - for ( size_t j = 0 ; j < 8 ; ++j ) { - graph[i].push_back( i + j * 3 ); + for (size_t j = 0; j < 8; ++j) { + graph[i].push_back(i + j * 3); } } - dx = Kokkos::create_staticcrsgraph( "dx" , graph ); - hx = Kokkos::create_mirror( dx ); + dx = Kokkos::create_staticcrsgraph("dx", graph); + hx = Kokkos::create_mirror(dx); - ASSERT_EQ( hx.row_map.extent(0) - 1 , LENGTH ); + ASSERT_EQ(hx.row_map.extent(0) - 1, LENGTH); - for ( size_t i = 0 ; i < LENGTH ; ++i ) { + for (size_t i = 0; i < LENGTH; ++i) { const size_t begin = hx.row_map[i]; - const size_t n = hx.row_map[i+1] - begin ; - ASSERT_EQ( n , graph[i].size() ); - for ( size_t j = 0 ; j < n ; ++j ) { - ASSERT_EQ( (int) hx.entries( j + begin ) , graph[i][j] ); + const size_t n = hx.row_map[i + 1] - begin; + ASSERT_EQ(n, graph[i].size()); + for (size_t j = 0; j < n; ++j) { + ASSERT_EQ((int)hx.entries(j + begin), graph[i][j]); } } // Test row view access - for ( size_t i = 0 ; i < LENGTH ; ++i ) { + for (size_t i = 0; i < LENGTH; ++i) { auto rowView = hx.rowConst(i); - ASSERT_EQ( rowView.length, graph[i].size() ); - for ( size_t j = 0 ; j < rowView.length ; ++j ) { - ASSERT_EQ( rowView.colidx( j ) , graph[i][j] ); - ASSERT_EQ( rowView( j ) , graph[i][j] ); + ASSERT_EQ(rowView.length, graph[i].size()); + for (size_t j = 0; j < rowView.length; ++j) { + ASSERT_EQ(rowView.colidx(j), graph[i][j]); + ASSERT_EQ(rowView(j), graph[i][j]); } } } -template< class Space > -void run_test_graph2() -{ - typedef Kokkos::StaticCrsGraph< unsigned[3] , Space > dView ; - typedef typename dView::HostMirror hView ; +template +void run_test_graph2() { + typedef Kokkos::StaticCrsGraph dView; + typedef typename dView::HostMirror hView; - const unsigned LENGTH = 10 ; + const unsigned LENGTH = 10; - std::vector< size_t > sizes( LENGTH ); + std::vector sizes(LENGTH); - size_t total_length = 0 ; + size_t total_length = 0; - for ( size_t i = 0 ; i < LENGTH ; ++i ) { - total_length += ( sizes[i] = 6 + i % 4 ); + for (size_t i = 0; i < LENGTH; ++i) { + total_length += (sizes[i] = 6 + i % 4); } - dView dx = Kokkos::create_staticcrsgraph( "test" , sizes ); - hView hx = Kokkos::create_mirror( dx ); - hView mx = Kokkos::create_mirror( dx ); + dView dx = Kokkos::create_staticcrsgraph("test", sizes); + hView hx = Kokkos::create_mirror(dx); + hView mx = Kokkos::create_mirror(dx); - ASSERT_EQ( (size_t) dx.row_map.extent(0) , (size_t) LENGTH + 1 ); - ASSERT_EQ( (size_t) hx.row_map.extent(0) , (size_t) LENGTH + 1 ); - ASSERT_EQ( (size_t) mx.row_map.extent(0) , (size_t) LENGTH + 1 ); + ASSERT_EQ((size_t)dx.row_map.extent(0), (size_t)LENGTH + 1); + ASSERT_EQ((size_t)hx.row_map.extent(0), (size_t)LENGTH + 1); + ASSERT_EQ((size_t)mx.row_map.extent(0), (size_t)LENGTH + 1); - ASSERT_EQ( (size_t) dx.entries.extent(0) , (size_t) total_length ); - ASSERT_EQ( (size_t) hx.entries.extent(0) , (size_t) total_length ); - ASSERT_EQ( (size_t) mx.entries.extent(0) , (size_t) total_length ); + ASSERT_EQ((size_t)dx.entries.extent(0), (size_t)total_length); + ASSERT_EQ((size_t)hx.entries.extent(0), (size_t)total_length); + ASSERT_EQ((size_t)mx.entries.extent(0), (size_t)total_length); - ASSERT_EQ( (size_t) dx.entries.extent(1) , (size_t) 3 ); - ASSERT_EQ( (size_t) hx.entries.extent(1) , (size_t) 3 ); - ASSERT_EQ( (size_t) mx.entries.extent(1) , (size_t) 3 ); + ASSERT_EQ((size_t)dx.entries.extent(1), (size_t)3); + ASSERT_EQ((size_t)hx.entries.extent(1), (size_t)3); + ASSERT_EQ((size_t)mx.entries.extent(1), (size_t)3); - for ( size_t i = 0 ; i < LENGTH ; ++i ) { + for (size_t i = 0; i < LENGTH; ++i) { const size_t entry_begin = hx.row_map[i]; - const size_t entry_end = hx.row_map[i+1]; - for ( size_t j = entry_begin ; j < entry_end ; ++j ) { - hx.entries(j,0) = j + 1 ; - hx.entries(j,1) = j + 2 ; - hx.entries(j,2) = j + 3 ; + const size_t entry_end = hx.row_map[i + 1]; + for (size_t j = entry_begin; j < entry_end; ++j) { + hx.entries(j, 0) = j + 1; + hx.entries(j, 1) = j + 2; + hx.entries(j, 2) = j + 3; } } - Kokkos::deep_copy( dx.entries , hx.entries ); - Kokkos::deep_copy( mx.entries , dx.entries ); + Kokkos::deep_copy(dx.entries, hx.entries); + Kokkos::deep_copy(mx.entries, dx.entries); - ASSERT_EQ( mx.row_map.extent(0) , (size_t) LENGTH + 1 ); + ASSERT_EQ(mx.row_map.extent(0), (size_t)LENGTH + 1); - for ( size_t i = 0 ; i < LENGTH ; ++i ) { + for (size_t i = 0; i < LENGTH; ++i) { const size_t entry_begin = mx.row_map[i]; - const size_t entry_end = mx.row_map[i+1]; - ASSERT_EQ( ( entry_end - entry_begin ) , sizes[i] ); - for ( size_t j = entry_begin ; j < entry_end ; ++j ) { - ASSERT_EQ( (size_t) mx.entries( j , 0 ) , ( j + 1 ) ); - ASSERT_EQ( (size_t) mx.entries( j , 1 ) , ( j + 2 ) ); - ASSERT_EQ( (size_t) mx.entries( j , 2 ) , ( j + 3 ) ); + const size_t entry_end = mx.row_map[i + 1]; + ASSERT_EQ((entry_end - entry_begin), sizes[i]); + for (size_t j = entry_begin; j < entry_end; ++j) { + ASSERT_EQ((size_t)mx.entries(j, 0), (j + 1)); + ASSERT_EQ((size_t)mx.entries(j, 1), (j + 2)); + ASSERT_EQ((size_t)mx.entries(j, 2), (j + 3)); } } } -template< class Space > -void run_test_graph3(size_t B, size_t N) -{ +template +void run_test_graph3(size_t B, size_t N) { srand(10310); - typedef Kokkos::StaticCrsGraph< int , Space > dView ; - typedef typename dView::HostMirror hView ; + typedef Kokkos::StaticCrsGraph dView; + typedef typename dView::HostMirror hView; - const unsigned LENGTH = 2000 ; + const unsigned LENGTH = 2000; - std::vector< size_t > sizes( LENGTH ); + std::vector sizes(LENGTH); - size_t total_length = 0 ; + size_t total_length = 0; - for ( size_t i = 0 ; i < LENGTH ; ++i ) { - sizes[i] = rand()%1000; + for (size_t i = 0; i < LENGTH; ++i) { + sizes[i] = rand() % 1000; } - sizes[1] = N; + sizes[1] = N; sizes[1998] = N; - for ( size_t i = 0 ; i < LENGTH ; ++i ) { + for (size_t i = 0; i < LENGTH; ++i) { total_length += sizes[i]; } - int C = 0; - dView dx = Kokkos::create_staticcrsgraph( "test" , sizes ); - dx.create_block_partitioning(B,C); - hView hx = Kokkos::create_mirror( dx ); + int C = 0; + dView dx = Kokkos::create_staticcrsgraph("test", sizes); + dx.create_block_partitioning(B, C); + hView hx = Kokkos::create_mirror(dx); - for( size_t i = 0; i2*((hx.row_map(hx.numRows())+C*hx.numRows())/B))&&(hx.row_block_offsets(i+1)>hx.row_block_offsets(i)+1)); + ASSERT_FALSE( + (ne > 2 * ((hx.row_map(hx.numRows()) + C * hx.numRows()) / B)) && + (hx.row_block_offsets(i + 1) > hx.row_block_offsets(i) + 1)); } } -template< class Space > -void run_test_graph4() -{ +template +void run_test_graph4() { typedef unsigned ordinal_type; typedef Kokkos::LayoutRight layout_type; typedef Space space_type; typedef Kokkos::MemoryUnmanaged memory_traits_type; #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - typedef Kokkos::StaticCrsGraph< ordinal_type , layout_type , space_type , ordinal_type , memory_traits_type > dView ; + typedef Kokkos::StaticCrsGraph + dView; #else - typedef Kokkos::StaticCrsGraph< ordinal_type , layout_type , space_type , memory_traits_type > dView ; + typedef Kokkos::StaticCrsGraph + dView; #endif - typedef typename dView::HostMirror hView ; + typedef typename dView::HostMirror hView; - dView dx ; + dView dx; - // StaticCrsGraph with Unmanaged trait will contain row_map and entries members - // with the Unmanaged memory trait. - // Use of such a StaticCrsGraph requires an allocaton of memory for the unmanaged views - // to wrap. + // StaticCrsGraph with Unmanaged trait will contain row_map and entries + // members with the Unmanaged memory trait. Use of such a StaticCrsGraph + // requires an allocaton of memory for the unmanaged views to wrap. // // In this test, a graph (via raw arrays) resides on the host. - // The pointers are wrapped by unmanaged Views. - // To make use of this on the device, managed device Views are created (allocation required), - // and data from the unmanaged host views is deep copied to the device Views - // Unmanaged views of the appropriate type wrap the device data and are assigned to - // their corresponding unmanaged view members of the unmanaged StaticCrsGraph + // The pointers are wrapped by unmanaged Views. + // To make use of this on the device, managed device Views are created + // (allocation required), and data from the unmanaged host views is deep + // copied to the device Views Unmanaged views of the appropriate type wrap the + // device data and are assigned to their corresponding unmanaged view members + // of the unmanaged StaticCrsGraph // Data types for raw pointers storing StaticCrsGraph info typedef typename dView::size_type ptr_row_map_type; typedef typename dView::data_type ptr_entries_type; const ordinal_type numRows = 8; - const ordinal_type nnz = 24; - ptr_row_map_type ptrRaw[] = {0, 4, 8, 10, 12, 14, 16, 20, 24}; - ptr_entries_type indRaw[] = {0, 1, 4, 5, 0, 1, 4, 5, 2, 3, 2, 3, 4, 5, 4, 5, 2, 3, 6, 7, 2, 3, 6, 7}; + const ordinal_type nnz = 24; + ptr_row_map_type ptrRaw[] = {0, 4, 8, 10, 12, 14, 16, 20, 24}; + ptr_entries_type indRaw[] = {0, 1, 4, 5, 0, 1, 4, 5, 2, 3, 2, 3, + 4, 5, 4, 5, 2, 3, 6, 7, 2, 3, 6, 7}; // Wrap pointers in unmanaged host views - typedef typename hView::row_map_type local_row_map_type ; - typedef typename hView::entries_type local_entries_type ; - local_row_map_type unman_row_map( &(ptrRaw[0]) , numRows+1 ); - local_entries_type unman_entries( &(indRaw[0]) , nnz ); + typedef typename hView::row_map_type local_row_map_type; + typedef typename hView::entries_type local_entries_type; + local_row_map_type unman_row_map(&(ptrRaw[0]), numRows + 1); + local_entries_type unman_entries(&(indRaw[0]), nnz); - hView hx ; - hx = hView( unman_entries, unman_row_map ); + hView hx; + hx = hView(unman_entries, unman_row_map); // Create the device Views for copying the host arrays into - // An allocation is needed on the device for the unmanaged StaticCrsGraph to wrap the pointer - typedef typename Kokkos::View< ptr_row_map_type*, layout_type, space_type > d_row_map_view_type; - typedef typename Kokkos::View< ptr_entries_type*, layout_type, space_type > d_entries_view_type; - - d_row_map_view_type tmp_row_map( "tmp_row_map", numRows+1 ); - d_entries_view_type tmp_entries( "tmp_entries", nnz ); - - Kokkos::deep_copy (tmp_row_map, unman_row_map); - Kokkos::deep_copy (tmp_entries, unman_entries); - - // Wrap the pointer in unmanaged View and assign to the corresponding StaticCrsGraph member - dx.row_map = typename dView::row_map_type(tmp_row_map.data(), numRows+1); + // An allocation is needed on the device for the unmanaged StaticCrsGraph to + // wrap the pointer + typedef typename Kokkos::View + d_row_map_view_type; + typedef typename Kokkos::View + d_entries_view_type; + + d_row_map_view_type tmp_row_map("tmp_row_map", numRows + 1); + d_entries_view_type tmp_entries("tmp_entries", nnz); + + Kokkos::deep_copy(tmp_row_map, unman_row_map); + Kokkos::deep_copy(tmp_entries, unman_entries); + + // Wrap the pointer in unmanaged View and assign to the corresponding + // StaticCrsGraph member + dx.row_map = typename dView::row_map_type(tmp_row_map.data(), numRows + 1); dx.entries = typename dView::entries_type(tmp_entries.data(), nnz); - ASSERT_TRUE((std::is_same< typename dView::row_map_type::memory_traits , Kokkos::MemoryUnmanaged >::value)); - ASSERT_TRUE((std::is_same< typename dView::entries_type::memory_traits , Kokkos::MemoryUnmanaged >::value)); - ASSERT_TRUE((std::is_same< typename hView::row_map_type::memory_traits , Kokkos::MemoryUnmanaged >::value)); - ASSERT_TRUE((std::is_same< typename hView::entries_type::memory_traits , Kokkos::MemoryUnmanaged >::value)); + ASSERT_TRUE((std::is_same::value)); + ASSERT_TRUE((std::is_same::value)); + ASSERT_TRUE((std::is_same::value)); + ASSERT_TRUE((std::is_same::value)); } } /* namespace TestStaticCrsGraph */ -TEST_F( TEST_CATEGORY , staticcrsgraph ) -{ - TestStaticCrsGraph::run_test_graph< TEST_EXECSPACE >(); - TestStaticCrsGraph::run_test_graph2< TEST_EXECSPACE >(); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(1, 0); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(1, 1000); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(1, 10000); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(1, 100000); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(3, 0); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(3, 1000); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(3, 10000); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(3, 100000); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(75, 0); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(75, 1000); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(75, 10000); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(75, 100000); - TestStaticCrsGraph::run_test_graph4< TEST_EXECSPACE >(); -} +TEST(TEST_CATEGORY, staticcrsgraph) { + TestStaticCrsGraph::run_test_graph(); + TestStaticCrsGraph::run_test_graph2(); + TestStaticCrsGraph::run_test_graph3(1, 0); + TestStaticCrsGraph::run_test_graph3(1, 1000); + TestStaticCrsGraph::run_test_graph3(1, 10000); + TestStaticCrsGraph::run_test_graph3(1, 100000); + TestStaticCrsGraph::run_test_graph3(3, 0); + TestStaticCrsGraph::run_test_graph3(3, 1000); + TestStaticCrsGraph::run_test_graph3(3, 10000); + TestStaticCrsGraph::run_test_graph3(3, 100000); + TestStaticCrsGraph::run_test_graph3(75, 0); + TestStaticCrsGraph::run_test_graph3(75, 1000); + TestStaticCrsGraph::run_test_graph3(75, 10000); + TestStaticCrsGraph::run_test_graph3(75, 100000); + TestStaticCrsGraph::run_test_graph4(); } +} // namespace Test diff --git a/lib/kokkos/containers/unit_tests/TestUnorderedMap.hpp b/lib/kokkos/containers/unit_tests/TestUnorderedMap.hpp index 2d34267df3..82782d3bf4 100644 --- a/lib/kokkos/containers/unit_tests/TestUnorderedMap.hpp +++ b/lib/kokkos/containers/unit_tests/TestUnorderedMap.hpp @@ -1,10 +1,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -22,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -51,8 +52,7 @@ namespace Test { namespace Impl { template -struct TestInsert -{ +struct TestInsert { typedef MapType map_type; typedef typename map_type::execution_space execution_space; typedef uint32_t value_type; @@ -61,14 +61,10 @@ struct TestInsert uint32_t inserts; uint32_t collisions; - TestInsert( map_type arg_map, uint32_t arg_inserts, uint32_t arg_collisions) - : map(arg_map) - , inserts(arg_inserts) - , collisions(arg_collisions) - {} + TestInsert(map_type arg_map, uint32_t arg_inserts, uint32_t arg_collisions) + : map(arg_map), inserts(arg_inserts), collisions(arg_collisions) {} - void testit( bool rehash_on_fail = true ) - { + void testit(bool rehash_on_fail = true) { execution_space().fence(); uint32_t failed_count = 0; @@ -77,138 +73,127 @@ struct TestInsert Kokkos::parallel_reduce(inserts, *this, failed_count); if (rehash_on_fail && failed_count > 0u) { - const uint32_t new_capacity = map.capacity() + ((map.capacity()*3ull)/20u) + failed_count/collisions ; - map.rehash( new_capacity ); + const uint32_t new_capacity = map.capacity() + + ((map.capacity() * 3ull) / 20u) + + failed_count / collisions; + map.rehash(new_capacity); } } while (rehash_on_fail && failed_count > 0u); execution_space().fence(); } - KOKKOS_INLINE_FUNCTION - void init( value_type & failed_count ) const { failed_count = 0; } + void init(value_type &failed_count) const { failed_count = 0; } KOKKOS_INLINE_FUNCTION - void join( volatile value_type & failed_count, const volatile value_type & count ) const - { failed_count += count; } + void join(volatile value_type &failed_count, + const volatile value_type &count) const { + failed_count += count; + } KOKKOS_INLINE_FUNCTION - void operator()(uint32_t i, value_type & failed_count) const - { - const uint32_t key = Near ? i/collisions : i%(inserts/collisions); - if (map.insert(key,i).failed()) ++failed_count; + void operator()(uint32_t i, value_type &failed_count) const { + const uint32_t key = Near ? i / collisions : i % (inserts / collisions); + if (map.insert(key, i).failed()) ++failed_count; } - }; - template - struct TestErase - { - typedef TestErase self_type; +template +struct TestErase { + typedef TestErase self_type; - typedef MapType map_type; - typedef typename MapType::execution_space execution_space; + typedef MapType map_type; + typedef typename MapType::execution_space execution_space; - map_type m_map; - uint32_t m_num_erase; - uint32_t m_num_duplicates; + map_type m_map; + uint32_t m_num_erase; + uint32_t m_num_duplicates; - TestErase(map_type map, uint32_t num_erases, uint32_t num_duplicates) - : m_map(map) - , m_num_erase(num_erases) - , m_num_duplicates(num_duplicates) - {} + TestErase(map_type map, uint32_t num_erases, uint32_t num_duplicates) + : m_map(map), m_num_erase(num_erases), m_num_duplicates(num_duplicates) {} - void testit() - { - execution_space().fence(); - Kokkos::parallel_for(m_num_erase, *this); - execution_space().fence(); - } - - KOKKOS_INLINE_FUNCTION - void operator()(typename execution_space::size_type i) const - { - if (Near) { - m_map.erase(i/m_num_duplicates); - } - else { - m_map.erase(i%(m_num_erase/m_num_duplicates)); - } + void testit() { + execution_space().fence(); + Kokkos::parallel_for(m_num_erase, *this); + execution_space().fence(); + } + KOKKOS_INLINE_FUNCTION + void operator()(typename execution_space::size_type i) const { + if (Near) { + m_map.erase(i / m_num_duplicates); + } else { + m_map.erase(i % (m_num_erase / m_num_duplicates)); } - }; + } +}; - template - struct TestFind - { - typedef MapType map_type; - typedef typename MapType::execution_space::execution_space execution_space; - typedef uint32_t value_type; - - map_type m_map; - uint32_t m_num_insert; - uint32_t m_num_duplicates; - uint32_t m_max_key; - - TestFind(map_type map, uint32_t num_inserts, uint32_t num_duplicates) - : m_map(map) - , m_num_insert(num_inserts) - , m_num_duplicates(num_duplicates) - , m_max_key( ((num_inserts + num_duplicates) - 1)/num_duplicates ) - {} - - void testit(value_type &errors) - { - execution_space().fence(); - Kokkos::parallel_reduce(m_map.capacity(), *this, errors); - execution_space().fence(); - } +template +struct TestFind { + typedef MapType map_type; + typedef typename MapType::execution_space::execution_space execution_space; + typedef uint32_t value_type; - KOKKOS_INLINE_FUNCTION - static void init( value_type & dst) - { - dst = 0; - } + map_type m_map; + uint32_t m_num_insert; + uint32_t m_num_duplicates; + uint32_t m_max_key; - KOKKOS_INLINE_FUNCTION - static void join( volatile value_type & dst, const volatile value_type & src) - { dst += src; } + TestFind(map_type map, uint32_t num_inserts, uint32_t num_duplicates) + : m_map(map), + m_num_insert(num_inserts), + m_num_duplicates(num_duplicates), + m_max_key(((num_inserts + num_duplicates) - 1) / num_duplicates) {} - KOKKOS_INLINE_FUNCTION - void operator()(typename execution_space::size_type i, value_type & errors) const - { - const bool expect_to_find_i = (i < m_max_key); + void testit(value_type &errors) { + execution_space().fence(); + Kokkos::parallel_reduce(m_map.capacity(), *this, errors); + execution_space().fence(); + } - const bool exists = m_map.exists(i); + KOKKOS_INLINE_FUNCTION + static void init(value_type &dst) { dst = 0; } - if (expect_to_find_i && !exists) ++errors; - if (!expect_to_find_i && exists) ++errors; - } - }; + KOKKOS_INLINE_FUNCTION + static void join(volatile value_type &dst, const volatile value_type &src) { + dst += src; + } + + KOKKOS_INLINE_FUNCTION + void operator()(typename execution_space::size_type i, + value_type &errors) const { + const bool expect_to_find_i = (i < m_max_key); -} // namespace Impl + const bool exists = m_map.exists(i); + if (expect_to_find_i && !exists) ++errors; + if (!expect_to_find_i && exists) ++errors; + } +}; +} // namespace Impl template -void test_insert( uint32_t num_nodes , uint32_t num_inserts , uint32_t num_duplicates , bool near ) -{ - typedef Kokkos::UnorderedMap map_type; - typedef Kokkos::UnorderedMap const_map_type; +void test_insert(uint32_t num_nodes, uint32_t num_inserts, + uint32_t num_duplicates, bool near) { + typedef Kokkos::UnorderedMap map_type; + typedef Kokkos::UnorderedMap + const_map_type; - const uint32_t expected_inserts = (num_inserts + num_duplicates -1u) / num_duplicates; + const uint32_t expected_inserts = + (num_inserts + num_duplicates - 1u) / num_duplicates; map_type map; - map.rehash(num_nodes,false); + map.rehash(num_nodes, false); if (near) { - Impl::TestInsert test_insert(map, num_inserts, num_duplicates); + Impl::TestInsert test_insert(map, num_inserts, + num_duplicates); test_insert.testit(); - } else - { - Impl::TestInsert test_insert(map, num_inserts, num_duplicates); + } else { + Impl::TestInsert test_insert(map, num_inserts, + num_duplicates); test_insert.testit(); } @@ -220,19 +205,21 @@ void test_insert( uint32_t num_nodes , uint32_t num_inserts , uint32_t num_dupli const uint32_t map_size = map.size(); - ASSERT_FALSE( map.failed_insert()); + ASSERT_FALSE(map.failed_insert()); { EXPECT_EQ(expected_inserts, map_size); { uint32_t find_errors = 0; - Impl::TestFind test_find(map, num_inserts, num_duplicates); + Impl::TestFind test_find(map, num_inserts, + num_duplicates); test_find.testit(find_errors); - EXPECT_EQ( 0u, find_errors); + EXPECT_EQ(0u, find_errors); } map.begin_erase(); - Impl::TestErase test_erase(map, num_inserts, num_duplicates); + Impl::TestErase test_erase(map, num_inserts, + num_duplicates); test_erase.testit(); map.end_erase(); EXPECT_EQ(0u, map.size()); @@ -240,56 +227,53 @@ void test_insert( uint32_t num_nodes , uint32_t num_inserts , uint32_t num_dupli } template -void test_failed_insert( uint32_t num_nodes) -{ - typedef Kokkos::UnorderedMap map_type; +void test_failed_insert(uint32_t num_nodes) { + typedef Kokkos::UnorderedMap map_type; map_type map(num_nodes); - Impl::TestInsert test_insert(map, 2u*num_nodes, 1u); + Impl::TestInsert test_insert(map, 2u * num_nodes, 1u); test_insert.testit(false /*don't rehash on fail*/); typename Device::execution_space().fence(); - EXPECT_TRUE( map.failed_insert() ); + EXPECT_TRUE(map.failed_insert()); } - - template -void test_deep_copy( uint32_t num_nodes ) -{ - typedef Kokkos::UnorderedMap map_type; - typedef Kokkos::UnorderedMap const_map_type; +void test_deep_copy(uint32_t num_nodes) { + typedef Kokkos::UnorderedMap map_type; + typedef Kokkos::UnorderedMap + const_map_type; - typedef typename map_type::HostMirror host_map_type ; - // typedef Kokkos::UnorderedMap host_map_type; + typedef typename map_type::HostMirror host_map_type; + // typedef Kokkos::UnorderedMap host_map_type; map_type map; - map.rehash(num_nodes,false); + map.rehash(num_nodes, false); { Impl::TestInsert test_insert(map, num_nodes, 1); test_insert.testit(); - ASSERT_EQ( map.size(), num_nodes); - ASSERT_FALSE( map.failed_insert() ); + ASSERT_EQ(map.size(), num_nodes); + ASSERT_FALSE(map.failed_insert()); { uint32_t find_errors = 0; Impl::TestFind test_find(map, num_nodes, 1); test_find.testit(find_errors); - EXPECT_EQ( find_errors, 0u); + EXPECT_EQ(find_errors, 0u); } - } host_map_type hmap; Kokkos::deep_copy(hmap, map); - ASSERT_EQ( map.size(), hmap.size()); - ASSERT_EQ( map.capacity(), hmap.capacity()); + ASSERT_EQ(map.size(), hmap.size()); + ASSERT_EQ(map.capacity(), hmap.capacity()); { uint32_t find_errors = 0; Impl::TestFind test_find(hmap, num_nodes, 1); test_find.testit(find_errors); - EXPECT_EQ( find_errors, 0u); + EXPECT_EQ(find_errors, 0u); } map_type mmap; @@ -297,35 +281,31 @@ void test_deep_copy( uint32_t num_nodes ) const_map_type cmap = mmap; - EXPECT_EQ( cmap.size(), num_nodes); + EXPECT_EQ(cmap.size(), num_nodes); { uint32_t find_errors = 0; Impl::TestFind test_find(cmap, num_nodes, 1); test_find.testit(find_errors); - EXPECT_EQ( find_errors, 0u); + EXPECT_EQ(find_errors, 0u); } - } -TEST_F( TEST_CATEGORY, UnorderedMap_insert) { - for (int i=0; i<500; ++i) { +TEST(TEST_CATEGORY, UnorderedMap_insert) { + for (int i = 0; i < 500; ++i) { test_insert(100000, 90000, 100, true); test_insert(100000, 90000, 100, false); } } -TEST_F( TEST_CATEGORY, UnorderedMap_failed_insert) { - for (int i=0; i<1000; ++i) - test_failed_insert(10000); +TEST(TEST_CATEGORY, UnorderedMap_failed_insert) { + for (int i = 0; i < 1000; ++i) test_failed_insert(10000); } -TEST_F( TEST_CATEGORY, UnorderedMap_deep_copy) { - for (int i=0; i<2; ++i) - test_deep_copy(10000); +TEST(TEST_CATEGORY, UnorderedMap_deep_copy) { + for (int i = 0; i < 2; ++i) test_deep_copy(10000); } -} // namespace Test - -#endif //KOKKOS_TEST_UNORDERED_MAP_HPP +} // namespace Test +#endif // KOKKOS_TEST_UNORDERED_MAP_HPP diff --git a/lib/kokkos/containers/unit_tests/TestVector.hpp b/lib/kokkos/containers/unit_tests/TestVector.hpp index b766ae8718..4174a477c4 100644 --- a/lib/kokkos/containers/unit_tests/TestVector.hpp +++ b/lib/kokkos/containers/unit_tests/TestVector.hpp @@ -1,10 +1,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -22,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -52,85 +53,193 @@ namespace Test { namespace Impl { - template - struct test_vector_combinations - { - typedef test_vector_combinations self_type; - - typedef Scalar scalar_type; - typedef Device execution_space; - - Scalar reference; - Scalar result; - - template - Scalar run_me(unsigned int n){ - Vector a(n,1); - - - a.push_back(2); - a.resize(n+4); - a[n+1] = 3; - a[n+2] = 4; - a[n+3] = 5; - +template +struct test_vector_insert { + typedef Scalar scalar_type; + typedef Device execution_space; + + template + void run_test(Vector& a) { + int n = a.size(); + + auto it = a.begin(); + it += 15; + ASSERT_EQ(*it, scalar_type(1)); + + auto it_return = a.insert(it, scalar_type(3)); + ASSERT_EQ(a.size(), n + 1); + ASSERT_EQ(std::distance(it_return, a.begin() + 15), 0); + + it = a.begin(); + it += 17; +// Looks like some std::vector implementations do not have the restriction +// right on the overload taking three iterators, and thus the following call +// will hit that overload and then fail to compile. +#if defined(KOKKOS_COMPILER_INTEL) && (1700 > KOKKOS_COMPILER_INTEL) +// And at least GCC 4.8.4 doesn't implement vector insert correct for C++11 +// Return type is void ... +#if (__GNUC__ < 5) + a.insert(it, typename Vector::size_type(n + 5), scalar_type(5)); + it_return = a.begin() + 17; +#else + it_return = a.insert(it, typename Vector::size_type(n + 5), scalar_type(5)); +#endif +#else +#if (__GNUC__ < 5) + a.insert(it, n + 5, scalar_type(5)); + it_return = a.begin() + 17; +#else + it_return = a.insert(it, n + 5, scalar_type(5)); +#endif +#endif + + ASSERT_EQ(a.size(), n + 1 + n + 5); + ASSERT_EQ(std::distance(it_return, a.begin() + 17), 0); + + Vector b; + +// Looks like some std::vector implementations do not have the restriction +// right on the overload taking three iterators, and thus the following call +// will hit that overload and then fail to compile. +#if defined(KOKKOS_COMPILER_INTEL) && (1700 > KOKKOS_COMPILER_INTEL) + b.insert(b.begin(), typename Vector::size_type(7), 9); +#else + b.insert(b.begin(), 7, 9); +#endif + ASSERT_EQ(b.size(), 7); + ASSERT_EQ(b[0], scalar_type(9)); + + it = a.begin(); + it += 27 + n; +#if (__GNUC__ < 5) + a.insert(it, b.begin(), b.end()); + it_return = a.begin() + (27 + n); +#else + it_return = a.insert(it, b.begin(), b.end()); +#endif + ASSERT_EQ(a.size(), n + 1 + n + 5 + 7); + ASSERT_EQ(std::distance(it_return, a.begin() + 27 + n), 0); + + // Testing insert at end via all three function interfaces + a.insert(a.end(), 11); +#if defined(KOKKOS_COMPILER_INTEL) && (1700 > KOKKOS_COMPILER_INTEL) + a.insert(a.end(), typename Vector::size_type(2), 12); +#else + a.insert(a.end(), 2, 12); +#endif + a.insert(a.end(), b.begin(), b.end()); + } + + template + void check_test(Vector& a, int n) { + for (int i = 0; i < (int)a.size(); i++) { + if (i == 15) + ASSERT_EQ(a[i], scalar_type(3)); + else if (i > 16 && i < 16 + 6 + n) + ASSERT_EQ(a[i], scalar_type(5)); + else if (i > 26 + n && i < 34 + n) + ASSERT_EQ(a[i], scalar_type(9)); + else if (i == (int)a.size() - 10) + ASSERT_EQ(a[i], scalar_type(11)); + else if ((i == (int)a.size() - 9) || (i == (int)a.size() - 8)) + ASSERT_EQ(a[i], scalar_type(12)); + else if (i > (int)a.size() - 8) + ASSERT_EQ(a[i], scalar_type(9)); + else + ASSERT_EQ(a[i], scalar_type(1)); + } + } - Scalar temp1 = a[2]; - Scalar temp2 = a[n]; - Scalar temp3 = a[n+1]; + test_vector_insert(unsigned int size) { + { + std::vector a(size, scalar_type(1)); + run_test(a); + check_test(a, size); + } + { + Kokkos::vector a(size, scalar_type(1)); + a.sync_device(); + run_test(a); + a.sync_host(); + check_test(a, size); + } + { + Kokkos::vector a(size, scalar_type(1)); + a.sync_host(); + run_test(a); + check_test(a, size); + } + } +}; - a.assign(n+2,-1); +template +struct test_vector_combinations { + typedef test_vector_combinations self_type; - a[2] = temp1; - a[n] = temp2; - a[n+1] = temp3; + typedef Scalar scalar_type; + typedef Device execution_space; - Scalar test1 = 0; - for(unsigned int i=0; i + Scalar run_me(unsigned int n) { + Vector a(n, 1); - a.reserve(n+10); + a.push_back(2); + a.resize(n + 4); + a[n + 1] = 3; + a[n + 2] = 4; + a[n + 3] = 5; - Scalar test3 = 0; - for(unsigned int i=0; i >(size); - result = run_me >(size); - } + a.assign(n + 1, -2); + Scalar test2 = 0; + for (unsigned int i = 0; i < a.size(); i++) test2 += a[i]; - }; + a.reserve(n + 10); -} // namespace Impl + Scalar test3 = 0; + for (unsigned int i = 0; i < a.size(); i++) test3 += a[i]; + return (test1 * test2 + test3) * test2 + test1 * test3; + } + test_vector_combinations(unsigned int size) { + reference = run_me >(size); + result = run_me >(size); + } +}; +} // namespace Impl template -void test_vector_combinations(unsigned int size) -{ - Impl::test_vector_combinations test(size); - ASSERT_EQ( test.reference, test.result); +void test_vector_combinations(unsigned int size) { + Impl::test_vector_combinations test(size); + ASSERT_EQ(test.reference, test.result); } -TEST_F( TEST_CATEGORY, vector_combination) { - test_vector_combinations(10); - test_vector_combinations(3057); +TEST(TEST_CATEGORY, vector_combination) { + test_vector_combinations(10); + test_vector_combinations(3057); } -} // namespace Test +TEST(TEST_CATEGORY, vector_insert) { + Impl::test_vector_insert(3057); +} -#endif //KOKKOS_TEST_UNORDERED_MAP_HPP +} // namespace Test +#endif // KOKKOS_TEST_UNORDERED_MAP_HPP diff --git a/lib/kokkos/containers/unit_tests/TestViewCtorPropEmbeddedDim.hpp b/lib/kokkos/containers/unit_tests/TestViewCtorPropEmbeddedDim.hpp index 2dd5c56cd9..6bac2ca9bd 100644 --- a/lib/kokkos/containers/unit_tests/TestViewCtorPropEmbeddedDim.hpp +++ b/lib/kokkos/containers/unit_tests/TestViewCtorPropEmbeddedDim.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -55,63 +56,58 @@ namespace Test { namespace { -template +template struct TestViewCtorProp_EmbeddedDim { + using ViewIntType = typename Kokkos::View; + using ViewDoubleType = typename Kokkos::View; - using ViewIntType = typename Kokkos::View< int**, ExecSpace >; - using ViewDoubleType = typename Kokkos::View< double*, ExecSpace >; + using DynRankViewIntType = typename Kokkos::DynRankView; + using DynRankViewDoubleType = typename Kokkos::DynRankView; - using DynRankViewIntType = typename Kokkos::DynRankView< int, ExecSpace >; - using DynRankViewDoubleType = typename Kokkos::DynRankView< double, ExecSpace >; - - // Cuda 7.0 has issues with using a lambda in parallel_for to initialize the view - replace with this functor - template < class ViewType > + // Cuda 7.0 has issues with using a lamda in parallel_for to initialize the + // view - replace with this functor + template struct Functor { - ViewType v; - Functor( const ViewType & v_ ) : v(v_) {} + Functor(const ViewType& v_) : v(v_) {} KOKKOS_INLINE_FUNCTION - void operator()( const int i ) const { - v(i) = i; - } - + void operator()(const int i) const { v(i) = i; } }; - - static void test_vcpt( const int N0, const int N1 ) - { - + static void test_vcpt(const int N0, const int N1) { // Create two views to test { - using VIT = typename TestViewCtorProp_EmbeddedDim::ViewIntType ; - using VDT = typename TestViewCtorProp_EmbeddedDim::ViewDoubleType ; + using VIT = typename TestViewCtorProp_EmbeddedDim::ViewIntType; + using VDT = typename TestViewCtorProp_EmbeddedDim::ViewDoubleType; VIT vi1("vi1", N0, N1); VDT vd1("vd1", N0); - // TEST: Test for common type between two views, one with type double, other with type int - // Deduce common value_type and construct a view with that type + // TEST: Test for common type between two views, one with type double, + // other with type int Deduce common value_type and construct a view with + // that type { // Two views auto view_alloc_arg = Kokkos::common_view_alloc_prop(vi1, vd1); - typedef typename decltype( view_alloc_arg )::value_type CommonViewValueType; - typedef typename Kokkos::View< CommonViewValueType*, ExecSpace > CVT; - typedef typename CVT::HostMirror HostCVT; + typedef + typename decltype(view_alloc_arg)::value_type CommonViewValueType; + typedef typename Kokkos::View CVT; + typedef typename CVT::HostMirror HostCVT; - // Construct View using the common type; for case of specialization, an 'embedded_dim' would be stored by view_alloc_arg - CVT cv1( Kokkos::view_alloc( "cv1", view_alloc_arg ), N0*N1 ); + // Construct View using the common type; for case of specialization, an + // 'embedded_dim' would be stored by view_alloc_arg + CVT cv1(Kokkos::view_alloc("cv1", view_alloc_arg), N0 * N1); - Kokkos::parallel_for( Kokkos::RangePolicy< ExecSpace >(0, N0*N1), - Functor(cv1) - ); + Kokkos::parallel_for(Kokkos::RangePolicy(0, N0 * N1), + Functor(cv1)); - HostCVT hcv1 = Kokkos::create_mirror_view( cv1 ); - Kokkos::deep_copy( hcv1, cv1 ); + HostCVT hcv1 = Kokkos::create_mirror_view(cv1); + Kokkos::deep_copy(hcv1, cv1); - ASSERT_EQ( (std::is_same< CommonViewValueType, double >::value) , true ) ; - #if 0 + ASSERT_EQ((std::is_same::value), true); +#if 0 // debug output for ( int i = 0; i < N0*N1; ++i ) { printf(" Output check: hcv1(%d) = %lf\n ", i, hcv1(i) ); @@ -126,91 +122,92 @@ struct TestViewCtorProp_EmbeddedDim { printf("WRONG common value_type\n"); } // end debug output - #endif +#endif } { // Single view auto view_alloc_arg = Kokkos::common_view_alloc_prop(vi1); - typedef typename decltype( view_alloc_arg )::value_type CommonViewValueType; - typedef typename Kokkos::View< CommonViewValueType*, ExecSpace > CVT; - typedef typename CVT::HostMirror HostCVT; + typedef + typename decltype(view_alloc_arg)::value_type CommonViewValueType; + typedef typename Kokkos::View CVT; + typedef typename CVT::HostMirror HostCVT; - // Construct View using the common type; for case of specialization, an 'embedded_dim' would be stored by view_alloc_arg - CVT cv1( Kokkos::view_alloc( "cv1", view_alloc_arg ), N0*N1 ); + // Construct View using the common type; for case of specialization, an + // 'embedded_dim' would be stored by view_alloc_arg + CVT cv1(Kokkos::view_alloc("cv1", view_alloc_arg), N0 * N1); - Kokkos::parallel_for( Kokkos::RangePolicy< ExecSpace >(0, N0*N1), - Functor(cv1) - ); + Kokkos::parallel_for(Kokkos::RangePolicy(0, N0 * N1), + Functor(cv1)); - HostCVT hcv1 = Kokkos::create_mirror_view( cv1 ); - Kokkos::deep_copy( hcv1, cv1 ); + HostCVT hcv1 = Kokkos::create_mirror_view(cv1); + Kokkos::deep_copy(hcv1, cv1); - ASSERT_EQ( (std::is_same< CommonViewValueType, int>::value) , true ) ; + ASSERT_EQ((std::is_same::value), true); } - } // Create two dynamic rank views to test { - using VIT = typename TestViewCtorProp_EmbeddedDim::DynRankViewIntType ; - using VDT = typename TestViewCtorProp_EmbeddedDim::DynRankViewDoubleType ; + using VIT = typename TestViewCtorProp_EmbeddedDim::DynRankViewIntType; + using VDT = typename TestViewCtorProp_EmbeddedDim::DynRankViewDoubleType; VIT vi1("vi1", N0, N1); VDT vd1("vd1", N0); - // TEST: Test for common type between two views, one with type double, other with type int - // Deduce common value_type and construct a view with that type + // TEST: Test for common type between two views, one with type double, + // other with type int Deduce common value_type and construct a view with + // that type { // Two views - auto view_alloc_arg = Kokkos::common_view_alloc_prop( vi1, vd1 ); - typedef typename decltype( view_alloc_arg )::value_type CommonViewValueType; - typedef typename Kokkos::View< CommonViewValueType*, ExecSpace > CVT; - typedef typename CVT::HostMirror HostCVT; - - // Construct View using the common type; for case of specialization, an 'embedded_dim' would be stored by view_alloc_arg - CVT cv1( Kokkos::view_alloc( "cv1", view_alloc_arg ), N0*N1 ); + auto view_alloc_arg = Kokkos::common_view_alloc_prop(vi1, vd1); + typedef + typename decltype(view_alloc_arg)::value_type CommonViewValueType; + typedef typename Kokkos::View CVT; + typedef typename CVT::HostMirror HostCVT; + // Construct View using the common type; for case of specialization, an + // 'embedded_dim' would be stored by view_alloc_arg + CVT cv1(Kokkos::view_alloc("cv1", view_alloc_arg), N0 * N1); - Kokkos::parallel_for( Kokkos::RangePolicy< ExecSpace >(0, N0*N1), - Functor(cv1) - ); + Kokkos::parallel_for(Kokkos::RangePolicy(0, N0 * N1), + Functor(cv1)); - HostCVT hcv1 = Kokkos::create_mirror_view( cv1 ); - Kokkos::deep_copy( hcv1, cv1 ); + HostCVT hcv1 = Kokkos::create_mirror_view(cv1); + Kokkos::deep_copy(hcv1, cv1); - ASSERT_EQ( (std::is_same< CommonViewValueType, double >::value) , true ) ; + ASSERT_EQ((std::is_same::value), true); } { // Single views - auto view_alloc_arg = Kokkos::common_view_alloc_prop( vi1 ); - typedef typename decltype( view_alloc_arg )::value_type CommonViewValueType; - typedef typename Kokkos::View< CommonViewValueType*, ExecSpace > CVT; - typedef typename CVT::HostMirror HostCVT; + auto view_alloc_arg = Kokkos::common_view_alloc_prop(vi1); + typedef + typename decltype(view_alloc_arg)::value_type CommonViewValueType; + typedef typename Kokkos::View CVT; + typedef typename CVT::HostMirror HostCVT; - // Construct View using the common type; for case of specialization, an 'embedded_dim' would be stored by view_alloc_arg - CVT cv1( Kokkos::view_alloc( "cv1", view_alloc_arg ), N0*N1 ); + // Construct View using the common type; for case of specialization, an + // 'embedded_dim' would be stored by view_alloc_arg + CVT cv1(Kokkos::view_alloc("cv1", view_alloc_arg), N0 * N1); - Kokkos::parallel_for( Kokkos::RangePolicy< ExecSpace >(0, N0*N1), - Functor(cv1) - ); + Kokkos::parallel_for(Kokkos::RangePolicy(0, N0 * N1), + Functor(cv1)); - HostCVT hcv1 = Kokkos::create_mirror_view( cv1 ); - Kokkos::deep_copy( hcv1, cv1 ); + HostCVT hcv1 = Kokkos::create_mirror_view(cv1); + Kokkos::deep_copy(hcv1, cv1); - ASSERT_EQ( (std::is_same< CommonViewValueType, int>::value) , true ) ; + ASSERT_EQ((std::is_same::value), true); } } + } // end test_vcpt - } // end test_vcpt - -}; // end struct +}; // end struct -} // namespace +} // namespace -TEST_F( TEST_CATEGORY, viewctorprop_embedded_dim ) { - TestViewCtorProp_EmbeddedDim< TEST_EXECSPACE >::test_vcpt( 2, 3 ); +TEST(TEST_CATEGORY, viewctorprop_embedded_dim) { + TestViewCtorProp_EmbeddedDim::test_vcpt(2, 3); } -} // namespace Test +} // namespace Test diff --git a/lib/kokkos/containers/unit_tests/UnitTestMain.cpp b/lib/kokkos/containers/unit_tests/UnitTestMain.cpp index 508b43efd8..e245aad35f 100644 --- a/lib/kokkos/containers/unit_tests/UnitTestMain.cpp +++ b/lib/kokkos/containers/unit_tests/UnitTestMain.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,14 +43,12 @@ */ #include -#include #include int main(int argc, char *argv[]) { - Kokkos::initialize(argc,argv); - ::testing::InitGoogleTest(&argc,argv); + Kokkos::initialize(argc, argv); + ::testing::InitGoogleTest(&argc, argv); int result = RUN_ALL_TESTS(); Kokkos::finalize(); return result; } - diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_BitSet.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_BitSet.cpp index 5f7bc684e6..5306ab3883 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_BitSet.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_BitSet.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_Category.hpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_Category.hpp index 3e0d142480..50935d7a34 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_Category.hpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_Category.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,21 +45,6 @@ #ifndef KOKKOS_TEST_CUDA_HPP #define KOKKOS_TEST_CUDA_HPP -#include - -namespace Test { - -class cuda : public ::testing::Test { -protected: - static void SetUpTestCase() { - } - - static void TearDownTestCase() { - } -}; - -} // namespace Test - #define TEST_CATEGORY cuda #define TEST_EXECSPACE Kokkos::Cuda diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_DualView.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_DualView.cpp index 1930293c3a..5641966db4 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_DualView.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_DualView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_generic.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_generic.cpp index 3d381b3fb6..609c8b41a5 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_generic.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_generic.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_rank12345.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_rank12345.cpp index 08d5b3957a..66d2d17e8b 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_rank12345.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_rank12345.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_rank67.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_rank67.cpp index a655491e81..19e248dd93 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_rank67.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_rank67.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynamicView.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynamicView.cpp index 1986fd7e92..9eccb05a25 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynamicView.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynamicView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_ErrorReporter.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_ErrorReporter.cpp index 22d8d15e03..806a3c6ecc 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_ErrorReporter.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_ErrorReporter.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_OffsetView.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_OffsetView.cpp index 546f6d603a..b2e851d099 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_OffsetView.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_OffsetView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_ScatterView.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_ScatterView.cpp index 9bd1bbab2c..10b63d037d 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_ScatterView.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_ScatterView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_StaticCrsGraph.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_StaticCrsGraph.cpp index b15abcf525..9c93da9c50 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_StaticCrsGraph.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_StaticCrsGraph.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_UnorderedMap.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_UnorderedMap.cpp index 881b20b575..b204e68977 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_UnorderedMap.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_UnorderedMap.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_Vector.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_Vector.cpp index cf0f2012dc..408d0c76fc 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_Vector.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_Vector.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_ViewCtorPropEmbeddedDim.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_ViewCtorPropEmbeddedDim.cpp index 7130195839..c865deb0b2 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_ViewCtorPropEmbeddedDim.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_ViewCtorPropEmbeddedDim.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_BitSet.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_BitSet.cpp index cec24e00c7..179cfcc7b4 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_BitSet.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_BitSet.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_Category.hpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_Category.hpp index 358b42d1aa..64fc7c0757 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_Category.hpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_Category.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,21 +45,6 @@ #ifndef KOKKOS_TEST_HPX_HPP #define KOKKOS_TEST_HPX_HPP -#include - -namespace Test { - -class hpx : public ::testing::Test { -protected: - static void SetUpTestCase() { - } - - static void TearDownTestCase() { - } -}; - -} // namespace Test - #define TEST_CATEGORY hpx #define TEST_EXECSPACE Kokkos::Experimental::HPX diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_DualView.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_DualView.cpp index 80af9dc33a..368cdde95c 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_DualView.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_DualView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_generic.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_generic.cpp index 95d49c8acf..778bd891d6 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_generic.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_generic.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_rank12345.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_rank12345.cpp index 72e0bc6616..0bb77a266d 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_rank12345.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_rank12345.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_rank67.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_rank67.cpp index 5a104f0de2..6594cb3213 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_rank67.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_rank67.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynamicView.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynamicView.cpp index 718b322684..c1efc778a6 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynamicView.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynamicView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_ErrorReporter.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_ErrorReporter.cpp index ea819ae343..3f68c6d07f 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_ErrorReporter.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_ErrorReporter.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_OffsetView.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_OffsetView.cpp index 4d3684923f..1719300228 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_OffsetView.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_OffsetView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_ScatterView.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_ScatterView.cpp index 6a871cc121..8f9eb05918 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_ScatterView.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_ScatterView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_StaticCrsGraph.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_StaticCrsGraph.cpp index fbb70a762b..4f513efb0f 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_StaticCrsGraph.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_StaticCrsGraph.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_UnorderedMap.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_UnorderedMap.cpp index 7e7aad309f..517135290a 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_UnorderedMap.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_UnorderedMap.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_Vector.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_Vector.cpp index 5fb3664197..d42cef4b28 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_Vector.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_Vector.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_ViewCtorPropEmbeddedDim.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_ViewCtorPropEmbeddedDim.cpp index fb9c263c83..de2e96be73 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_ViewCtorPropEmbeddedDim.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_ViewCtorPropEmbeddedDim.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_BitSet.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_BitSet.cpp index 2f3a52787d..db11017159 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_BitSet.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_BitSet.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_Category.hpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_Category.hpp index 150173e4bf..a0169d1702 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_Category.hpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_Category.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,21 +45,6 @@ #ifndef KOKKOS_TEST_OPENMP_HPP #define KOKKOS_TEST_OPENMP_HPP -#include - -namespace Test { - -class openmp : public ::testing::Test { -protected: - static void SetUpTestCase() { - } - - static void TearDownTestCase() { - } -}; - -} // namespace Test - #define TEST_CATEGORY openmp #define TEST_EXECSPACE Kokkos::OpenMP diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DualView.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DualView.cpp index fd6b9ae707..ed4eb23a8b 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DualView.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DualView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_generic.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_generic.cpp index 066d8f9194..637be64dfa 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_generic.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_generic.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_rank12345.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_rank12345.cpp index f44e320eba..01b57a1690 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_rank12345.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_rank12345.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_rank67.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_rank67.cpp index 154243aec9..7d742eaeed 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_rank67.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_rank67.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynamicView.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynamicView.cpp index 7d9ead910f..75b616f168 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynamicView.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynamicView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ErrorReporter.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ErrorReporter.cpp index d05bf163bf..1f00f18532 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ErrorReporter.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ErrorReporter.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_OffsetView.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_OffsetView.cpp index 169dae3212..98531ff212 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_OffsetView.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_OffsetView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ScatterView.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ScatterView.cpp index 3adfcd8409..c49577f75d 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ScatterView.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ScatterView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_StaticCrsGraph.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_StaticCrsGraph.cpp index 486a51a0b9..d8ab7b6b21 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_StaticCrsGraph.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_StaticCrsGraph.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_UnorderedMap.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_UnorderedMap.cpp index 32dc22ec93..c3db0c0d88 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_UnorderedMap.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_UnorderedMap.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_Vector.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_Vector.cpp index 006caba816..7ac49f24fb 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_Vector.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_Vector.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ViewCtorPropEmbeddedDim.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ViewCtorPropEmbeddedDim.cpp index dbbf14cb5b..b9ae5d80ed 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ViewCtorPropEmbeddedDim.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ViewCtorPropEmbeddedDim.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_BitSet.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_BitSet.cpp index 2c8657e464..c72077eb4c 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_BitSet.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_BitSet.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_Category.hpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_Category.hpp index d520bbc5a7..d37cd05db6 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_Category.hpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_Category.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,21 +45,6 @@ #ifndef KOKKOS_TEST_ROCM_HPP #define KOKKOS_TEST_ROCM_HPP -#include - -namespace Test { - -class rocm : public ::testing::Test { -protected: - static void SetUpTestCase() { - } - - static void TearDownTestCase() { - } -}; - -} // namespace Test - #define TEST_CATEGORY rocm #define TEST_EXECSPACE Kokkos::Experimental::ROCm diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_DualView.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_DualView.cpp index f60c6ade44..e9820395ba 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_DualView.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_DualView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_generic.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_generic.cpp index 80bfe06153..7a3dd65f0e 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_generic.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_generic.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_rank12345.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_rank12345.cpp index b42ce07e8f..3963dd9c9c 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_rank12345.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_rank12345.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_rank67.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_rank67.cpp index 0f47b800c6..b9a4582622 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_rank67.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_rank67.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynamicView.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynamicView.cpp index 5540eb2d20..285ed916c4 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynamicView.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynamicView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_ErrorReporter.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_ErrorReporter.cpp index 2c7a26c7fe..2af2f79a16 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_ErrorReporter.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_ErrorReporter.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_ScatterView.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_ScatterView.cpp index cc4a07ddbd..f7000bc99e 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_ScatterView.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_ScatterView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_StaticCrsGraph.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_StaticCrsGraph.cpp index be83d4ef50..bb1e04c536 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_StaticCrsGraph.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_StaticCrsGraph.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_UnorderedMap.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_UnorderedMap.cpp index f6b2f9ef40..7b8172fabd 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_UnorderedMap.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_UnorderedMap.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_Vector.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_Vector.cpp index e9073b6bb5..1759797487 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_Vector.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_Vector.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_ViewCtorPropEmbeddedDim.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_ViewCtorPropEmbeddedDim.cpp index dd472270e7..e95680445b 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_ViewCtorPropEmbeddedDim.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_ViewCtorPropEmbeddedDim.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_BitSet.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_BitSet.cpp index 03edd30c34..322e88a6af 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_BitSet.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_BitSet.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_Category.hpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_Category.hpp index 858b669286..2aa09a315a 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_Category.hpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_Category.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,21 +45,6 @@ #ifndef KOKKOS_TEST_SERIAL_HPP #define KOKKOS_TEST_SERIAL_HPP -#include - -namespace Test { - -class serial : public ::testing::Test { -protected: - static void SetUpTestCase() { - } - - static void TearDownTestCase() { - } -}; - -} // namespace Test - #define TEST_CATEGORY serial #define TEST_EXECSPACE Kokkos::Serial diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_DualView.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_DualView.cpp index 0dac8eba87..c1646ed13b 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_DualView.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_DualView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_generic.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_generic.cpp index 1a5874e7fa..e8f577c6ac 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_generic.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_generic.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_rank12345.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_rank12345.cpp index df802bfe68..7db8983c1b 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_rank12345.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_rank12345.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_rank67.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_rank67.cpp index 84e5b452c4..a3a745efb5 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_rank67.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_rank67.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_DynamicView.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_DynamicView.cpp index 34f4002db2..6624e3aa07 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_DynamicView.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_DynamicView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_ErrorReporter.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_ErrorReporter.cpp index 326853f33a..280302275f 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_ErrorReporter.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_ErrorReporter.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_OffsetView.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_OffsetView.cpp index fadd748efb..5f8caf7c3f 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_OffsetView.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_OffsetView.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,6 +42,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_ScatterView.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_ScatterView.cpp index ee04d35584..3f102e5cbc 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_ScatterView.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_ScatterView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_StaticCrsGraph.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_StaticCrsGraph.cpp index 2d10ee70d2..64f09e76e5 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_StaticCrsGraph.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_StaticCrsGraph.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_UnorderedMap.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_UnorderedMap.cpp index e78667e8aa..a72be8e2fc 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_UnorderedMap.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_UnorderedMap.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_Vector.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_Vector.cpp index bf98055622..3826dab1d7 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_Vector.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_Vector.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_ViewCtorPropEmbeddedDim.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_ViewCtorPropEmbeddedDim.cpp index 143b1f1c2d..1251808bed 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_ViewCtorPropEmbeddedDim.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_ViewCtorPropEmbeddedDim.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_BitSet.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_BitSet.cpp index 0dfe69fee2..ec93bb121c 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_BitSet.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_BitSet.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_Category.hpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_Category.hpp index c4d0ed6da2..74a2b0da36 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_Category.hpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_Category.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,21 +45,6 @@ #ifndef KOKKOS_TEST_THREADS_HPP #define KOKKOS_TEST_THREADS_HPP -#include - -namespace Test { - -class threads : public ::testing::Test { -protected: - static void SetUpTestCase() { - } - - static void TearDownTestCase() { - } -}; - -} // namespace Test - #define TEST_CATEGORY threads #define TEST_EXECSPACE Kokkos::Threads diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_DualView.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_DualView.cpp index 0ddafcd6fd..f6967bf0d4 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_DualView.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_DualView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_generic.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_generic.cpp index 0030673785..b015683bb9 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_generic.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_generic.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_rank12345.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_rank12345.cpp index db39db38b3..dea56c408b 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_rank12345.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_rank12345.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_rank67.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_rank67.cpp index 1d1f94d6cf..17a289b506 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_rank67.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_rank67.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_DynamicView.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_DynamicView.cpp index 61616a5132..499321dbbe 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_DynamicView.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_DynamicView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_ErrorReporter.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_ErrorReporter.cpp index a64c3f4082..513fdc4af6 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_ErrorReporter.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_ErrorReporter.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_OffsetView.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_OffsetView.cpp index d1eaa265e3..717967b2ef 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_OffsetView.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_OffsetView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_ScatterView.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_ScatterView.cpp index 6c7138058d..fbb37606ea 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_ScatterView.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_ScatterView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_StaticCrsGraph.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_StaticCrsGraph.cpp index f6a1204dd3..29117c4ef6 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_StaticCrsGraph.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_StaticCrsGraph.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_UnorderedMap.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_UnorderedMap.cpp index 2f3aeedae0..9a06288de4 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_UnorderedMap.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_UnorderedMap.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_Vector.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_Vector.cpp index a497d43772..33e8b26c8e 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_Vector.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_Vector.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_ViewCtorPropEmbeddedDim.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_ViewCtorPropEmbeddedDim.cpp index 89f85dca56..567b224195 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_ViewCtorPropEmbeddedDim.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_ViewCtorPropEmbeddedDim.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/core/CMakeLists.txt b/lib/kokkos/core/CMakeLists.txt index 93db0d2ecf..8df72dfc90 100644 --- a/lib/kokkos/core/CMakeLists.txt +++ b/lib/kokkos/core/CMakeLists.txt @@ -1,13 +1,12 @@ - - -TRIBITS_SUBPACKAGE(Core) - -IF(KOKKOS_HAS_TRILINOS) - ADD_SUBDIRECTORY(src) -ENDIF() - -TRIBITS_ADD_TEST_DIRECTORIES(unit_test) -TRIBITS_ADD_TEST_DIRECTORIES(perf_test) - -TRIBITS_SUBPACKAGE_POSTPROCESS() - + + +KOKKOS_SUBPACKAGE(Core) + +ADD_SUBDIRECTORY(src) + +KOKKOS_ADD_TEST_DIRECTORIES(unit_test) +KOKKOS_ADD_TEST_DIRECTORIES(perf_test) + +KOKKOS_SUBPACKAGE_POSTPROCESS() + + diff --git a/lib/kokkos/core/cmake/KokkosCore_config.h.in b/lib/kokkos/core/cmake/KokkosCore_config.h.in index b2c80207d4..f430c2b5f6 100644 --- a/lib/kokkos/core/cmake/KokkosCore_config.h.in +++ b/lib/kokkos/core/cmake/KokkosCore_config.h.in @@ -13,8 +13,7 @@ #cmakedefine KOKKOS_ENABLE_CUDA #cmakedefine KOKKOS_ENABLE_OPENMP -#cmakedefine KOKKOS_ENABLE_PTHREAD -#cmakedefine KOKKOS_ENABLE_QTHREADS +#cmakedefine KOKKOS_ENABLE_THREADS #cmakedefine KOKKOS_ENABLE_SERIAL #cmakedefine KOKKOS_ENABLE_Winthread diff --git a/lib/kokkos/core/perf_test/CMakeLists.txt b/lib/kokkos/core/perf_test/CMakeLists.txt index d92462a357..79567835ee 100644 --- a/lib/kokkos/core/perf_test/CMakeLists.txt +++ b/lib/kokkos/core/perf_test/CMakeLists.txt @@ -1,59 +1,71 @@ -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) -INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${CMAKE_CURRENT_SOURCE_DIR}) +#INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +#INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${CMAKE_CURRENT_SOURCE_DIR}) -IF(NOT KOKKOS_HAS_TRILINOS) - IF(KOKKOS_SEPARATE_LIBS) - set(TEST_LINK_TARGETS kokkoscore) - ELSE() - set(TEST_LINK_TARGETS kokkos) - ENDIF() -ENDIF() # warning: PerfTest_CustomReduction.cpp uses # ../../algorithms/src/Kokkos_Random.hpp # we'll just allow it to be included, but note # that in TriBITS KokkosAlgorithms can be disabled... -INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../../algorithms/src") +#INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../../algorithms/src") SET(SOURCES PerfTestMain.cpp PerfTestGramSchmidt.cpp PerfTestHexGrad.cpp PerfTest_CustomReduction.cpp + PerfTest_ExecSpacePartitioning.cpp + PerfTest_ViewCopy_a123.cpp + PerfTest_ViewCopy_b123.cpp + PerfTest_ViewCopy_c123.cpp + PerfTest_ViewCopy_d123.cpp + PerfTest_ViewCopy_a45.cpp + PerfTest_ViewCopy_b45.cpp + PerfTest_ViewCopy_c45.cpp + PerfTest_ViewCopy_d45.cpp + PerfTest_ViewCopy_a6.cpp + PerfTest_ViewCopy_b6.cpp + PerfTest_ViewCopy_c6.cpp + PerfTest_ViewCopy_d6.cpp + PerfTest_ViewCopy_a7.cpp + PerfTest_ViewCopy_b7.cpp + PerfTest_ViewCopy_c7.cpp + PerfTest_ViewCopy_d7.cpp + PerfTest_ViewCopy_a8.cpp + PerfTest_ViewCopy_b8.cpp + PerfTest_ViewCopy_c8.cpp + PerfTest_ViewCopy_d8.cpp + PerfTest_ViewAllocate.cpp + PerfTest_ViewFill_123.cpp + PerfTest_ViewFill_45.cpp + PerfTest_ViewFill_6.cpp + PerfTest_ViewFill_7.cpp + PerfTest_ViewFill_8.cpp + PerfTest_ViewResize_123.cpp + PerfTest_ViewResize_45.cpp + PerfTest_ViewResize_6.cpp + PerfTest_ViewResize_7.cpp + PerfTest_ViewResize_8.cpp ) # Per #374, we always want to build this test, but we only want to run # it as a PERFORMANCE test. That's why we separate building the test # from running the test. -TRIBITS_ADD_EXECUTABLE( +#leave these as basic includes for now +#I don't need anything transitive +KOKKOS_INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../../algorithms/src") +KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +KOKKOS_INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${CMAKE_CURRENT_SOURCE_DIR}) + +KOKKOS_ADD_EXECUTABLE_AND_TEST( PerfTestExec SOURCES ${SOURCES} - COMM serial mpi - TESTONLYLIBS kokkos_gtest ${TEST_LINK_TARGETS} - ) - -TRIBITS_ADD_TEST( - PerfTest - NAME PerfTestExec - COMM serial mpi - NUM_MPI_PROCS 1 CATEGORIES PERFORMANCE - FAIL_REGULAR_EXPRESSION " FAILED " - ) +) -TRIBITS_ADD_EXECUTABLE( - PerformanceTest_TaskDAG +KOKKOS_ADD_EXECUTABLE_AND_TEST( + PerformanceTest_TaskDag SOURCES test_taskdag.cpp - COMM serial mpi - TESTONLYLIBS kokkos_gtest ${TEST_LINK_TARGETS} - ) - -TRIBITS_ADD_TEST( - PerformanceTest_TaskDAG - NAME PerformanceTest_TaskDAG - COMM serial mpi - NUM_MPI_PROCS 1 CATEGORIES PERFORMANCE - ) +) diff --git a/lib/kokkos/core/perf_test/PerfTestBlasKernels.hpp b/lib/kokkos/core/perf_test/PerfTestBlasKernels.hpp index ff9bf5a91b..a5a376565d 100644 --- a/lib/kokkos/core/perf_test/PerfTestBlasKernels.hpp +++ b/lib/kokkos/core/perf_test/PerfTestBlasKernels.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -48,217 +49,186 @@ namespace Kokkos { -template< class ConstVectorType , - class Device = typename ConstVectorType::execution_space > -struct Dot ; +template +struct Dot; -template< class ConstVectorType , - class Device = typename ConstVectorType::execution_space > -struct DotSingle ; +template +struct DotSingle; -template< class ConstScalarType , - class VectorType , - class Device = typename VectorType::execution_space > -struct Scale ; +template +struct Scale; -template< class ConstScalarType , - class ConstVectorType , - class VectorType , - class Device = typename VectorType::execution_space > -struct AXPBY ; +template +struct AXPBY; /** \brief Y = alpha * X + beta * Y */ -template< class ConstScalarType , - class ConstVectorType , - class VectorType > -void axpby( const ConstScalarType & alpha , - const ConstVectorType & X , - const ConstScalarType & beta , - const VectorType & Y ) -{ - typedef AXPBY< ConstScalarType , ConstVectorType , VectorType > functor ; - - parallel_for( Y.extent(0) , functor( alpha , X , beta , Y ) ); +template +void axpby(const ConstScalarType& alpha, const ConstVectorType& X, + const ConstScalarType& beta, const VectorType& Y) { + typedef AXPBY functor; + + parallel_for(Y.extent(0), functor(alpha, X, beta, Y)); } /** \brief Y *= alpha */ -template< class ConstScalarType , - class VectorType > -void scale( const ConstScalarType & alpha , const VectorType & Y ) -{ - typedef Scale< ConstScalarType , VectorType > functor ; +template +void scale(const ConstScalarType& alpha, const VectorType& Y) { + typedef Scale functor; - parallel_for( Y.extent(0) , functor( alpha , Y ) ); + parallel_for(Y.extent(0), functor(alpha, Y)); } -template< class ConstVectorType , - class Finalize > -void dot( const ConstVectorType & X , - const ConstVectorType & Y , - const Finalize & finalize ) -{ - typedef Dot< ConstVectorType > functor ; +template +void dot(const ConstVectorType& X, const ConstVectorType& Y, + const Finalize& finalize) { + typedef Dot functor; - parallel_reduce( X.extent(0) , functor( X , Y ) , finalize ); + parallel_reduce(X.extent(0), functor(X, Y), finalize); } -template< class ConstVectorType , - class Finalize > -void dot( const ConstVectorType & X , - const Finalize & finalize ) -{ - typedef DotSingle< ConstVectorType > functor ; +template +void dot(const ConstVectorType& X, const Finalize& finalize) { + typedef DotSingle functor; - parallel_reduce( X.extent(0) , functor( X ) , finalize ); + parallel_reduce(X.extent(0), functor(X), finalize); } } /* namespace Kokkos */ - //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- namespace Kokkos { -template< class Type , class Device > -struct Dot -{ - typedef typename Device::execution_space execution_space ; - - static_assert( static_cast(Type::Rank) == static_cast(1), - "Dot static_assert Fail: Rank != 1"); +template +struct Dot { + typedef typename Device::execution_space execution_space; + static_assert(static_cast(Type::Rank) == static_cast(1), + "Dot static_assert Fail: Rank != 1"); - typedef double value_type ; + typedef double value_type; #if 1 - typename Type::const_type X ; - typename Type::const_type Y ; + typename Type::const_type X; + typename Type::const_type Y; #else - Type X ; - Type Y ; + Type X; + Type Y; #endif - Dot( const Type & arg_x , const Type & arg_y ) - : X(arg_x) , Y(arg_y) { } + Dot(const Type& arg_x, const Type& arg_y) : X(arg_x), Y(arg_y) {} KOKKOS_INLINE_FUNCTION - void operator()( int i , value_type & update ) const - { update += X[i] * Y[i]; } + void operator()(int i, value_type& update) const { update += X[i] * Y[i]; } KOKKOS_INLINE_FUNCTION - static void join( volatile value_type & update , - const volatile value_type & source ) - { update += source; } + static void join(volatile value_type& update, + const volatile value_type& source) { + update += source; + } KOKKOS_INLINE_FUNCTION - static void init( value_type & update ) - { update = 0 ; } + static void init(value_type& update) { update = 0; } }; -template< class Type , class Device > -struct DotSingle -{ - typedef typename Device::execution_space execution_space ; +template +struct DotSingle { + typedef typename Device::execution_space execution_space; - static_assert( static_cast(Type::Rank) == static_cast(1), - "DotSingle static_assert Fail: Rank != 1"); + static_assert(static_cast(Type::Rank) == static_cast(1), + "DotSingle static_assert Fail: Rank != 1"); - typedef double value_type ; + typedef double value_type; #if 1 - typename Type::const_type X ; + typename Type::const_type X; #else - Type X ; + Type X; #endif - DotSingle( const Type & arg_x ) : X(arg_x) {} + DotSingle(const Type& arg_x) : X(arg_x) {} KOKKOS_INLINE_FUNCTION - void operator()( int i , value_type & update ) const - { - const typename Type::value_type & x = X[i]; update += x * x ; - } + void operator()(int i, value_type& update) const { + const typename Type::value_type& x = X[i]; + update += x * x; + } KOKKOS_INLINE_FUNCTION - static void join( volatile value_type & update , - const volatile value_type & source ) - { update += source; } + static void join(volatile value_type& update, + const volatile value_type& source) { + update += source; + } KOKKOS_INLINE_FUNCTION - static void init( value_type & update ) - { update = 0 ; } + static void init(value_type& update) { update = 0; } }; +template +struct Scale { + typedef typename Device::execution_space execution_space; -template< class ScalarType , class VectorType , class Device> -struct Scale -{ - typedef typename Device::execution_space execution_space ; + static_assert(static_cast(ScalarType::Rank) == + static_cast(0), + "Scale static_assert Fail: ScalarType::Rank != 0"); - static_assert( static_cast(ScalarType::Rank) == static_cast(0), - "Scale static_assert Fail: ScalarType::Rank != 0"); - - static_assert( static_cast(VectorType::Rank) == static_cast(1), - "Scale static_assert Fail: VectorType::Rank != 1"); + static_assert(static_cast(VectorType::Rank) == + static_cast(1), + "Scale static_assert Fail: VectorType::Rank != 1"); #if 1 - typename ScalarType::const_type alpha ; + typename ScalarType::const_type alpha; #else - ScalarType alpha ; + ScalarType alpha; #endif - VectorType Y ; + VectorType Y; - Scale( const ScalarType & arg_alpha , const VectorType & arg_Y ) - : alpha( arg_alpha ), Y( arg_Y ) {} + Scale(const ScalarType& arg_alpha, const VectorType& arg_Y) + : alpha(arg_alpha), Y(arg_Y) {} KOKKOS_INLINE_FUNCTION - void operator()( int i ) const - { - Y[i] *= alpha() ; - } + void operator()(int i) const { Y[i] *= alpha(); } }; - -template< class ScalarType , - class ConstVectorType , - class VectorType, +template -struct AXPBY -{ - typedef typename Device::execution_space execution_space ; +struct AXPBY { + typedef typename Device::execution_space execution_space; - static_assert( static_cast(ScalarType::Rank) == static_cast(0), - "AXPBY static_assert Fail: ScalarType::Rank != 0"); + static_assert(static_cast(ScalarType::Rank) == + static_cast(0), + "AXPBY static_assert Fail: ScalarType::Rank != 0"); - static_assert( static_cast(ConstVectorType::Rank) == static_cast(1), - "AXPBY static_assert Fail: ConstVectorType::Rank != 1"); + static_assert(static_cast(ConstVectorType::Rank) == + static_cast(1), + "AXPBY static_assert Fail: ConstVectorType::Rank != 1"); - static_assert( static_cast(VectorType::Rank) == static_cast(1), - "AXPBY static_assert Fail: VectorType::Rank != 1"); + static_assert(static_cast(VectorType::Rank) == + static_cast(1), + "AXPBY static_assert Fail: VectorType::Rank != 1"); #if 1 - typename ScalarType::const_type alpha , beta ; - typename ConstVectorType::const_type X ; + typename ScalarType::const_type alpha, beta; + typename ConstVectorType::const_type X; #else - ScalarType alpha , beta ; - ConstVectorType X ; + ScalarType alpha, beta; + ConstVectorType X; #endif - VectorType Y ; + VectorType Y; - AXPBY( const ScalarType & arg_alpha , - const ConstVectorType & arg_X , - const ScalarType & arg_beta , - const VectorType & arg_Y ) - : alpha( arg_alpha ), beta( arg_beta ), X( arg_X ), Y( arg_Y ) {} + AXPBY(const ScalarType& arg_alpha, const ConstVectorType& arg_X, + const ScalarType& arg_beta, const VectorType& arg_Y) + : alpha(arg_alpha), beta(arg_beta), X(arg_X), Y(arg_Y) {} KOKKOS_INLINE_FUNCTION - void operator()( int i ) const - { - Y[i] = alpha() * X[i] + beta() * Y[i] ; - } + void operator()(int i) const { Y[i] = alpha() * X[i] + beta() * Y[i]; } }; } /* namespace Kokkos */ diff --git a/lib/kokkos/core/perf_test/PerfTestDriver.hpp b/lib/kokkos/core/perf_test/PerfTestDriver.hpp index 5367f2542e..95d5128abf 100644 --- a/lib/kokkos/core/perf_test/PerfTestDriver.hpp +++ b/lib/kokkos/core/perf_test/PerfTestDriver.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -60,244 +61,262 @@ namespace Test { enum { NUMBER_OF_TRIALS = 5 }; -template< class DeviceType , class LayoutType > -void run_test_mdrange( int exp_beg , int exp_end, const char deviceTypeName[], int range_offset = 0, int tile_offset = 0 ) +template +void run_test_mdrange(int exp_beg, int exp_end, const char deviceTypeName[], + int range_offset = 0, int tile_offset = 0) // exp_beg = 6 => 2^6 = 64 is starting range length { #define MDRANGE_PERFORMANCE_OUTPUT_VERBOSE 0 - std::string label_mdrange ; - label_mdrange.append( "\"MDRange< double , " ); - label_mdrange.append( deviceTypeName ); - label_mdrange.append( " >\"" ); - - std::string label_range_col2 ; - label_range_col2.append( "\"RangeColTwo< double , " ); - label_range_col2.append( deviceTypeName ); - label_range_col2.append( " >\"" ); - - std::string label_range_col_all ; - label_range_col_all.append( "\"RangeColAll< double , " ); - label_range_col_all.append( deviceTypeName ); - label_range_col_all.append( " >\"" ); - - if ( std::is_same::value) { - std::cout << "--------------------------------------------------------------\n" - << "Performance tests for MDRange Layout Right" - << "\n--------------------------------------------------------------" << std::endl; + std::string label_mdrange; + label_mdrange.append("\"MDRange< double , "); + label_mdrange.append(deviceTypeName); + label_mdrange.append(" >\""); + + std::string label_range_col2; + label_range_col2.append("\"RangeColTwo< double , "); + label_range_col2.append(deviceTypeName); + label_range_col2.append(" >\""); + + std::string label_range_col_all; + label_range_col_all.append("\"RangeColAll< double , "); + label_range_col_all.append(deviceTypeName); + label_range_col_all.append(" >\""); + + if (std::is_same::value) { + std::cout + << "--------------------------------------------------------------\n" + << "Performance tests for MDRange Layout Right" + << "\n--------------------------------------------------------------" + << std::endl; } else { - std::cout << "--------------------------------------------------------------\n" - << "Performance tests for MDRange Layout Left" - << "\n--------------------------------------------------------------" << std::endl; + std::cout + << "--------------------------------------------------------------\n" + << "Performance tests for MDRange Layout Left" + << "\n--------------------------------------------------------------" + << std::endl; } + for (int i = exp_beg; i < exp_end; ++i) { + const int range_length = (1 << i) + range_offset; - for (int i = exp_beg ; i < exp_end ; ++i) { - const int range_length = (1<= min_bnd ) { - int tmid = min_bnd; - while ( tmid < tfast ) { - t0 = min_bnd; - t1 = tmid; - t2 = tfast; - int t2_rev = min_bnd; - int t1_rev = tmid; - int t0_rev = tfast; + while (tfast >= min_bnd) { + int tmid = min_bnd; + while (tmid < tfast) { + t0 = min_bnd; + t1 = tmid; + t2 = tfast; + int t2_rev = min_bnd; + int t1_rev = tmid; + int t0_rev = tfast; #if defined(KOKKOS_ENABLE_CUDA) - //Note: Product of tile sizes must be < 1024 for Cuda - if ( t0*t1*t2 >= 1024 ) { - printf(" Exceeded Cuda tile limits; onto next range set\n\n"); - break; - } + // Note: Product of tile sizes must be < 1024 for Cuda + if (t0 * t1 * t2 >= 1024) { + printf(" Exceeded Cuda tile limits; onto next range set\n\n"); + break; + } #endif - // Run 1 with tiles LayoutRight style - double seconds_1 = 0; - { seconds_1 = MultiDimRangePerf3D< DeviceType , double , LayoutType >::test_multi_index(range_length,range_length,range_length, t0, t1, t2) ; } + // Run 1 with tiles LayoutRight style + double seconds_1 = 0; + { + seconds_1 = + MultiDimRangePerf3D::test_multi_index(range_length, + range_length, + range_length, + t0, t1, t2); + } #if MDRANGE_PERFORMANCE_OUTPUT_VERBOSE - std::cout << label_mdrange - << " , " << t0 << " , " << t1 << " , " << t2 - << " , " << seconds_1 - << std::endl ; + std::cout << label_mdrange << " , " << t0 << " , " << t1 << " , " + << t2 << " , " << seconds_1 << std::endl; #endif - if ( counter == 1 ) { - seconds_min = seconds_1; - t0_min = t0; - t1_min = t1; - t2_min = t2; - } - else { - if ( seconds_1 < seconds_min ) - { - seconds_min = seconds_1; - t0_min = t0; - t1_min = t1; - t2_min = t2; + if (counter == 1) { + seconds_min = seconds_1; + t0_min = t0; + t1_min = t1; + t2_min = t2; + } else { + if (seconds_1 < seconds_min) { + seconds_min = seconds_1; + t0_min = t0; + t1_min = t1; + t2_min = t2; + } } - } - // Run 2 with tiles LayoutLeft style - reverse order of tile dims - double seconds_1rev = 0; - { seconds_1rev = MultiDimRangePerf3D< DeviceType , double , LayoutType >::test_multi_index(range_length,range_length,range_length, t0_rev, t1_rev, t2_rev) ; } + // Run 2 with tiles LayoutLeft style - reverse order of tile dims + double seconds_1rev = 0; + { + seconds_1rev = + MultiDimRangePerf3D::test_multi_index(range_length, + range_length, + range_length, + t0_rev, + t1_rev, + t2_rev); + } #if MDRANGE_PERFORMANCE_OUTPUT_VERBOSE - std::cout << label_mdrange - << " , " << t0_rev << " , " << t1_rev << " , " << t2_rev - << " , " << seconds_1rev - << std::endl ; + std::cout << label_mdrange << " , " << t0_rev << " , " << t1_rev + << " , " << t2_rev << " , " << seconds_1rev << std::endl; #endif - if ( seconds_1rev < seconds_min ) - { - seconds_min = seconds_1rev; - t0_min = t0_rev; - t1_min = t1_rev; - t2_min = t2_rev; - } + if (seconds_1rev < seconds_min) { + seconds_min = seconds_1rev; + t0_min = t0_rev; + t1_min = t1_rev; + t2_min = t2_rev; + } - ++counter; - tmid <<= 1; - } //end inner while - tfast >>=1; - } //end outer while - - std::cout << "\n" - << "--------------------------------------------------------------\n" - << label_mdrange - << "\n Min values " - << "\n Range length per dim (3D): " << range_length - << "\n TileDims: " << t0_min << " , " << t1_min << " , " << t2_min - << "\n Min time: " << seconds_min - << "\n---------------------------------------------------------------" - << std::endl ; - } //end scope + ++counter; + tmid <<= 1; + } // end inner while + tfast >>= 1; + } // end outer while + + std::cout + << "\n" + << "--------------------------------------------------------------\n" + << label_mdrange << "\n Min values " + << "\n Range length per dim (3D): " << range_length + << "\n TileDims: " << t0_min << " , " << t1_min << " , " << t2_min + << "\n Min time: " << seconds_min + << "\n---------------------------------------------------------------" + << std::endl; + } // end scope #if !defined(KOKKOS_ENABLE_CUDA) - double seconds_min_c = 0.0; - int t0c_min = 0, t1c_min = 0, t2c_min = 0; - int counter = 1; - { - int min_bnd = 8; - // Test 1_c: MDRange with 0 for 'inner' tile dim; this case will utilize the full span in that direction, should be similar to Collapse<2> - if ( std::is_same::value ) { - for ( unsigned int T0 = min_bnd; T0 < static_cast(range_length); T0<<=1 ) { - for ( unsigned int T1 = min_bnd; T1 < static_cast(range_length); T1<<=1 ) { - double seconds_c = 0; - { seconds_c = MultiDimRangePerf3D< DeviceType , double , LayoutType >::test_multi_index(range_length,range_length,range_length, T0, T1, 0) ; } + double seconds_min_c = 0.0; + int t0c_min = 0, t1c_min = 0, t2c_min = 0; + int counter = 1; + { + int min_bnd = 8; + // Test 1_c: MDRange with 0 for 'inner' tile dim; this case will utilize + // the full span in that direction, should be similar to Collapse<2> + if (std::is_same::value) { + for (unsigned int T0 = min_bnd; + T0 < static_cast(range_length); T0 <<= 1) { + for (unsigned int T1 = min_bnd; + T1 < static_cast(range_length); T1 <<= 1) { + double seconds_c = 0; + { + seconds_c = MultiDimRangePerf3D:: + test_multi_index(range_length, range_length, range_length, T0, + T1, 0); + } #if MDRANGE_PERFORMANCE_OUTPUT_VERBOSE - std::cout << " MDRange LR with '0' tile - collapse-like \n" - << label_mdrange - << " , " << T0 << " , " << T1 << " , " << range_length - << " , " << seconds_c - << std::endl ; + std::cout << " MDRange LR with '0' tile - collapse-like \n" + << label_mdrange << " , " << T0 << " , " << T1 << " , " + << range_length << " , " << seconds_c << std::endl; #endif - t2c_min = range_length; - if ( counter == 1 ) { - seconds_min_c = seconds_c; - t0c_min = T0; - t1c_min = T1; - } - else { - if ( seconds_c < seconds_min_c ) - { - seconds_min_c = seconds_c; - t0c_min = T0; - t1c_min = T1; + t2c_min = range_length; + if (counter == 1) { + seconds_min_c = seconds_c; + t0c_min = T0; + t1c_min = T1; + } else { + if (seconds_c < seconds_min_c) { + seconds_min_c = seconds_c; + t0c_min = T0; + t1c_min = T1; + } } + ++counter; } - ++counter; } - } - } - else { - for ( unsigned int T1 = min_bnd; T1 <= static_cast(range_length); T1<<=1 ) { - for ( unsigned int T2 = min_bnd; T2 <= static_cast(range_length); T2<<=1 ) { - double seconds_c = 0; - { seconds_c = MultiDimRangePerf3D< DeviceType , double , LayoutType >::test_multi_index(range_length,range_length,range_length, 0, T1, T2) ; } + } else { + for (unsigned int T1 = min_bnd; + T1 <= static_cast(range_length); T1 <<= 1) { + for (unsigned int T2 = min_bnd; + T2 <= static_cast(range_length); T2 <<= 1) { + double seconds_c = 0; + { + seconds_c = MultiDimRangePerf3D:: + test_multi_index(range_length, range_length, range_length, 0, + T1, T2); + } #if MDRANGE_PERFORMANCE_OUTPUT_VERBOSE - std::cout << " MDRange LL with '0' tile - collapse-like \n" - << label_mdrange - << " , " < style: " - << "\n Min values " - << "\n Range length per dim (3D): " << range_length - << "\n TileDims: " << t0c_min << " , " << t1c_min << " , " << t2c_min - << "\n Min time: " << seconds_min_c - << "\n---------------------------------------------------------------" - << std::endl ; - } //end scope test 2 + std::cout + // << + // "--------------------------------------------------------------\n" + << label_mdrange << " Collapse<2> style: " + << "\n Min values " + << "\n Range length per dim (3D): " << range_length + << "\n TileDims: " << t0c_min << " , " << t1c_min << " , " << t2c_min + << "\n Min time: " << seconds_min_c + << "\n---------------------------------------------------------------" + << std::endl; + } // end scope test 2 #endif - // Test 2: RangePolicy Collapse2 style double seconds_2 = 0; - { seconds_2 = RangePolicyCollapseTwo< DeviceType , double , LayoutType >::test_index_collapse_two(range_length,range_length,range_length) ; } - std::cout << label_range_col2 - << " , " << range_length - << " , " << seconds_2 - << std::endl ; - + { + seconds_2 = RangePolicyCollapseTwo:: + test_index_collapse_two(range_length, range_length, range_length); + } + std::cout << label_range_col2 << " , " << range_length << " , " << seconds_2 + << std::endl; // Test 3: RangePolicy Collapse all style - not necessary, always slow /* double seconds_3 = 0; - { seconds_3 = RangePolicyCollapseAll< DeviceType , double , LayoutType >::test_collapse_all(range_length,range_length,range_length) ; } - std::cout << label_range_col_all + { seconds_3 = RangePolicyCollapseAll< DeviceType , double , LayoutType + >::test_collapse_all(range_length,range_length,range_length) ; } std::cout + << label_range_col_all << " , " << range_length << " , " << seconds_3 << "\n---------------------------------------------------------------" @@ -306,97 +325,105 @@ void run_test_mdrange( int exp_beg , int exp_end, const char deviceTypeName[], i // Compare fastest times... will never be collapse all so ignore it // seconds_min = tiled MDRange - // seconds_min_c = collapse<2>-like MDRange (tiledim = span for fast dim) - only for non-Cuda, else tile too long - // seconds_2 = collapse<2>-style RangePolicy - // seconds_3 = collapse<3>-style RangePolicy + // seconds_min_c = collapse<2>-like MDRange (tiledim = span for fast dim) - + // only for non-Cuda, else tile too long seconds_2 = collapse<2>-style + // RangePolicy seconds_3 = collapse<3>-style RangePolicy #if !defined(KOKKOS_ENABLE_CUDA) - if ( seconds_min < seconds_min_c ) { - if ( seconds_min < seconds_2 ) { - std::cout << "--------------------------------------------------------------\n" - << " Fastest run: MDRange tiled\n" - << " Time: " << seconds_min - << " Difference: " << seconds_2 - seconds_min - << " Other times: \n" - << " MDrange collapse-like (tiledim = span on fast dim) type: " << seconds_min_c << "\n" - << " Collapse2 Range Policy: " << seconds_2 << "\n" - << "\n--------------------------------------------------------------" - << "\n--------------------------------------------------------------" - //<< "\n\n" - << std::endl; - } - else if ( seconds_min > seconds_2 ) { - std::cout << " Fastest run: Collapse2 RangePolicy\n" - << " Time: " << seconds_2 - << " Difference: " << seconds_min - seconds_2 - << " Other times: \n" - << " MDrange Tiled: " << seconds_min << "\n" - << " MDrange collapse-like (tiledim = span on fast dim) type: " << seconds_min_c << "\n" - << "\n--------------------------------------------------------------" - << "\n--------------------------------------------------------------" - //<< "\n\n" - << std::endl; - } - } - else if ( seconds_min > seconds_min_c ) { - if ( seconds_min_c < seconds_2 ) { - std::cout << "--------------------------------------------------------------\n" - << " Fastest run: MDRange collapse-like (tiledim = span on fast dim) type\n" - << " Time: " << seconds_min_c - << " Difference: " << seconds_2 - seconds_min_c - << " Other times: \n" - << " MDrange Tiled: " << seconds_min << "\n" - << " Collapse2 Range Policy: " << seconds_2 << "\n" - << "\n--------------------------------------------------------------" - << "\n--------------------------------------------------------------" - //<< "\n\n" - << std::endl; + if (seconds_min < seconds_min_c) { + if (seconds_min < seconds_2) { + std::cout + << "--------------------------------------------------------------" + "\n" + << " Fastest run: MDRange tiled\n" + << " Time: " << seconds_min + << " Difference: " << seconds_2 - seconds_min << " Other times: \n" + << " MDrange collapse-like (tiledim = span on fast dim) type: " + << seconds_min_c << "\n" + << " Collapse2 Range Policy: " << seconds_2 << "\n" + << "\n-------------------------------------------------------------" + "-" + << "\n-------------------------------------------------------------" + "-" + //<< "\n\n" + << std::endl; + } else if (seconds_min > seconds_2) { + std::cout + << " Fastest run: Collapse2 RangePolicy\n" + << " Time: " << seconds_2 + << " Difference: " << seconds_min - seconds_2 << " Other times: \n" + << " MDrange Tiled: " << seconds_min << "\n" + << " MDrange collapse-like (tiledim = span on fast dim) type: " + << seconds_min_c << "\n" + << "\n-------------------------------------------------------------" + "-" + << "\n-------------------------------------------------------------" + "-" + //<< "\n\n" + << std::endl; } - else if ( seconds_min_c > seconds_2 ) { - std::cout << " Fastest run: Collapse2 RangePolicy\n" - << " Time: " << seconds_2 - << " Difference: " << seconds_min_c - seconds_2 - << " Other times: \n" - << " MDrange Tiled: " << seconds_min << "\n" - << " MDrange collapse-like (tiledim = span on fast dim) type: " << seconds_min_c << "\n" - << "\n--------------------------------------------------------------" - << "\n--------------------------------------------------------------" - //<< "\n\n" - << std::endl; + } else if (seconds_min > seconds_min_c) { + if (seconds_min_c < seconds_2) { + std::cout << "---------------------------------------------------------" + "-----\n" + << " Fastest run: MDRange collapse-like (tiledim = span on " + "fast dim) type\n" + << " Time: " << seconds_min_c + << " Difference: " << seconds_2 - seconds_min_c + << " Other times: \n" + << " MDrange Tiled: " << seconds_min << "\n" + << " Collapse2 Range Policy: " << seconds_2 << "\n" + << "\n-------------------------------------------------------" + "-------" + << "\n-------------------------------------------------------" + "-------" + //<< "\n\n" + << std::endl; + } else if (seconds_min_c > seconds_2) { + std::cout + << " Fastest run: Collapse2 RangePolicy\n" + << " Time: " << seconds_2 + << " Difference: " << seconds_min_c - seconds_2 + << " Other times: \n" + << " MDrange Tiled: " << seconds_min << "\n" + << " MDrange collapse-like (tiledim = span on fast dim) type: " + << seconds_min_c << "\n" + << "\n-------------------------------------------------------------" + "-" + << "\n-------------------------------------------------------------" + "-" + //<< "\n\n" + << std::endl; } - } // end else if + } // end else if #else - if ( seconds_min < seconds_2 ) { - std::cout << "--------------------------------------------------------------\n" + if (seconds_min < seconds_2) { + std::cout + << "--------------------------------------------------------------\n" << " Fastest run: MDRange tiled\n" << " Time: " << seconds_min - << " Difference: " << seconds_2 - seconds_min - << " Other times: \n" + << " Difference: " << seconds_2 - seconds_min << " Other times: \n" << " Collapse2 Range Policy: " << seconds_2 << "\n" << "\n--------------------------------------------------------------" << "\n--------------------------------------------------------------" //<< "\n\n" << std::endl; - } - else if ( seconds_min > seconds_2 ) { - std::cout << " Fastest run: Collapse2 RangePolicy\n" + } else if (seconds_min > seconds_2) { + std::cout + << " Fastest run: Collapse2 RangePolicy\n" << " Time: " << seconds_2 - << " Difference: " << seconds_min - seconds_2 - << " Other times: \n" + << " Difference: " << seconds_min - seconds_2 << " Other times: \n" << " MDrange Tiled: " << seconds_min << "\n" << "\n--------------------------------------------------------------" << "\n--------------------------------------------------------------" //<< "\n\n" << std::endl; - } + } #endif - } //end for + } // end for #undef MDRANGE_PERFORMANCE_OUTPUT_VERBOSE - -} - - } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTestGramSchmidt.cpp b/lib/kokkos/core/perf_test/PerfTestGramSchmidt.cpp index d812b16d85..5e85163acf 100644 --- a/lib/kokkos/core/perf_test/PerfTestGramSchmidt.cpp +++ b/lib/kokkos/core/perf_test/PerfTestGramSchmidt.cpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -55,131 +56,105 @@ namespace Test { // Reduction : result = dot( Q(:,j) , Q(:,j) ); // PostProcess : R(j,j) = result ; inv = 1 / result ; -template< class VectorView , class ValueView > -struct InvNorm2 : public Kokkos::DotSingle< VectorView > { +template +struct InvNorm2 : public Kokkos::DotSingle { + typedef typename Kokkos::DotSingle::value_type value_type; - typedef typename Kokkos::DotSingle< VectorView >::value_type value_type ; + ValueView Rjj; + ValueView inv; - ValueView Rjj ; - ValueView inv ; - - InvNorm2( const VectorView & argX , - const ValueView & argR , - const ValueView & argInv ) - : Kokkos::DotSingle< VectorView >( argX ) - , Rjj( argR ) - , inv( argInv ) - {} + InvNorm2(const VectorView& argX, const ValueView& argR, + const ValueView& argInv) + : Kokkos::DotSingle(argX), Rjj(argR), inv(argInv) {} KOKKOS_INLINE_FUNCTION - void final( value_type & result ) const - { - result = std::sqrt( result ); - Rjj() = result ; - inv() = ( 0 < result ) ? 1.0 / result : 0 ; + void final(value_type& result) const { + result = std::sqrt(result); + Rjj() = result; + inv() = (0 < result) ? 1.0 / result : 0; } }; -template< class VectorView , class ValueView > -inline -void invnorm2( const VectorView & x , - const ValueView & r , - const ValueView & r_inv ) -{ - Kokkos::parallel_reduce( x.extent(0) , InvNorm2< VectorView , ValueView >( x , r , r_inv ) ); +template +inline void invnorm2(const VectorView& x, const ValueView& r, + const ValueView& r_inv) { + Kokkos::parallel_reduce(x.extent(0), + InvNorm2(x, r, r_inv)); } // PostProcess : tmp = - ( R(j,k) = result ); -template< class VectorView , class ValueView > -struct DotM : public Kokkos::Dot< VectorView > { - - typedef typename Kokkos::Dot< VectorView >::value_type value_type ; +template +struct DotM : public Kokkos::Dot { + typedef typename Kokkos::Dot::value_type value_type; - ValueView Rjk ; - ValueView tmp ; + ValueView Rjk; + ValueView tmp; - DotM( const VectorView & argX , - const VectorView & argY , - const ValueView & argR , - const ValueView & argTmp ) - : Kokkos::Dot< VectorView >( argX , argY ) - , Rjk( argR ) - , tmp( argTmp ) - {} + DotM(const VectorView& argX, const VectorView& argY, const ValueView& argR, + const ValueView& argTmp) + : Kokkos::Dot(argX, argY), Rjk(argR), tmp(argTmp) {} KOKKOS_INLINE_FUNCTION - void final( value_type & result ) const - { - Rjk() = result ; - tmp() = - result ; + void final(value_type& result) const { + Rjk() = result; + tmp() = -result; } }; -template< class VectorView , class ValueView > -inline -void dot_neg( const VectorView & x , - const VectorView & y , - const ValueView & r , - const ValueView & r_neg ) -{ - Kokkos::parallel_reduce( x.extent(0) , DotM< VectorView , ValueView >( x , y , r , r_neg ) ); +template +inline void dot_neg(const VectorView& x, const VectorView& y, + const ValueView& r, const ValueView& r_neg) { + Kokkos::parallel_reduce(x.extent(0), + DotM(x, y, r, r_neg)); } +template +struct ModifiedGramSchmidt { + typedef DeviceType execution_space; + typedef typename execution_space::size_type size_type; -template< typename Scalar , class DeviceType > -struct ModifiedGramSchmidt -{ - typedef DeviceType execution_space ; - typedef typename execution_space::size_type size_type ; - - typedef Kokkos::View< Scalar** , - Kokkos::LayoutLeft , - execution_space > multivector_type ; - - typedef Kokkos::View< Scalar* , - Kokkos::LayoutLeft , - execution_space > vector_type ; + typedef Kokkos::View + multivector_type; - typedef Kokkos::View< Scalar , - Kokkos::LayoutLeft , - execution_space > value_view ; + typedef Kokkos::View + vector_type; + typedef Kokkos::View value_view; - multivector_type Q ; - multivector_type R ; + multivector_type Q; + multivector_type R; - static double factorization( const multivector_type Q_ , - const multivector_type R_ ) - { - const size_type count = Q_.extent(1); + static double factorization(const multivector_type Q_, + const multivector_type R_) { + const size_type count = Q_.extent(1); value_view tmp("tmp"); value_view one("one"); - Kokkos::deep_copy( one , (Scalar) 1 ); + Kokkos::deep_copy(one, (Scalar)1); - Kokkos::Timer timer ; + Kokkos::Timer timer; - for ( size_type j = 0 ; j < count ; ++j ) { + for (size_type j = 0; j < count; ++j) { // Reduction : tmp = dot( Q(:,j) , Q(:,j) ); // PostProcess : tmp = std::sqrt( tmp ); R(j,j) = tmp ; tmp = 1 / tmp ; - const vector_type Qj = Kokkos::subview( Q_ , Kokkos::ALL() , j ); - const value_view Rjj = Kokkos::subview( R_ , j , j ); + const vector_type Qj = Kokkos::subview(Q_, Kokkos::ALL(), j); + const value_view Rjj = Kokkos::subview(R_, j, j); - invnorm2( Qj , Rjj , tmp ); + invnorm2(Qj, Rjj, tmp); // Q(:,j) *= ( 1 / R(j,j) ); => Q(:,j) *= tmp ; - Kokkos::scale( tmp , Qj ); + Kokkos::scale(tmp, Qj); - for ( size_t k = j + 1 ; k < count ; ++k ) { - const vector_type Qk = Kokkos::subview( Q_ , Kokkos::ALL() , k ); - const value_view Rjk = Kokkos::subview( R_ , j , k ); + for (size_t k = j + 1; k < count; ++k) { + const vector_type Qk = Kokkos::subview(Q_, Kokkos::ALL(), k); + const value_view Rjk = Kokkos::subview(R_, j, k); // Reduction : R(j,k) = dot( Q(:,j) , Q(:,k) ); // PostProcess : tmp = - R(j,k); - dot_neg( Qj , Qk , Rjk , tmp ); + dot_neg(Qj, Qk, Rjk, tmp); // Q(:,k) -= R(j,k) * Q(:,j); => Q(:,k) += tmp * Q(:,j) - Kokkos::axpby( tmp , Qj , one , Qk ); + Kokkos::axpby(tmp, Qj, one, Qk); } } @@ -190,94 +165,87 @@ struct ModifiedGramSchmidt //-------------------------------------------------------------------------- - static double test( const size_t length , - const size_t count , - const size_t iter = 1 ) - { - multivector_type Q_( "Q" , length , count ); - multivector_type R_( "R" , count , count ); + static double test(const size_t length, const size_t count, + const size_t iter = 1) { + multivector_type Q_("Q", length, count); + multivector_type R_("R", count, count); - typename multivector_type::HostMirror A = - Kokkos::create_mirror( Q_ ); + typename multivector_type::HostMirror A = Kokkos::create_mirror(Q_); // Create and fill A on the host - for ( size_type j = 0 ; j < count ; ++j ) { - for ( size_type i = 0 ; i < length ; ++i ) { - A(i,j) = ( i + 1 ) * ( j + 1 ); + for (size_type j = 0; j < count; ++j) { + for (size_type i = 0; i < length; ++i) { + A(i, j) = (i + 1) * (j + 1); } } - double dt_min = 0 ; + double dt_min = 0; - for ( size_t i = 0 ; i < iter ; ++i ) { - - Kokkos::deep_copy( Q_ , A ); + for (size_t i = 0; i < iter; ++i) { + Kokkos::deep_copy(Q_, A); // A = Q * R - const double dt = factorization( Q_ , R_ ); + const double dt = factorization(Q_, R_); - if ( 0 == i ) dt_min = dt ; - else dt_min = dt < dt_min ? dt : dt_min ; + if (0 == i) + dt_min = dt; + else + dt_min = dt < dt_min ? dt : dt_min; } - return dt_min ; + return dt_min; } }; -template< class DeviceType > -void run_test_gramschmidt( int exp_beg , int exp_end, int num_trials, const char deviceTypeName[] ) -{ - std::string label_gramschmidt ; - label_gramschmidt.append( "\"GramSchmidt< double , " ); - label_gramschmidt.append( deviceTypeName ); - label_gramschmidt.append( " >\"" ); - - for (int i = exp_beg ; i < exp_end ; ++i) { - double min_seconds = 0.0 ; - double max_seconds = 0.0 ; - double avg_seconds = 0.0 ; - - const int parallel_work_length = 1<::test(parallel_work_length, 32 ) ; - - if ( 0 == j ) { - min_seconds = seconds ; - max_seconds = seconds ; - } - else { - if ( seconds < min_seconds ) min_seconds = seconds ; - if ( seconds > max_seconds ) max_seconds = seconds ; +template +void run_test_gramschmidt(int exp_beg, int exp_end, int num_trials, + const char deviceTypeName[]) { + std::string label_gramschmidt; + label_gramschmidt.append("\"GramSchmidt< double , "); + label_gramschmidt.append(deviceTypeName); + label_gramschmidt.append(" >\""); + + for (int i = exp_beg; i < exp_end; ++i) { + double min_seconds = 0.0; + double max_seconds = 0.0; + double avg_seconds = 0.0; + + const int parallel_work_length = 1 << i; + + for (int j = 0; j < num_trials; ++j) { + const double seconds = ModifiedGramSchmidt::test( + parallel_work_length, 32); + + if (0 == j) { + min_seconds = seconds; + max_seconds = seconds; + } else { + if (seconds < min_seconds) min_seconds = seconds; + if (seconds > max_seconds) max_seconds = seconds; } - avg_seconds += seconds ; + avg_seconds += seconds; } - avg_seconds /= num_trials ; + avg_seconds /= num_trials; - std::cout << label_gramschmidt - << " , " << parallel_work_length - << " , " << min_seconds - << " , " << ( min_seconds / parallel_work_length ) - << std::endl ; + std::cout << label_gramschmidt << " , " << parallel_work_length << " , " + << min_seconds << " , " << (min_seconds / parallel_work_length) + << std::endl; } } -TEST_F( default_exec, gramschmidt ) { - int exp_beg = 10; - int exp_end = 20; +TEST(default_exec, gramschmidt) { + int exp_beg = 10; + int exp_end = 20; int num_trials = 5; - if(command_line_num_args()>1) - exp_beg = atoi(command_line_arg(1)); - if(command_line_num_args()>2) - exp_end = atoi(command_line_arg(2)); - if(command_line_num_args()>3) - num_trials = atoi(command_line_arg(3)); - - EXPECT_NO_THROW(run_test_gramschmidt< Kokkos::DefaultExecutionSpace>( exp_beg, exp_end, num_trials, Kokkos::DefaultExecutionSpace::name() )); -} + if (command_line_num_args() > 1) exp_beg = atoi(command_line_arg(1)); + if (command_line_num_args() > 2) exp_end = atoi(command_line_arg(2)); + if (command_line_num_args() > 3) num_trials = atoi(command_line_arg(3)); + EXPECT_NO_THROW(run_test_gramschmidt( + exp_beg, exp_end, num_trials, Kokkos::DefaultExecutionSpace::name())); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTestHexGrad.cpp b/lib/kokkos/core/perf_test/PerfTestHexGrad.cpp index 03285a375c..d879282867 100644 --- a/lib/kokkos/core/perf_test/PerfTestHexGrad.cpp +++ b/lib/kokkos/core/perf_test/PerfTestHexGrad.cpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -47,279 +48,253 @@ namespace Test { -template< class DeviceType , - typename CoordScalarType = double , - typename GradScalarType = float > -struct HexGrad -{ - typedef DeviceType execution_space ; - typedef typename execution_space::size_type size_type ; +template +struct HexGrad { + typedef DeviceType execution_space; + typedef typename execution_space::size_type size_type; - typedef HexGrad self_type; + typedef HexGrad self_type; // 3D array : ( ParallelWork , Space , Node ) - enum { NSpace = 3 , NNode = 8 }; + enum { NSpace = 3, NNode = 8 }; - typedef Kokkos::View< CoordScalarType*[NSpace][NNode] , execution_space > - elem_coord_type ; + typedef Kokkos::View + elem_coord_type; - typedef Kokkos::View< GradScalarType*[NSpace][NNode] , execution_space > - elem_grad_type ; + typedef Kokkos::View + elem_grad_type; - elem_coord_type coords ; - elem_grad_type grad_op ; + elem_coord_type coords; + elem_grad_type grad_op; - enum { FLOPS = 318 }; // = 3 * ( 18 + 8 * 11 ) }; - enum { READS = 18 }; + enum { FLOPS = 318 }; // = 3 * ( 18 + 8 * 11 ) }; + enum { READS = 18 }; enum { WRITES = 18 }; - HexGrad( const elem_coord_type & arg_coords , - const elem_grad_type & arg_grad_op ) - : coords( arg_coords ) - , grad_op( arg_grad_op ) - {} - - KOKKOS_INLINE_FUNCTION static - void grad( const CoordScalarType x[] , - const CoordScalarType z[] , - GradScalarType grad_y[] ) - { - const GradScalarType R42=(x[3] - x[1]); - const GradScalarType R52=(x[4] - x[1]); - const GradScalarType R54=(x[4] - x[3]); - - const GradScalarType R63=(x[5] - x[2]); - const GradScalarType R83=(x[7] - x[2]); - const GradScalarType R86=(x[7] - x[5]); - - const GradScalarType R31=(x[2] - x[0]); - const GradScalarType R61=(x[5] - x[0]); - const GradScalarType R74=(x[6] - x[3]); - - const GradScalarType R72=(x[6] - x[1]); - const GradScalarType R75=(x[6] - x[4]); - const GradScalarType R81=(x[7] - x[0]); - - const GradScalarType t1=(R63 + R54); - const GradScalarType t2=(R61 + R74); - const GradScalarType t3=(R72 + R81); - - const GradScalarType t4 =(R86 + R42); - const GradScalarType t5 =(R83 + R52); - const GradScalarType t6 =(R75 + R31); + HexGrad(const elem_coord_type& arg_coords, const elem_grad_type& arg_grad_op) + : coords(arg_coords), grad_op(arg_grad_op) {} + + KOKKOS_INLINE_FUNCTION static void grad(const CoordScalarType x[], + const CoordScalarType z[], + GradScalarType grad_y[]) { + const GradScalarType R42 = (x[3] - x[1]); + const GradScalarType R52 = (x[4] - x[1]); + const GradScalarType R54 = (x[4] - x[3]); + + const GradScalarType R63 = (x[5] - x[2]); + const GradScalarType R83 = (x[7] - x[2]); + const GradScalarType R86 = (x[7] - x[5]); + + const GradScalarType R31 = (x[2] - x[0]); + const GradScalarType R61 = (x[5] - x[0]); + const GradScalarType R74 = (x[6] - x[3]); + + const GradScalarType R72 = (x[6] - x[1]); + const GradScalarType R75 = (x[6] - x[4]); + const GradScalarType R81 = (x[7] - x[0]); + + const GradScalarType t1 = (R63 + R54); + const GradScalarType t2 = (R61 + R74); + const GradScalarType t3 = (R72 + R81); + + const GradScalarType t4 = (R86 + R42); + const GradScalarType t5 = (R83 + R52); + const GradScalarType t6 = (R75 + R31); // Calculate Y gradient from X and Z data - grad_y[0] = (z[1] * t1) - (z[2] * R42) - (z[3] * t5) + (z[4] * t4) + (z[5] * R52) - (z[7] * R54); - grad_y[1] = (z[2] * t2) + (z[3] * R31) - (z[0] * t1) - (z[5] * t6) + (z[6] * R63) - (z[4] * R61); - grad_y[2] = (z[3] * t3) + (z[0] * R42) - (z[1] * t2) - (z[6] * t4) + (z[7] * R74) - (z[5] * R72); - grad_y[3] = (z[0] * t5) - (z[1] * R31) - (z[2] * t3) + (z[7] * t6) + (z[4] * R81) - (z[6] * R83); - grad_y[4] = (z[5] * t3) + (z[6] * R86) - (z[7] * t2) - (z[0] * t4) - (z[3] * R81) + (z[1] * R61); - grad_y[5] = (z[6] * t5) - (z[4] * t3) - (z[7] * R75) + (z[1] * t6) - (z[0] * R52) + (z[2] * R72); - grad_y[6] = (z[7] * t1) - (z[5] * t5) - (z[4] * R86) + (z[2] * t4) - (z[1] * R63) + (z[3] * R83); - grad_y[7] = (z[4] * t2) - (z[6] * t1) + (z[5] * R75) - (z[3] * t6) - (z[2] * R74) + (z[0] * R54); + grad_y[0] = (z[1] * t1) - (z[2] * R42) - (z[3] * t5) + (z[4] * t4) + + (z[5] * R52) - (z[7] * R54); + grad_y[1] = (z[2] * t2) + (z[3] * R31) - (z[0] * t1) - (z[5] * t6) + + (z[6] * R63) - (z[4] * R61); + grad_y[2] = (z[3] * t3) + (z[0] * R42) - (z[1] * t2) - (z[6] * t4) + + (z[7] * R74) - (z[5] * R72); + grad_y[3] = (z[0] * t5) - (z[1] * R31) - (z[2] * t3) + (z[7] * t6) + + (z[4] * R81) - (z[6] * R83); + grad_y[4] = (z[5] * t3) + (z[6] * R86) - (z[7] * t2) - (z[0] * t4) - + (z[3] * R81) + (z[1] * R61); + grad_y[5] = (z[6] * t5) - (z[4] * t3) - (z[7] * R75) + (z[1] * t6) - + (z[0] * R52) + (z[2] * R72); + grad_y[6] = (z[7] * t1) - (z[5] * t5) - (z[4] * R86) + (z[2] * t4) - + (z[1] * R63) + (z[3] * R83); + grad_y[7] = (z[4] * t2) - (z[6] * t1) + (z[5] * R75) - (z[3] * t6) - + (z[2] * R74) + (z[0] * R54); } KOKKOS_INLINE_FUNCTION - void operator()( size_type ielem ) const - { - GradScalarType g[NNode] ; - - const CoordScalarType x[NNode] = { - coords(ielem,0,0), - coords(ielem,0,1), - coords(ielem,0,2), - coords(ielem,0,3), - coords(ielem,0,4), - coords(ielem,0,5), - coords(ielem,0,6), - coords(ielem,0,7) - }; - - const CoordScalarType y[NNode] = { - coords(ielem,1,0), - coords(ielem,1,1), - coords(ielem,1,2), - coords(ielem,1,3), - coords(ielem,1,4), - coords(ielem,1,5), - coords(ielem,1,6), - coords(ielem,1,7) - }; - - const CoordScalarType z[NNode] = { - coords(ielem,2,0), - coords(ielem,2,1), - coords(ielem,2,2), - coords(ielem,2,3), - coords(ielem,2,4), - coords(ielem,2,5), - coords(ielem,2,6), - coords(ielem,2,7) - }; - - grad( z , y , g ); - - grad_op(ielem,0,0) = g[0]; - grad_op(ielem,0,1) = g[1]; - grad_op(ielem,0,2) = g[2]; - grad_op(ielem,0,3) = g[3]; - grad_op(ielem,0,4) = g[4]; - grad_op(ielem,0,5) = g[5]; - grad_op(ielem,0,6) = g[6]; - grad_op(ielem,0,7) = g[7]; - - grad( x , z , g ); - - grad_op(ielem,1,0) = g[0]; - grad_op(ielem,1,1) = g[1]; - grad_op(ielem,1,2) = g[2]; - grad_op(ielem,1,3) = g[3]; - grad_op(ielem,1,4) = g[4]; - grad_op(ielem,1,5) = g[5]; - grad_op(ielem,1,6) = g[6]; - grad_op(ielem,1,7) = g[7]; - - grad( y , x , g ); - - grad_op(ielem,2,0) = g[0]; - grad_op(ielem,2,1) = g[1]; - grad_op(ielem,2,2) = g[2]; - grad_op(ielem,2,3) = g[3]; - grad_op(ielem,2,4) = g[4]; - grad_op(ielem,2,5) = g[5]; - grad_op(ielem,2,6) = g[6]; - grad_op(ielem,2,7) = g[7]; + void operator()(size_type ielem) const { + GradScalarType g[NNode]; + + const CoordScalarType x[NNode] = {coords(ielem, 0, 0), coords(ielem, 0, 1), + coords(ielem, 0, 2), coords(ielem, 0, 3), + coords(ielem, 0, 4), coords(ielem, 0, 5), + coords(ielem, 0, 6), coords(ielem, 0, 7)}; + + const CoordScalarType y[NNode] = {coords(ielem, 1, 0), coords(ielem, 1, 1), + coords(ielem, 1, 2), coords(ielem, 1, 3), + coords(ielem, 1, 4), coords(ielem, 1, 5), + coords(ielem, 1, 6), coords(ielem, 1, 7)}; + + const CoordScalarType z[NNode] = {coords(ielem, 2, 0), coords(ielem, 2, 1), + coords(ielem, 2, 2), coords(ielem, 2, 3), + coords(ielem, 2, 4), coords(ielem, 2, 5), + coords(ielem, 2, 6), coords(ielem, 2, 7)}; + + grad(z, y, g); + + grad_op(ielem, 0, 0) = g[0]; + grad_op(ielem, 0, 1) = g[1]; + grad_op(ielem, 0, 2) = g[2]; + grad_op(ielem, 0, 3) = g[3]; + grad_op(ielem, 0, 4) = g[4]; + grad_op(ielem, 0, 5) = g[5]; + grad_op(ielem, 0, 6) = g[6]; + grad_op(ielem, 0, 7) = g[7]; + + grad(x, z, g); + + grad_op(ielem, 1, 0) = g[0]; + grad_op(ielem, 1, 1) = g[1]; + grad_op(ielem, 1, 2) = g[2]; + grad_op(ielem, 1, 3) = g[3]; + grad_op(ielem, 1, 4) = g[4]; + grad_op(ielem, 1, 5) = g[5]; + grad_op(ielem, 1, 6) = g[6]; + grad_op(ielem, 1, 7) = g[7]; + + grad(y, x, g); + + grad_op(ielem, 2, 0) = g[0]; + grad_op(ielem, 2, 1) = g[1]; + grad_op(ielem, 2, 2) = g[2]; + grad_op(ielem, 2, 3) = g[3]; + grad_op(ielem, 2, 4) = g[4]; + grad_op(ielem, 2, 5) = g[5]; + grad_op(ielem, 2, 6) = g[6]; + grad_op(ielem, 2, 7) = g[7]; } //-------------------------------------------------------------------------- struct Init { - typedef typename self_type::execution_space execution_space ; + typedef typename self_type::execution_space execution_space; - elem_coord_type coords ; + elem_coord_type coords; - Init( const elem_coord_type & arg_coords ) - : coords( arg_coords ) {} + Init(const elem_coord_type& arg_coords) : coords(arg_coords) {} KOKKOS_INLINE_FUNCTION - void operator()( size_type ielem ) const - { - coords(ielem,0,0) = 0.; - coords(ielem,1,0) = 0.; - coords(ielem,2,0) = 0.; - - coords(ielem,0,1) = 1.; - coords(ielem,1,1) = 0.; - coords(ielem,2,1) = 0.; - - coords(ielem,0,2) = 1.; - coords(ielem,1,2) = 1.; - coords(ielem,2,2) = 0.; - - coords(ielem,0,3) = 0.; - coords(ielem,1,3) = 1.; - coords(ielem,2,3) = 0.; - - - coords(ielem,0,4) = 0.; - coords(ielem,1,4) = 0.; - coords(ielem,2,4) = 1.; - - coords(ielem,0,5) = 1.; - coords(ielem,1,5) = 0.; - coords(ielem,2,5) = 1.; - - coords(ielem,0,6) = 1.; - coords(ielem,1,6) = 1.; - coords(ielem,2,6) = 1.; - - coords(ielem,0,7) = 0.; - coords(ielem,1,7) = 1.; - coords(ielem,2,7) = 1.; + void operator()(size_type ielem) const { + coords(ielem, 0, 0) = 0.; + coords(ielem, 1, 0) = 0.; + coords(ielem, 2, 0) = 0.; + + coords(ielem, 0, 1) = 1.; + coords(ielem, 1, 1) = 0.; + coords(ielem, 2, 1) = 0.; + + coords(ielem, 0, 2) = 1.; + coords(ielem, 1, 2) = 1.; + coords(ielem, 2, 2) = 0.; + + coords(ielem, 0, 3) = 0.; + coords(ielem, 1, 3) = 1.; + coords(ielem, 2, 3) = 0.; + + coords(ielem, 0, 4) = 0.; + coords(ielem, 1, 4) = 0.; + coords(ielem, 2, 4) = 1.; + + coords(ielem, 0, 5) = 1.; + coords(ielem, 1, 5) = 0.; + coords(ielem, 2, 5) = 1.; + + coords(ielem, 0, 6) = 1.; + coords(ielem, 1, 6) = 1.; + coords(ielem, 2, 6) = 1.; + + coords(ielem, 0, 7) = 0.; + coords(ielem, 1, 7) = 1.; + coords(ielem, 2, 7) = 1.; } }; //-------------------------------------------------------------------------- - static double test( const int count , const int iter = 1 ) - { - elem_coord_type coord( "coord" , count ); - elem_grad_type grad ( "grad" , count ); + static double test(const int count, const int iter = 1) { + elem_coord_type coord("coord", count); + elem_grad_type grad("grad", count); // Execute the parallel kernels on the arrays: - double dt_min = 0 ; + double dt_min = 0; - Kokkos::parallel_for( count , Init( coord ) ); + Kokkos::parallel_for(count, Init(coord)); execution_space().fence(); - for ( int i = 0 ; i < iter ; ++i ) { - Kokkos::Timer timer ; - Kokkos::parallel_for( count , HexGrad( coord , grad ) ); + for (int i = 0; i < iter; ++i) { + Kokkos::Timer timer; + Kokkos::parallel_for(count, HexGrad(coord, grad)); execution_space().fence(); const double dt = timer.seconds(); - if ( 0 == i ) dt_min = dt ; - else dt_min = dt < dt_min ? dt : dt_min ; + if (0 == i) + dt_min = dt; + else + dt_min = dt < dt_min ? dt : dt_min; } - return dt_min ; + return dt_min; } }; -template< class DeviceType > -void run_test_hexgrad( int exp_beg , int exp_end, int num_trials, const char deviceTypeName[] ) -{ - std::string label_hexgrad ; - label_hexgrad.append( "\"HexGrad< double , " ); - label_hexgrad.append( deviceTypeName ); - label_hexgrad.append( " >\"" ); - - for (int i = exp_beg ; i < exp_end ; ++i) { - double min_seconds = 0.0 ; - double max_seconds = 0.0 ; - double avg_seconds = 0.0 ; - - const int parallel_work_length = 1<::test(parallel_work_length) ; - - if ( 0 == j ) { - min_seconds = seconds ; - max_seconds = seconds ; +template +void run_test_hexgrad(int exp_beg, int exp_end, int num_trials, + const char deviceTypeName[]) { + std::string label_hexgrad; + label_hexgrad.append("\"HexGrad< double , "); + label_hexgrad.append(deviceTypeName); + label_hexgrad.append(" >\""); + + for (int i = exp_beg; i < exp_end; ++i) { + double min_seconds = 0.0; + double max_seconds = 0.0; + double avg_seconds = 0.0; + + const int parallel_work_length = 1 << i; + + for (int j = 0; j < num_trials; ++j) { + const double seconds = HexGrad::test(parallel_work_length); + + if (0 == j) { + min_seconds = seconds; + max_seconds = seconds; + } else { + if (seconds < min_seconds) min_seconds = seconds; + if (seconds > max_seconds) max_seconds = seconds; } - else { - if ( seconds < min_seconds ) min_seconds = seconds ; - if ( seconds > max_seconds ) max_seconds = seconds ; - } - avg_seconds += seconds ; + avg_seconds += seconds; } - avg_seconds /= num_trials ; + avg_seconds /= num_trials; - std::cout << label_hexgrad - << " , " << parallel_work_length - << " , " << min_seconds - << " , " << ( min_seconds / parallel_work_length ) - << std::endl ; + std::cout << label_hexgrad << " , " << parallel_work_length << " , " + << min_seconds << " , " << (min_seconds / parallel_work_length) + << std::endl; } } -TEST_F( default_exec, hexgrad ) { - int exp_beg = 10; - int exp_end = 20; +TEST(default_exec, hexgrad) { + int exp_beg = 10; + int exp_end = 20; int num_trials = 5; - if(command_line_num_args()>1) - exp_beg = atoi(command_line_arg(1)); - if(command_line_num_args()>2) - exp_end = atoi(command_line_arg(2)); - if(command_line_num_args()>3) - num_trials = atoi(command_line_arg(3)); - - EXPECT_NO_THROW(run_test_hexgrad< Kokkos::DefaultExecutionSpace >( exp_beg, exp_end, num_trials, Kokkos::DefaultExecutionSpace::name() )); -} + if (command_line_num_args() > 1) exp_beg = atoi(command_line_arg(1)); + if (command_line_num_args() > 2) exp_end = atoi(command_line_arg(2)); + if (command_line_num_args() > 3) num_trials = atoi(command_line_arg(3)); + EXPECT_NO_THROW(run_test_hexgrad( + exp_beg, exp_end, num_trials, Kokkos::DefaultExecutionSpace::name())); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTestMDRange.hpp b/lib/kokkos/core/perf_test/PerfTestMDRange.hpp index f433451f78..3afff96ff3 100644 --- a/lib/kokkos/core/perf_test/PerfTestMDRange.hpp +++ b/lib/kokkos/core/perf_test/PerfTestMDRange.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,24 +37,21 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ namespace Test { -template< class DeviceType - , typename ScalarType = double - , typename TestLayout = Kokkos::LayoutRight - > -struct MultiDimRangePerf3D -{ +template +struct MultiDimRangePerf3D { typedef DeviceType execution_space; - typedef typename execution_space::size_type size_type; + typedef typename execution_space::size_type size_type; using iterate_type = Kokkos::Iterate; - typedef Kokkos::View view_type; + typedef Kokkos::View view_type; typedef typename view_type::HostMirror host_view_type; view_type A; @@ -62,39 +60,36 @@ struct MultiDimRangePerf3D const long jrange; const long krange; - MultiDimRangePerf3D(const view_type & A_, const view_type & B_, const long &irange_, const long &jrange_, const long &krange_) - : A(A_), B(B_), irange(irange_), jrange(jrange_), krange(krange_) - {} + MultiDimRangePerf3D(const view_type &A_, const view_type &B_, + const long &irange_, const long &jrange_, + const long &krange_) + : A(A_), B(B_), irange(irange_), jrange(jrange_), krange(krange_) {} KOKKOS_INLINE_FUNCTION - void operator()(const long i, const long j, const long k) const - { - A(i,j,k) = 0.25*(ScalarType)( B(i+2,j,k) + B(i+1,j,k) - + B(i,j+2,k) + B(i,j+1,k) - + B(i,j,k+2) + B(i,j,k+1) - + B(i,j,k) ); + void operator()(const long i, const long j, const long k) const { + A(i, j, k) = + 0.25 * (ScalarType)(B(i + 2, j, k) + B(i + 1, j, k) + B(i, j + 2, k) + + B(i, j + 1, k) + B(i, j, k + 2) + B(i, j, k + 1) + + B(i, j, k)); } - struct InitZeroTag {}; -// struct InitViewTag {}; - - struct Init - { + // struct InitViewTag {}; - Init(const view_type & input_, const long &irange_, const long &jrange_, const long &krange_) - : input(input_), irange(irange_), jrange(jrange_), krange(krange_) {} + struct Init { + Init(const view_type &input_, const long &irange_, const long &jrange_, + const long &krange_) + : input(input_), irange(irange_), jrange(jrange_), krange(krange_) {} KOKKOS_INLINE_FUNCTION - void operator()(const long i, const long j, const long k) const - { - input(i,j,k) = 1.0; + void operator()(const long i, const long j, const long k) const { + input(i, j, k) = 1.0; } KOKKOS_INLINE_FUNCTION - void operator()(const InitZeroTag&, const long i, const long j, const long k) const - { - input(i,j,k) = 0; + void operator()(const InitZeroTag &, const long i, const long j, + const long k) const { + input(i, j, k) = 0; } view_type input; @@ -103,166 +98,221 @@ struct MultiDimRangePerf3D const long krange; }; - - static double test_multi_index(const unsigned int icount, const unsigned int jcount, const unsigned int kcount, const unsigned int Ti = 1, const unsigned int Tj = 1, const unsigned int Tk = 1, const long iter = 1) - { - //This test performs multidim range over all dims + static double test_multi_index(const unsigned int icount, + const unsigned int jcount, + const unsigned int kcount, + const unsigned int Ti = 1, + const unsigned int Tj = 1, + const unsigned int Tk = 1, + const long iter = 1) { + // This test performs multidim range over all dims view_type Atest("Atest", icount, jcount, kcount); - view_type Btest("Btest", icount+2, jcount+2, kcount+2); - typedef MultiDimRangePerf3D FunctorType; + view_type Btest("Btest", icount + 2, jcount + 2, kcount + 2); + typedef MultiDimRangePerf3D + FunctorType; double dt_min = 0; // LayoutRight - if ( std::is_same::value ) { - Kokkos::MDRangePolicy, execution_space > policy_initA({{0,0,0}},{{icount,jcount,kcount}},{{Ti,Tj,Tk}}); - Kokkos::MDRangePolicy, execution_space > policy_initB({{0,0,0}},{{icount+2,jcount+2,kcount+2}},{{Ti,Tj,Tk}}); - - typedef typename Kokkos::MDRangePolicy, execution_space > MDRangeType; - using tile_type = typename MDRangeType::tile_type; + if (std::is_same::value) { + Kokkos::MDRangePolicy< + Kokkos::Rank<3, iterate_type::Right, iterate_type::Right>, + execution_space> + policy_initA({{0, 0, 0}}, {{icount, jcount, kcount}}, {{Ti, Tj, Tk}}); + Kokkos::MDRangePolicy< + Kokkos::Rank<3, iterate_type::Right, iterate_type::Right>, + execution_space> + policy_initB({{0, 0, 0}}, {{icount + 2, jcount + 2, kcount + 2}}, + {{Ti, Tj, Tk}}); + + typedef typename Kokkos::MDRangePolicy< + Kokkos::Rank<3, iterate_type::Right, iterate_type::Right>, + execution_space> + MDRangeType; + using tile_type = typename MDRangeType::tile_type; using point_type = typename MDRangeType::point_type; - Kokkos::MDRangePolicy, execution_space > policy(point_type{{0,0,0}},point_type{{icount,jcount,kcount}},tile_type{{Ti,Tj,Tk}} ); + Kokkos::MDRangePolicy< + Kokkos::Rank<3, iterate_type::Right, iterate_type::Right>, + execution_space> + policy(point_type{{0, 0, 0}}, point_type{{icount, jcount, kcount}}, + tile_type{{Ti, Tj, Tk}}); - Kokkos::parallel_for( policy_initA, Init(Atest, icount, jcount, kcount) ); + Kokkos::parallel_for(policy_initA, Init(Atest, icount, jcount, kcount)); execution_space().fence(); - Kokkos::parallel_for( policy_initB, Init(Btest, icount+2, jcount+2, kcount+2) ); + Kokkos::parallel_for(policy_initB, + Init(Btest, icount + 2, jcount + 2, kcount + 2)); execution_space().fence(); - for (int i = 0; i < iter; ++i) - { - Kokkos::Timer timer; - Kokkos::parallel_for( policy, FunctorType(Atest, Btest, icount, jcount, kcount) ); - execution_space().fence(); - const double dt = timer.seconds(); - if ( 0 == i ) dt_min = dt ; - else dt_min = dt < dt_min ? dt : dt_min ; - - //Correctness check - only the first run - if ( 0 == i ) - { - long numErrors = 0; - host_view_type Ahost("Ahost", icount, jcount, kcount); - Kokkos::deep_copy(Ahost, Atest); - host_view_type Bhost("Bhost", icount+2, jcount+2, kcount+2); - Kokkos::deep_copy(Bhost, Btest); - - // On KNL, this may vectorize - add print statement to prevent - // Also, compare against epsilon, as vectorization can change bitwise answer - for ( long l = 0; l < static_cast(icount); ++l ) { - for ( long j = 0; j < static_cast(jcount); ++j ) { - for ( long k = 0; k < static_cast(kcount); ++k ) { - ScalarType check = 0.25*(ScalarType)( Bhost(l+2,j,k) + Bhost(l+1,j,k) - + Bhost(l,j+2,k) + Bhost(l,j+1,k) - + Bhost(l,j,k+2) + Bhost(l,j,k+1) - + Bhost(l,j,k) ); - if ( Ahost(l,j,k) - check != 0 ) { - ++numErrors; - std::cout << " Correctness error at index: " << l << ","<(icount); ++l) { + for (long j = 0; j < static_cast(jcount); ++j) { + for (long k = 0; k < static_cast(kcount); ++k) { + ScalarType check = + 0.25 * + (ScalarType)(Bhost(l + 2, j, k) + Bhost(l + 1, j, k) + + Bhost(l, j + 2, k) + Bhost(l, j + 1, k) + + Bhost(l, j, k + 2) + Bhost(l, j, k + 1) + + Bhost(l, j, k)); + if (Ahost(l, j, k) - check != 0) { + ++numErrors; + std::cout << " Correctness error at index: " << l << "," << j + << "," << k << "\n" + << " multi Ahost = " << Ahost(l, j, k) + << " expected = " << check + << " multi Bhost(ijk) = " << Bhost(l, j, k) + << " multi Bhost(l+1jk) = " << Bhost(l + 1, j, k) + << " multi Bhost(l+2jk) = " << Bhost(l + 2, j, k) + << " multi Bhost(ij+1k) = " << Bhost(l, j + 1, k) + << " multi Bhost(ij+2k) = " << Bhost(l, j + 2, k) + << " multi Bhost(ijk+1) = " << Bhost(l, j, k + 1) + << " multi Bhost(ijk+2) = " << Bhost(l, j, k + 2) + << std::endl; + // exit(-1); + } + } + } } - } } } - if ( numErrors != 0 ) { std::cout << "LR multi: errors " << numErrors << " range product " << icount*jcount*kcount << " LL " << jcount*kcount << " LR " << icount*jcount << std::endl; } - //else { std::cout << " multi: No errors!" << std::endl; } - } - } //end for + if (numErrors != 0) { + std::cout << "LR multi: errors " << numErrors << " range product " + << icount * jcount * kcount << " LL " << jcount * kcount + << " LR " << icount * jcount << std::endl; + } + // else { std::cout << " multi: No errors!" << std::endl; } + } + } // end for - } + } // LayoutLeft else { - Kokkos::MDRangePolicy, execution_space > policy_initA({{0,0,0}},{{icount,jcount,kcount}},{{Ti,Tj,Tk}}); - Kokkos::MDRangePolicy, execution_space > policy_initB({{0,0,0}},{{icount+2,jcount+2,kcount+2}},{{Ti,Tj,Tk}}); - - //typedef typename Kokkos::MDRangePolicy, execution_space > MDRangeType; - //using tile_type = typename MDRangeType::tile_type; - //using point_type = typename MDRangeType::point_type; - //Kokkos::MDRangePolicy, execution_space > policy(point_type{{0,0,0}},point_type{{icount,jcount,kcount}},tile_type{{Ti,Tj,Tk}} ); - Kokkos::MDRangePolicy, execution_space > policy({{0,0,0}},{{icount,jcount,kcount}},{{Ti,Tj,Tk}} ); - - Kokkos::parallel_for( policy_initA, Init(Atest, icount, jcount, kcount) ); + Kokkos::MDRangePolicy< + Kokkos::Rank<3, iterate_type::Left, iterate_type::Left>, + execution_space> + policy_initA({{0, 0, 0}}, {{icount, jcount, kcount}}, {{Ti, Tj, Tk}}); + Kokkos::MDRangePolicy< + Kokkos::Rank<3, iterate_type::Left, iterate_type::Left>, + execution_space> + policy_initB({{0, 0, 0}}, {{icount + 2, jcount + 2, kcount + 2}}, + {{Ti, Tj, Tk}}); + + // typedef typename Kokkos::MDRangePolicy, execution_space > MDRangeType; + // using tile_type = typename MDRangeType::tile_type; + // using point_type = typename MDRangeType::point_type; + // Kokkos::MDRangePolicy, execution_space > + // policy(point_type{{0,0,0}},point_type{{icount,jcount,kcount}},tile_type{{Ti,Tj,Tk}} + // ); + Kokkos::MDRangePolicy< + Kokkos::Rank<3, iterate_type::Left, iterate_type::Left>, + execution_space> + policy({{0, 0, 0}}, {{icount, jcount, kcount}}, {{Ti, Tj, Tk}}); + + Kokkos::parallel_for(policy_initA, Init(Atest, icount, jcount, kcount)); execution_space().fence(); - Kokkos::parallel_for( policy_initB, Init(Btest, icount+2, jcount+2, kcount+2) ); + Kokkos::parallel_for(policy_initB, + Init(Btest, icount + 2, jcount + 2, kcount + 2)); execution_space().fence(); - for (int i = 0; i < iter; ++i) - { - Kokkos::Timer timer; - Kokkos::parallel_for( policy, FunctorType(Atest, Btest, icount, jcount, kcount) ); - execution_space().fence(); - const double dt = timer.seconds(); - if ( 0 == i ) dt_min = dt ; - else dt_min = dt < dt_min ? dt : dt_min ; - - //Correctness check - only the first run - if ( 0 == i ) - { - long numErrors = 0; - host_view_type Ahost("Ahost", icount, jcount, kcount); - Kokkos::deep_copy(Ahost, Atest); - host_view_type Bhost("Bhost", icount+2, jcount+2, kcount+2); - Kokkos::deep_copy(Bhost, Btest); - - // On KNL, this may vectorize - add print statement to prevent - // Also, compare against epsilon, as vectorization can change bitwise answer - for ( long l = 0; l < static_cast(icount); ++l ) { - for ( long j = 0; j < static_cast(jcount); ++j ) { - for ( long k = 0; k < static_cast(kcount); ++k ) { - ScalarType check = 0.25*(ScalarType)( Bhost(l+2,j,k) + Bhost(l+1,j,k) - + Bhost(l,j+2,k) + Bhost(l,j+1,k) - + Bhost(l,j,k+2) + Bhost(l,j,k+1) - + Bhost(l,j,k) ); - if ( Ahost(l,j,k) - check != 0 ) { - ++numErrors; - std::cout << " Correctness error at index: " << l << ","<(icount); ++l) { + for (long j = 0; j < static_cast(jcount); ++j) { + for (long k = 0; k < static_cast(kcount); ++k) { + ScalarType check = + 0.25 * + (ScalarType)(Bhost(l + 2, j, k) + Bhost(l + 1, j, k) + + Bhost(l, j + 2, k) + Bhost(l, j + 1, k) + + Bhost(l, j, k + 2) + Bhost(l, j, k + 1) + + Bhost(l, j, k)); + if (Ahost(l, j, k) - check != 0) { + ++numErrors; + std::cout << " Correctness error at index: " << l << "," << j + << "," << k << "\n" + << " multi Ahost = " << Ahost(l, j, k) + << " expected = " << check + << " multi Bhost(ijk) = " << Bhost(l, j, k) + << " multi Bhost(l+1jk) = " << Bhost(l + 1, j, k) + << " multi Bhost(l+2jk) = " << Bhost(l + 2, j, k) + << " multi Bhost(ij+1k) = " << Bhost(l, j + 1, k) + << " multi Bhost(ij+2k) = " << Bhost(l, j + 2, k) + << " multi Bhost(ijk+1) = " << Bhost(l, j, k + 1) + << " multi Bhost(ijk+2) = " << Bhost(l, j, k + 2) + << std::endl; + // exit(-1); + } + } + } } - } } } - if ( numErrors != 0 ) { std::cout << " LL multi run: errors " << numErrors << " range product " << icount*jcount*kcount << " LL " << jcount*kcount << " LR " << icount*jcount << std::endl; } - //else { std::cout << " multi: No errors!" << std::endl; } - - } - } //end for + if (numErrors != 0) { + std::cout << " LL multi run: errors " << numErrors + << " range product " << icount * jcount * kcount + << " LL " << jcount * kcount << " LR " + << icount * jcount << std::endl; + } + // else { std::cout << " multi: No errors!" << std::endl; } + } + } // end for } return dt_min; - } - + } }; - -template< class DeviceType - , typename ScalarType = double - , typename TestLayout = Kokkos::LayoutRight - > -struct RangePolicyCollapseTwo -{ - // RangePolicy for 3D range, but will collapse only 2 dims => like Rank<2> for multi-dim; unroll 2 dims in one-dim +template +struct RangePolicyCollapseTwo { + // RangePolicy for 3D range, but will collapse only 2 dims => like Rank<2> for + // multi-dim; unroll 2 dims in one-dim typedef DeviceType execution_space; - typedef typename execution_space::size_type size_type; + typedef typename execution_space::size_type size_type; typedef TestLayout layout; using iterate_type = Kokkos::Iterate; - typedef Kokkos::View view_type; + typedef Kokkos::View view_type; typedef typename view_type::HostMirror host_view_type; view_type A; @@ -271,165 +321,170 @@ struct RangePolicyCollapseTwo const long jrange; const long krange; - RangePolicyCollapseTwo(view_type & A_, const view_type & B_, const long &irange_, const long &jrange_, const long &krange_) - : A(A_), B(B_) , irange(irange_), jrange(jrange_), krange(krange_) - {} + RangePolicyCollapseTwo(view_type &A_, const view_type &B_, + const long &irange_, const long &jrange_, + const long &krange_) + : A(A_), B(B_), irange(irange_), jrange(jrange_), krange(krange_) {} KOKKOS_INLINE_FUNCTION - void operator()(const long r) const - { - if ( std::is_same::value ) - { -//id(i,j,k) = k + j*Nk + i*Nk*Nj = k + Nk*(j + i*Nj) = k + Nk*r -//r = j + i*Nj - long i = int(r / jrange); - long j = int( r - i*jrange); + void operator()(const long r) const { + if (std::is_same::value) { + // id(i,j,k) = k + j*Nk + i*Nk*Nj = k + Nk*(j + i*Nj) = k + Nk*r + // r = j + i*Nj + long i = int(r / jrange); + long j = int(r - i * jrange); for (int k = 0; k < krange; ++k) { - A(i,j,k) = 0.25*(ScalarType)( B(i+2,j,k) + B(i+1,j,k) - + B(i,j+2,k) + B(i,j+1,k) - + B(i,j,k+2) + B(i,j,k+1) - + B(i,j,k) ); + A(i, j, k) = + 0.25 * (ScalarType)(B(i + 2, j, k) + B(i + 1, j, k) + + B(i, j + 2, k) + B(i, j + 1, k) + + B(i, j, k + 2) + B(i, j, k + 1) + B(i, j, k)); } - } - else if ( std::is_same::value ) - { -//id(i,j,k) = i + j*Ni + k*Ni*Nj = i + Ni*(j + k*Nj) = i + Ni*r -//r = j + k*Nj - long k = int(r / jrange); - long j = int( r - k*jrange); + } else if (std::is_same::value) { + // id(i,j,k) = i + j*Ni + k*Ni*Nj = i + Ni*(j + k*Nj) = i + Ni*r + // r = j + k*Nj + long k = int(r / jrange); + long j = int(r - k * jrange); for (int i = 0; i < irange; ++i) { - A(i,j,k) = 0.25*(ScalarType)( B(i+2,j,k) + B(i+1,j,k) - + B(i,j+2,k) + B(i,j+1,k) - + B(i,j,k+2) + B(i,j,k+1) - + B(i,j,k) ); + A(i, j, k) = + 0.25 * (ScalarType)(B(i + 2, j, k) + B(i + 1, j, k) + + B(i, j + 2, k) + B(i, j + 1, k) + + B(i, j, k + 2) + B(i, j, k + 1) + B(i, j, k)); } } } - - struct Init - { + struct Init { view_type input; const long irange; const long jrange; const long krange; - Init(const view_type & input_, const long &irange_, const long &jrange_, const long &krange_) - : input(input_), irange(irange_), jrange(jrange_), krange(krange_) {} + Init(const view_type &input_, const long &irange_, const long &jrange_, + const long &krange_) + : input(input_), irange(irange_), jrange(jrange_), krange(krange_) {} KOKKOS_INLINE_FUNCTION - void operator()(const long r) const - { - if ( std::is_same::value ) - { - long i = int(r / jrange); - long j = int( r - i*jrange); + void operator()(const long r) const { + if (std::is_same::value) { + long i = int(r / jrange); + long j = int(r - i * jrange); for (int k = 0; k < krange; ++k) { - input(i,j,k) = 1; + input(i, j, k) = 1; } - } - else if ( std::is_same::value ) - { - long k = int(r / jrange); - long j = int( r - k*jrange); + } else if (std::is_same::value) { + long k = int(r / jrange); + long j = int(r - k * jrange); for (int i = 0; i < irange; ++i) { - input(i,j,k) = 1; + input(i, j, k) = 1; } } } }; - - static double test_index_collapse_two(const unsigned int icount, const unsigned int jcount, const unsigned int kcount, const long iter = 1) - { + static double test_index_collapse_two(const unsigned int icount, + const unsigned int jcount, + const unsigned int kcount, + const long iter = 1) { // This test refers to collapsing two dims while using the RangePolicy view_type Atest("Atest", icount, jcount, kcount); - view_type Btest("Btest", icount+2, jcount+2, kcount+2); - typedef RangePolicyCollapseTwo FunctorType; + view_type Btest("Btest", icount + 2, jcount + 2, kcount + 2); + typedef RangePolicyCollapseTwo + FunctorType; long collapse_index_rangeA = 0; long collapse_index_rangeB = 0; - if ( std::is_same::value ) { - collapse_index_rangeA = icount*jcount; - collapse_index_rangeB = (icount+2)*(jcount+2); -// std::cout << " LayoutRight " << std::endl; - } else if ( std::is_same::value ) { - collapse_index_rangeA = kcount*jcount; - collapse_index_rangeB = (kcount+2)*(jcount+2); -// std::cout << " LayoutLeft " << std::endl; + if (std::is_same::value) { + collapse_index_rangeA = icount * jcount; + collapse_index_rangeB = (icount + 2) * (jcount + 2); + // std::cout << " LayoutRight " << std::endl; + } else if (std::is_same::value) { + collapse_index_rangeA = kcount * jcount; + collapse_index_rangeB = (kcount + 2) * (jcount + 2); + // std::cout << " LayoutLeft " << std::endl; } else { - std::cout << " LayoutRight or LayoutLeft required - will pass 0 as range instead " << std::endl; + std::cout << " LayoutRight or LayoutLeft required - will pass 0 as " + "range instead " + << std::endl; exit(-1); } - Kokkos::RangePolicy policy(0, (collapse_index_rangeA) ); - Kokkos::RangePolicy policy_initB(0, (collapse_index_rangeB) ); + Kokkos::RangePolicy policy(0, (collapse_index_rangeA)); + Kokkos::RangePolicy policy_initB(0, + (collapse_index_rangeB)); double dt_min = 0; - Kokkos::parallel_for( policy, Init(Atest,icount,jcount,kcount) ); + Kokkos::parallel_for(policy, Init(Atest, icount, jcount, kcount)); execution_space().fence(); - Kokkos::parallel_for( policy_initB, Init(Btest,icount+2,jcount+2,kcount+2) ); + Kokkos::parallel_for(policy_initB, + Init(Btest, icount + 2, jcount + 2, kcount + 2)); execution_space().fence(); - for (int i = 0; i < iter; ++i) - { + for (int i = 0; i < iter; ++i) { Kokkos::Timer timer; - Kokkos::parallel_for(policy, FunctorType(Atest, Btest, icount, jcount, kcount)); + Kokkos::parallel_for(policy, + FunctorType(Atest, Btest, icount, jcount, kcount)); execution_space().fence(); const double dt = timer.seconds(); - if ( 0 == i ) dt_min = dt ; - else dt_min = dt < dt_min ? dt : dt_min ; + if (0 == i) + dt_min = dt; + else + dt_min = dt < dt_min ? dt : dt_min; - //Correctness check - first iteration only - if ( 0 == i ) - { + // Correctness check - first iteration only + if (0 == i) { long numErrors = 0; host_view_type Ahost("Ahost", icount, jcount, kcount); Kokkos::deep_copy(Ahost, Atest); - host_view_type Bhost("Bhost", icount+2, jcount+2, kcount+2); + host_view_type Bhost("Bhost", icount + 2, jcount + 2, kcount + 2); Kokkos::deep_copy(Bhost, Btest); // On KNL, this may vectorize - add print statement to prevent - // Also, compare against epsilon, as vectorization can change bitwise answer - for ( long l = 0; l < static_cast(icount); ++l ) { - for ( long j = 0; j < static_cast(jcount); ++j ) { - for ( long k = 0; k < static_cast(kcount); ++k ) { - ScalarType check = 0.25*(ScalarType)( Bhost(l+2,j,k) + Bhost(l+1,j,k) - + Bhost(l,j+2,k) + Bhost(l,j+1,k) - + Bhost(l,j,k+2) + Bhost(l,j,k+1) - + Bhost(l,j,k) ); - if ( Ahost(l,j,k) - check != 0 ) { - ++numErrors; - std::cout << " Correctness error at index: " << l << ","< -struct RangePolicyCollapseAll -{ +template +struct RangePolicyCollapseAll { // RangePolicy for 3D range, but will collapse all dims typedef DeviceType execution_space; - typedef typename execution_space::size_type size_type; + typedef typename execution_space::size_type size_type; typedef TestLayout layout; - typedef Kokkos::View view_type; + typedef Kokkos::View view_type; typedef typename view_type::HostMirror host_view_type; view_type A; @@ -438,127 +493,134 @@ struct RangePolicyCollapseAll const long jrange; const long krange; - RangePolicyCollapseAll(view_type & A_, const view_type & B_, const long &irange_, const long &jrange_, const long &krange_) - : A(A_), B(B_), irange(irange_), jrange(jrange_), krange(krange_) - {} + RangePolicyCollapseAll(view_type &A_, const view_type &B_, + const long &irange_, const long &jrange_, + const long &krange_) + : A(A_), B(B_), irange(irange_), jrange(jrange_), krange(krange_) {} KOKKOS_INLINE_FUNCTION - void operator()(const long r) const - { - if ( std::is_same::value ) - { - long i = int(r / (jrange*krange)); - long j = int(( r - i*jrange*krange)/krange); - long k = int(r - i*jrange*krange - j*krange); - A(i,j,k) = 0.25*(ScalarType)( B(i+2,j,k) + B(i+1,j,k) - + B(i,j+2,k) + B(i,j+1,k) - + B(i,j,k+2) + B(i,j,k+1) - + B(i,j,k) ); - } - else if ( std::is_same::value ) - { - long k = int(r / (irange*jrange)); - long j = int(( r - k*irange*jrange)/irange); - long i = int(r - k*irange*jrange - j*irange); - A(i,j,k) = 0.25*(ScalarType)( B(i+2,j,k) + B(i+1,j,k) - + B(i,j+2,k) + B(i,j+1,k) - + B(i,j,k+2) + B(i,j,k+1) - + B(i,j,k) ); + void operator()(const long r) const { + if (std::is_same::value) { + long i = int(r / (jrange * krange)); + long j = int((r - i * jrange * krange) / krange); + long k = int(r - i * jrange * krange - j * krange); + A(i, j, k) = + 0.25 * (ScalarType)(B(i + 2, j, k) + B(i + 1, j, k) + B(i, j + 2, k) + + B(i, j + 1, k) + B(i, j, k + 2) + B(i, j, k + 1) + + B(i, j, k)); + } else if (std::is_same::value) { + long k = int(r / (irange * jrange)); + long j = int((r - k * irange * jrange) / irange); + long i = int(r - k * irange * jrange - j * irange); + A(i, j, k) = + 0.25 * (ScalarType)(B(i + 2, j, k) + B(i + 1, j, k) + B(i, j + 2, k) + + B(i, j + 1, k) + B(i, j, k + 2) + B(i, j, k + 1) + + B(i, j, k)); } } - - struct Init - { + struct Init { view_type input; const long irange; const long jrange; const long krange; - Init(const view_type & input_, const long &irange_, const long &jrange_, const long &krange_) - : input(input_), irange(irange_), jrange(jrange_), krange(krange_) {} + Init(const view_type &input_, const long &irange_, const long &jrange_, + const long &krange_) + : input(input_), irange(irange_), jrange(jrange_), krange(krange_) {} KOKKOS_INLINE_FUNCTION - void operator()(const long r) const - { - if ( std::is_same::value ) - { - long i = int(r / (jrange*krange)); - long j = int(( r - i*jrange*krange)/krange); - long k = int(r - i*jrange*krange - j*krange); - input(i,j,k) = 1; - } - else if ( std::is_same::value ) - { - long k = int(r / (irange*jrange)); - long j = int(( r - k*irange*jrange)/irange); - long i = int(r - k*irange*jrange - j*irange); - input(i,j,k) = 1; + void operator()(const long r) const { + if (std::is_same::value) { + long i = int(r / (jrange * krange)); + long j = int((r - i * jrange * krange) / krange); + long k = int(r - i * jrange * krange - j * krange); + input(i, j, k) = 1; + } else if (std::is_same::value) { + long k = int(r / (irange * jrange)); + long j = int((r - k * irange * jrange) / irange); + long i = int(r - k * irange * jrange - j * irange); + input(i, j, k) = 1; } } }; - - static double test_collapse_all(const unsigned int icount, const unsigned int jcount, const unsigned int kcount, const long iter = 1) - { - //This test refers to collapsing all dims using the RangePolicy + static double test_collapse_all(const unsigned int icount, + const unsigned int jcount, + const unsigned int kcount, + const long iter = 1) { + // This test refers to collapsing all dims using the RangePolicy view_type Atest("Atest", icount, jcount, kcount); - view_type Btest("Btest", icount+2, jcount+2, kcount+2); - typedef RangePolicyCollapseAll FunctorType; + view_type Btest("Btest", icount + 2, jcount + 2, kcount + 2); + typedef RangePolicyCollapseAll + FunctorType; - const long flat_index_range = icount*jcount*kcount; - Kokkos::RangePolicy policy(0, flat_index_range ); - Kokkos::RangePolicy policy_initB(0, (icount+2)*(jcount+2)*(kcount+2) ); + const long flat_index_range = icount * jcount * kcount; + Kokkos::RangePolicy policy(0, flat_index_range); + Kokkos::RangePolicy policy_initB( + 0, (icount + 2) * (jcount + 2) * (kcount + 2)); double dt_min = 0; - Kokkos::parallel_for( policy, Init(Atest,icount,jcount,kcount) ); + Kokkos::parallel_for(policy, Init(Atest, icount, jcount, kcount)); execution_space().fence(); - Kokkos::parallel_for( policy_initB, Init(Btest,icount+2,jcount+2,kcount+2) ); + Kokkos::parallel_for(policy_initB, + Init(Btest, icount + 2, jcount + 2, kcount + 2)); execution_space().fence(); - for (int i = 0; i < iter; ++i) - { + for (int i = 0; i < iter; ++i) { Kokkos::Timer timer; - Kokkos::parallel_for(policy, FunctorType(Atest, Btest, icount, jcount, kcount)); + Kokkos::parallel_for(policy, + FunctorType(Atest, Btest, icount, jcount, kcount)); execution_space().fence(); const double dt = timer.seconds(); - if ( 0 == i ) dt_min = dt ; - else dt_min = dt < dt_min ? dt : dt_min ; + if (0 == i) + dt_min = dt; + else + dt_min = dt < dt_min ? dt : dt_min; - //Correctness check - first iteration only - if ( 0 == i ) - { + // Correctness check - first iteration only + if (0 == i) { long numErrors = 0; host_view_type Ahost("Ahost", icount, jcount, kcount); Kokkos::deep_copy(Ahost, Atest); - host_view_type Bhost("Bhost", icount+2, jcount+2, kcount+2); + host_view_type Bhost("Bhost", icount + 2, jcount + 2, kcount + 2); Kokkos::deep_copy(Bhost, Btest); // On KNL, this may vectorize - add print statement to prevent - // Also, compare against epsilon, as vectorization can change bitwise answer - for ( long l = 0; l < static_cast(icount); ++l ) { - for ( long j = 0; j < static_cast(jcount); ++j ) { - for ( long k = 0; k < static_cast(kcount); ++k ) { - ScalarType check = 0.25*(ScalarType)( Bhost(l+2,j,k) + Bhost(l+1,j,k) - + Bhost(l,j+2,k) + Bhost(l,j+1,k) - + Bhost(l,j,k+2) + Bhost(l,j,k+1) - + Bhost(l,j,k) ); - if ( Ahost(l,j,k) - check != 0 ) { - ++numErrors; - std::cout << " Callapse ALL Correctness error at index: " << l << ","<0) - n_args = n; + if (n > 0) n_args = n; return n_args; } const char* command_line_arg(int k, char** input_args = NULL) { static char** args; - if(input_args != NULL) - args = input_args; - if(command_line_num_args() > k) + if (input_args != NULL) args = input_args; + if (command_line_num_args() > k) return args[k]; else return NULL; } -} +} // namespace Test -int main(int argc, char *argv[]) { - ::testing::InitGoogleTest(&argc,argv); - Kokkos::initialize(argc,argv); +int main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + Kokkos::initialize(argc, argv); - (void) Test::command_line_num_args(argc); - (void) Test::command_line_arg(0,argv); + (void)Test::command_line_num_args(argc); + (void)Test::command_line_arg(0, argv); int result = RUN_ALL_TESTS(); diff --git a/lib/kokkos/core/perf_test/PerfTest_Category.hpp b/lib/kokkos/core/perf_test/PerfTest_Category.hpp index 18e309ab12..c2cff22502 100644 --- a/lib/kokkos/core/perf_test/PerfTest_Category.hpp +++ b/lib/kokkos/core/perf_test/PerfTest_Category.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -51,16 +52,7 @@ namespace Test { extern int command_line_num_args(int n = 0); extern const char* command_line_arg(int k, char** input_args = NULL); -class default_exec : public ::testing::Test { -protected: - static void SetUpTestCase() { - } - - static void TearDownTestCase() { - } -}; - -} // namespace Test +} // namespace Test #define TEST_CATEGORY default_exec #define TEST_EXECSPACE Kokkos::DefaultExecutionSpace diff --git a/lib/kokkos/core/perf_test/PerfTest_CustomReduction.cpp b/lib/kokkos/core/perf_test/PerfTest_CustomReduction.cpp index 5c67084c6e..d06851ec9b 100644 --- a/lib/kokkos/core/perf_test/PerfTest_CustomReduction.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_CustomReduction.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,71 +49,90 @@ #ifdef KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA namespace Test { -template +template void custom_reduction_test(int N, int R, int num_trials) { Kokkos::Random_XorShift64_Pool<> rand_pool(183291); - Kokkos::View a("A",N); - Kokkos::fill_random(a,rand_pool,1.0); + Kokkos::View a("A", N); + Kokkos::fill_random(a, rand_pool, 1.0); Scalar max; int team_size = 32; - if ( team_size > Kokkos::DefaultExecutionSpace::concurrency() ) + if (team_size > Kokkos::DefaultExecutionSpace::concurrency()) team_size = Kokkos::DefaultExecutionSpace::concurrency(); // Warm up - Kokkos::parallel_reduce(Kokkos::TeamPolicy<>(N/1024,team_size), KOKKOS_LAMBDA( const Kokkos::TeamPolicy<>::member_type& team, Scalar& lmax) { - Scalar team_max = Scalar(0); - for(int rr = 0; rrlmax) lmax = val; - if((k == 11) && (j==17) && (i==2)) lmax = 11.5; - },Kokkos::Max(t_max)); - if(t_max>thread_max) thread_max = t_max; - },Kokkos::Max(team_max)); - } - if(team_max>lmax) lmax = team_max; - },Kokkos::Max(max)); + Kokkos::parallel_reduce( + Kokkos::TeamPolicy<>(N / 1024, team_size), + KOKKOS_LAMBDA(const Kokkos::TeamPolicy<>::member_type& team, + Scalar& lmax) { + Scalar team_max = Scalar(0); + for (int rr = 0; rr < R; rr++) { + int i = team.league_rank(); + Kokkos::parallel_reduce( + Kokkos::TeamThreadRange(team, 32), + [&](const int& j, Scalar& thread_max) { + Scalar t_max = Scalar(0); + Kokkos::parallel_reduce( + Kokkos::ThreadVectorRange(team, 32), + [&](const int& k, Scalar& max_) { + const Scalar val = a((i * 32 + j) * 32 + k); + if (val > lmax) lmax = val; + if ((k == 11) && (j == 17) && (i == 2)) lmax = 11.5; + }, + Kokkos::Max(t_max)); + if (t_max > thread_max) thread_max = t_max; + }, + Kokkos::Max(team_max)); + } + if (team_max > lmax) lmax = team_max; + }, + Kokkos::Max(max)); // Timing Kokkos::Timer timer; - for(int r = 0; r(N/1024,team_size), KOKKOS_LAMBDA( const Kokkos::TeamPolicy<>::member_type& team, Scalar& lmax) { - Scalar team_max = Scalar(0); - for(int rr = 0; rrlmax) lmax = val; - if((k == 11) && (j==17) && (i==2)) lmax = 11.5; - },Kokkos::Max(t_max)); - if(t_max>thread_max) thread_max = t_max; - },Kokkos::Max(team_max)); - } - if(team_max>lmax) lmax = team_max; - },Kokkos::Max(max)); + for (int r = 0; r < num_trials; r++) { + Kokkos::parallel_reduce( + Kokkos::TeamPolicy<>(N / 1024, team_size), + KOKKOS_LAMBDA(const Kokkos::TeamPolicy<>::member_type& team, + Scalar& lmax) { + Scalar team_max = Scalar(0); + for (int rr = 0; rr < R; rr++) { + int i = team.league_rank(); + Kokkos::parallel_reduce( + Kokkos::TeamThreadRange(team, 32), + [&](const int& j, Scalar& thread_max) { + Scalar t_max = Scalar(0); + Kokkos::parallel_reduce( + Kokkos::ThreadVectorRange(team, 32), + [&](const int& k, Scalar& max_) { + const Scalar val = a((i * 32 + j) * 32 + k); + if (val > lmax) lmax = val; + if ((k == 11) && (j == 17) && (i == 2)) lmax = 11.5; + }, + Kokkos::Max(t_max)); + if (t_max > thread_max) thread_max = t_max; + }, + Kokkos::Max(team_max)); + } + if (team_max > lmax) lmax = team_max; + }, + Kokkos::Max(max)); } double time = timer.seconds(); - printf("%e %e %e\n",time,1.0*N*R*num_trials*sizeof(Scalar)/time/1024/1024/1024,max); + printf("%e %e %e\n", time, + 1.0 * N * R * num_trials * sizeof(Scalar) / time / 1024 / 1024 / 1024, + max); } -TEST_F( default_exec, custom_reduction ) { - int N = 100000; - int R = 1000; +TEST(default_exec, custom_reduction) { + int N = 100000; + int R = 1000; int num_trials = 1; - if(command_line_num_args()>1) - N = atoi(command_line_arg(1)); - if(command_line_num_args()>2) - R = atoi(command_line_arg(2)); - if(command_line_num_args()>3) - num_trials = atoi(command_line_arg(3)); - custom_reduction_test(N,R,num_trials); -} + if (command_line_num_args() > 1) N = atoi(command_line_arg(1)); + if (command_line_num_args() > 2) R = atoi(command_line_arg(2)); + if (command_line_num_args() > 3) num_trials = atoi(command_line_arg(3)); + custom_reduction_test(N, R, num_trials); } +} // namespace Test #endif diff --git a/lib/kokkos/core/perf_test/PerfTest_ExecSpacePartitioning.cpp b/lib/kokkos/core/perf_test/PerfTest_ExecSpacePartitioning.cpp index 2fc889beed..c6d5b2b8d6 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ExecSpacePartitioning.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ExecSpacePartitioning.cpp @@ -2,563 +2,631 @@ #include #include - namespace Test { namespace { - template - struct SpaceInstance { - static ExecSpace create() { - return ExecSpace(); - } - static void destroy(ExecSpace&) { - } - static bool overlap() { - return false; - } - }; - - #ifndef KOKKOS_ENABLE_DEBUG - #ifdef KOKKOS_ENABLE_CUDA - template<> - struct SpaceInstance { - static Kokkos::Cuda create() { - cudaStream_t stream; - cudaStreamCreate(&stream); - return Kokkos::Cuda(stream); - } - static void destroy(Kokkos::Cuda& space) { - cudaStream_t stream = space.cuda_stream(); - cudaStreamDestroy(stream); - } - static bool overlap() { - bool value = true; - auto local_rank_str = std::getenv("CUDA_LAUNCH_BLOCKING"); - if(local_rank_str) { - value = (std::atoi(local_rank_str)==0); - } - return value; +template +struct SpaceInstance { + static ExecSpace create() { return ExecSpace(); } + static void destroy(ExecSpace&) {} + static bool overlap() { return false; } +}; + +#ifndef KOKKOS_ENABLE_DEBUG +#ifdef KOKKOS_ENABLE_CUDA +template <> +struct SpaceInstance { + static Kokkos::Cuda create() { + cudaStream_t stream; + cudaStreamCreate(&stream); + return Kokkos::Cuda(stream); + } + static void destroy(Kokkos::Cuda& space) { + cudaStream_t stream = space.cuda_stream(); + cudaStreamDestroy(stream); + } + static bool overlap() { + bool value = true; + auto local_rank_str = std::getenv("CUDA_LAUNCH_BLOCKING"); + if (local_rank_str) { + value = (std::atoi(local_rank_str) == 0); } - }; - #endif - #endif -} + return value; + } +}; +#endif +#endif +} // namespace struct FunctorRange { - int M,R; - Kokkos::View a; - FunctorRange(int M_, int R_, Kokkos::View a_):M(M_),R(R_),a(a_){} + int M, R; + Kokkos::View a; + FunctorRange(int M_, int R_, Kokkos::View a_) + : M(M_), R(R_), a(a_) {} KOKKOS_INLINE_FUNCTION - void operator() (const int i) const { - for(int r=0;r a; - FunctorMDRange(int M_, int R_, Kokkos::View a_):M(M_),R(R_),a(a_){} + int M, R; + Kokkos::View a; + FunctorMDRange(int M_, int R_, Kokkos::View a_) + : M(M_), R(R_), a(a_) {} KOKKOS_INLINE_FUNCTION - void operator() (const int i, const int) const { - for(int j=0;j a; - FunctorTeam(int M_, int R_, Kokkos::View a_):M(M_),R(R_),a(a_){} + int M, R; + Kokkos::View a; + FunctorTeam(int M_, int R_, + Kokkos::View a_) + : M(M_), R(R_), a(a_) {} KOKKOS_INLINE_FUNCTION - void operator() (const Kokkos::TeamPolicy::member_type& team) const { + void operator()( + const Kokkos::TeamPolicy::member_type& team) const { int i = team.league_rank(); - for(int r=0;r a; - FunctorRangeReduce(int M_, int R_, Kokkos::View a_):M(M_),R(R_),a(a_){} + int M, R; + Kokkos::View a; + FunctorRangeReduce(int M_, int R_, Kokkos::View a_) + : M(M_), R(R_), a(a_) {} KOKKOS_INLINE_FUNCTION - void operator() (const int i, double& tmp) const { - for(int r=0;r a; - FunctorMDRangeReduce(int M_, int R_, Kokkos::View a_):M(M_),R(R_),a(a_){} + int M, R; + Kokkos::View a; + FunctorMDRangeReduce(int M_, int R_, + Kokkos::View a_) + : M(M_), R(R_), a(a_) {} KOKKOS_INLINE_FUNCTION - void operator() (const int i, const int, double& tmp) const { - for(int j=0;j a; - FunctorTeamReduce(int M_, int R_, Kokkos::View a_):M(M_),R(R_),a(a_){} + int M, R; + Kokkos::View a; + FunctorTeamReduce( + int M_, int R_, + Kokkos::View a_) + : M(M_), R(R_), a(a_) {} KOKKOS_INLINE_FUNCTION - void operator() (const Kokkos::TeamPolicy::member_type& team, double& tmp) const { + void operator()(const Kokkos::TeamPolicy::member_type& team, + double& tmp) const { int i = team.league_rank(); - for(int r=0;r::create(); - TEST_EXECSPACE space2 = SpaceInstance::create(); - - Kokkos::View a("A",N,M); - FunctorRange f(M,R,a); - FunctorRangeReduce fr(M,R,a); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel0", - Kokkos::RangePolicy(0,N), FunctorRange(M,R,a)); - - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel1", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space1,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel2", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space2,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::fence(); - - Kokkos::Timer timer; - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel3", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel4", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::fence(); - - timer.reset(); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel5", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space1,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , FunctorRange(M,R,a)); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel6", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space2,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , FunctorRange(M,R,a)); - Kokkos::fence(); - double time_overlap = timer.seconds(); - - timer.reset(); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel7", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel8", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::fence(); - double time_end = timer.seconds(); - - if(SpaceInstance::overlap()) { - ASSERT_TRUE( (time_end > 1.5*time_overlap) ); - } - printf("Time RangePolicy: NonOverlap: %lf Time Overlap: %lf\n",time_end,time_overlap); - - Kokkos::View result("result"); - Kokkos::View result1("result1"); - Kokkos::View result2("result2"); - Kokkos::View h_result("h_result"); - Kokkos::View h_result1("h_result1"); - Kokkos::View h_result2("h_result2"); - - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_range_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); - Kokkos::fence(); - double time_fenced = timer.seconds(); - Kokkos::deep_copy(h_result,result); - - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_range_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); - double time_not_fenced = timer.seconds(); - Kokkos::fence(); - if(SpaceInstance::overlap()) { - ASSERT_TRUE(time_fenced>2.0*time_not_fenced); - } - - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_range_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); - Kokkos::parallel_reduce("default_exec::overlap_range_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); + int M = 10000; + int R = 10; + + TEST_EXECSPACE space; + TEST_EXECSPACE space1 = SpaceInstance::create(); + TEST_EXECSPACE space2 = SpaceInstance::create(); + + Kokkos::View a("A", N, M); + FunctorRange f(M, R, a); + FunctorRangeReduce fr(M, R, a); + Kokkos::parallel_for("default_exec::overlap_range_policy::kernel0", + Kokkos::RangePolicy(0, N), + FunctorRange(M, R, a)); + + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel1", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space1, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel2", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space2, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::fence(); + + Kokkos::Timer timer; + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel3", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel4", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::fence(); + + timer.reset(); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel5", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space1, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + FunctorRange(M, R, a)); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel6", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space2, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + FunctorRange(M, R, a)); + Kokkos::fence(); + double time_overlap = timer.seconds(); + + timer.reset(); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel7", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel8", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::fence(); + double time_end = timer.seconds(); + + if (SpaceInstance::overlap()) { + ASSERT_TRUE((time_end > 1.5 * time_overlap)); + } + printf("Time RangePolicy: NonOverlap: %lf Time Overlap: %lf\n", time_end, + time_overlap); + + Kokkos::View result("result"); + Kokkos::View result1("result1"); + Kokkos::View result2("result2"); + Kokkos::View h_result("h_result"); + Kokkos::View h_result1("h_result1"); + Kokkos::View h_result2("h_result2"); + + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_range_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); + Kokkos::fence(); + double time_fenced = timer.seconds(); + Kokkos::deep_copy(h_result, result); + + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_range_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); + double time_not_fenced = timer.seconds(); + Kokkos::fence(); + if (SpaceInstance::overlap()) { + ASSERT_TRUE(time_fenced > 2.0 * time_not_fenced); + } + + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_range_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); + Kokkos::parallel_reduce( + "default_exec::overlap_range_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); Kokkos::fence(); double time_no_overlapped_reduce = timer.seconds(); - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_range_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space1,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result1); - Kokkos::parallel_reduce("default_exec::overlap_range_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space2,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result2); + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_range_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space1, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result1); + Kokkos::parallel_reduce( + "default_exec::overlap_range_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space2, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result2); Kokkos::fence(); double time_overlapped_reduce = timer.seconds(); - Kokkos::deep_copy(h_result2,result2); - Kokkos::deep_copy(h_result1,result1); + Kokkos::deep_copy(h_result2, result2); + Kokkos::deep_copy(h_result1, result1); - ASSERT_EQ(h_result1(),h_result()); - ASSERT_EQ(h_result2(),h_result()); + ASSERT_EQ(h_result1(), h_result()); + ASSERT_EQ(h_result2(), h_result()); - if(SpaceInstance::overlap()) { - ASSERT_TRUE(time_overlapped_reduce < 1.5*time_no_overlapped_reduce); - } - printf("Time RangePolicy Reduce: NonOverlap: %lf Time Overlap: %lf\n",time_no_overlapped_reduce,time_overlapped_reduce); - SpaceInstance::destroy(space1); - SpaceInstance::destroy(space2); + if (SpaceInstance::overlap()) { + ASSERT_TRUE(time_overlapped_reduce < 1.5 * time_no_overlapped_reduce); + } + printf("Time RangePolicy Reduce: NonOverlap: %lf Time Overlap: %lf\n", + time_no_overlapped_reduce, time_overlapped_reduce); + SpaceInstance::destroy(space1); + SpaceInstance::destroy(space2); } -TEST_F( default_exec, overlap_mdrange_policy ) { - int N = 200; - int M = 10000; - int R = 10; - - TEST_EXECSPACE space; - TEST_EXECSPACE space1 = SpaceInstance::create(); - TEST_EXECSPACE space2 = SpaceInstance::create(); - - Kokkos::View a("A",N,M); - FunctorMDRange f(M,R,a); - FunctorMDRangeReduce fr(M,R,a); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel0", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>({0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , FunctorMDRange(M,R,a)); - - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel1", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space1,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel2", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space2,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::fence(); - - Kokkos::Timer timer; - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel3", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel4", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::fence(); - - timer.reset(); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel5", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space1,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , FunctorMDRange(M,R,a)); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel6", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space2,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , FunctorMDRange(M,R,a)); - Kokkos::fence(); - double time_overlap = timer.seconds(); - - timer.reset(); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel7", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel8", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::fence(); - double time_end = timer.seconds(); - - if(SpaceInstance::overlap()) { - ASSERT_TRUE( (time_end > 1.5*time_overlap) ); - } - printf("Time MDRangePolicy: NonOverlap: %lf Time Overlap: %lf\n",time_end,time_overlap); - - Kokkos::View result("result"); - Kokkos::View result1("result1"); - Kokkos::View result2("result2"); - Kokkos::View h_result("h_result"); - Kokkos::View h_result1("h_result1"); - Kokkos::View h_result2("h_result2"); - - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_mdrange_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); - Kokkos::fence(); - double time_fenced = timer.seconds(); - Kokkos::deep_copy(h_result,result); - - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_mdrange_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); - double time_not_fenced = timer.seconds(); - Kokkos::fence(); - if(SpaceInstance::overlap()) { - ASSERT_TRUE(time_fenced>2.0*time_not_fenced); - } - - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_mdrange_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); - Kokkos::parallel_reduce("default_exec::overlap_mdrange_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); +TEST(default_exec, overlap_mdrange_policy) { + int N = 200; + int M = 10000; + int R = 10; + + TEST_EXECSPACE space; + TEST_EXECSPACE space1 = SpaceInstance::create(); + TEST_EXECSPACE space2 = SpaceInstance::create(); + + Kokkos::View a("A", N, M); + FunctorMDRange f(M, R, a); + FunctorMDRangeReduce fr(M, R, a); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel0", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>({0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + FunctorMDRange(M, R, a)); + + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel1", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space1, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel2", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space2, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::fence(); + + Kokkos::Timer timer; + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel3", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel4", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::fence(); + + timer.reset(); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel5", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space1, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + FunctorMDRange(M, R, a)); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel6", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space2, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + FunctorMDRange(M, R, a)); + Kokkos::fence(); + double time_overlap = timer.seconds(); + + timer.reset(); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel7", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel8", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::fence(); + double time_end = timer.seconds(); + + if (SpaceInstance::overlap()) { + ASSERT_TRUE((time_end > 1.5 * time_overlap)); + } + printf("Time MDRangePolicy: NonOverlap: %lf Time Overlap: %lf\n", time_end, + time_overlap); + + Kokkos::View result("result"); + Kokkos::View result1("result1"); + Kokkos::View result2("result2"); + Kokkos::View h_result("h_result"); + Kokkos::View h_result1("h_result1"); + Kokkos::View h_result2("h_result2"); + + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_mdrange_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); + Kokkos::fence(); + double time_fenced = timer.seconds(); + Kokkos::deep_copy(h_result, result); + + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_mdrange_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); + double time_not_fenced = timer.seconds(); + Kokkos::fence(); + if (SpaceInstance::overlap()) { + ASSERT_TRUE(time_fenced > 2.0 * time_not_fenced); + } + + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_mdrange_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); + Kokkos::parallel_reduce( + "default_exec::overlap_mdrange_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); Kokkos::fence(); double time_no_overlapped_reduce = timer.seconds(); - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_mdrange_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space1,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result1); - Kokkos::parallel_reduce("default_exec::overlap_mdrange_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space2,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result2); + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_mdrange_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space1, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result1); + Kokkos::parallel_reduce( + "default_exec::overlap_mdrange_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space2, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result2); Kokkos::fence(); double time_overlapped_reduce = timer.seconds(); - Kokkos::deep_copy(h_result2,result2); - Kokkos::deep_copy(h_result1,result1); - - ASSERT_EQ(h_result1(),h_result()); - ASSERT_EQ(h_result2(),h_result()); + Kokkos::deep_copy(h_result2, result2); + Kokkos::deep_copy(h_result1, result1); - if(SpaceInstance::overlap()) { - ASSERT_TRUE(time_overlapped_reduce < 1.5*time_no_overlapped_reduce); - } - printf("Time MDRangePolicy Reduce: NonOverlap: %lf Time Overlap: %lf\n",time_no_overlapped_reduce,time_overlapped_reduce); - SpaceInstance::destroy(space2); - SpaceInstance::destroy(space1); + ASSERT_EQ(h_result1(), h_result()); + ASSERT_EQ(h_result2(), h_result()); + if (SpaceInstance::overlap()) { + ASSERT_TRUE(time_overlapped_reduce < 1.5 * time_no_overlapped_reduce); + } + printf("Time MDRangePolicy Reduce: NonOverlap: %lf Time Overlap: %lf\n", + time_no_overlapped_reduce, time_overlapped_reduce); + SpaceInstance::destroy(space2); + SpaceInstance::destroy(space1); } -TEST_F( default_exec, overlap_team_policy ) { +TEST(default_exec, overlap_team_policy) { int N = 20; - int M = 1000000; - int R = 10; - - TEST_EXECSPACE space; - TEST_EXECSPACE space1 = SpaceInstance::create(); - TEST_EXECSPACE space2 = SpaceInstance::create(); - - Kokkos::View a("A",N,M); - FunctorTeam f(M,R,a); - FunctorTeamReduce fr(M,R,a); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel0", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , FunctorTeam(M,R,a)); - - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel1", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space1,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel2", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space2,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::fence(); - - Kokkos::Timer timer; - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel3", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel4", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::fence(); - - timer.reset(); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel5", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space1,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , FunctorTeam(M,R,a)); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel6", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space2,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , FunctorTeam(M,R,a)); - Kokkos::fence(); - double time_overlap = timer.seconds(); - - timer.reset(); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel7", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel8", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::fence(); - double time_end = timer.seconds(); - - if(SpaceInstance::overlap()) { - ASSERT_TRUE( (time_end > 1.5*time_overlap) ); - } - printf("Time TeamPolicy: NonOverlap: %lf Time Overlap: %lf\n",time_end,time_overlap); - - Kokkos::View result("result"); - Kokkos::View result1("result1"); - Kokkos::View result2("result2"); - Kokkos::View h_result("h_result"); - Kokkos::View h_result1("h_result1"); - Kokkos::View h_result2("h_result2"); - - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_team_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); - Kokkos::fence(); - double time_fenced = timer.seconds(); - Kokkos::deep_copy(h_result,result); - - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_team_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); - double time_not_fenced = timer.seconds(); - Kokkos::fence(); - if(SpaceInstance::overlap()) { - ASSERT_TRUE(time_fenced>2.0*time_not_fenced); - } - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_team_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); - Kokkos::parallel_reduce("default_exec::overlap_team_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); + int M = 1000000; + int R = 10; + + TEST_EXECSPACE space; + TEST_EXECSPACE space1 = SpaceInstance::create(); + TEST_EXECSPACE space2 = SpaceInstance::create(); + + Kokkos::View a("A", N, M); + FunctorTeam f(M, R, a); + FunctorTeamReduce fr(M, R, a); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel0", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + FunctorTeam(M, R, a)); + + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel1", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space1, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel2", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space2, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::fence(); + + Kokkos::Timer timer; + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel3", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel4", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::fence(); + + timer.reset(); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel5", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space1, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + FunctorTeam(M, R, a)); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel6", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space2, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + FunctorTeam(M, R, a)); + Kokkos::fence(); + double time_overlap = timer.seconds(); + + timer.reset(); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel7", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel8", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::fence(); + double time_end = timer.seconds(); + + if (SpaceInstance::overlap()) { + ASSERT_TRUE((time_end > 1.5 * time_overlap)); + } + printf("Time TeamPolicy: NonOverlap: %lf Time Overlap: %lf\n", time_end, + time_overlap); + + Kokkos::View result("result"); + Kokkos::View result1("result1"); + Kokkos::View result2("result2"); + Kokkos::View h_result("h_result"); + Kokkos::View h_result1("h_result1"); + Kokkos::View h_result2("h_result2"); + + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_team_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); + Kokkos::fence(); + double time_fenced = timer.seconds(); + Kokkos::deep_copy(h_result, result); + + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_team_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); + double time_not_fenced = timer.seconds(); + Kokkos::fence(); + if (SpaceInstance::overlap()) { + ASSERT_TRUE(time_fenced > 2.0 * time_not_fenced); + } + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_team_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); + Kokkos::parallel_reduce( + "default_exec::overlap_team_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); Kokkos::fence(); double time_no_overlapped_reduce = timer.seconds(); - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_team_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space1,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result1); - Kokkos::parallel_reduce("default_exec::overlap_team_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space2,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result2); + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_team_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space1, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result1); + Kokkos::parallel_reduce( + "default_exec::overlap_team_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space2, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result2); Kokkos::fence(); double time_overlapped_reduce = timer.seconds(); - Kokkos::deep_copy(h_result2,result2); - Kokkos::deep_copy(h_result1,result1); + Kokkos::deep_copy(h_result2, result2); + Kokkos::deep_copy(h_result1, result1); - ASSERT_EQ(h_result1(),h_result()); - ASSERT_EQ(h_result2(),h_result()); + ASSERT_EQ(h_result1(), h_result()); + ASSERT_EQ(h_result2(), h_result()); - if(SpaceInstance::overlap()) { - ASSERT_TRUE(time_overlapped_reduce < 1.5*time_no_overlapped_reduce); - } - printf("Time TeamPolicy Reduce: NonOverlap: %lf Time Overlap: %lf\n",time_no_overlapped_reduce,time_overlapped_reduce); - SpaceInstance::destroy(space1); - SpaceInstance::destroy(space2); -} + if (SpaceInstance::overlap()) { + ASSERT_TRUE(time_overlapped_reduce < 1.5 * time_no_overlapped_reduce); + } + printf("Time TeamPolicy Reduce: NonOverlap: %lf Time Overlap: %lf\n", + time_no_overlapped_reduce, time_overlapped_reduce); + SpaceInstance::destroy(space1); + SpaceInstance::destroy(space2); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewAllocate.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewAllocate.cpp index 685194c150..550316bec9 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewAllocate.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewAllocate.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,102 +49,112 @@ namespace Test { -template +template void run_allocateview_tests(int N, int R) { const int N1 = N; - const int N2 = N*N; - const int N3 = N2*N; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N * N; + const int N3 = N2 * N; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time1,time2,time3,time4,time5,time6,time7,time8,time_raw = 100000.0; + double time1, time2, time3, time4, time5, time6, time7, time8, + time_raw = 100000.0; { Kokkos::Timer timer; - for(int r=0; r a("A1",N8); + for (int r = 0; r < R; r++) { + Kokkos::View a("A1", N8); } - time1 = timer.seconds()/R; + time1 = timer.seconds() / R; } { Kokkos::Timer timer; - for(int r=0; r a("A2",N4,N4); + for (int r = 0; r < R; r++) { + Kokkos::View a("A2", N4, N4); } - time2 = timer.seconds()/R; + time2 = timer.seconds() / R; } { Kokkos::Timer timer; - for(int r=0; r a("A3",N3,N3,N2); + for (int r = 0; r < R; r++) { + Kokkos::View a("A3", N3, N3, N2); } - time3 = timer.seconds()/R; + time3 = timer.seconds() / R; } { Kokkos::Timer timer; - for(int r=0; r a("A4",N2,N2,N2,N2); + for (int r = 0; r < R; r++) { + Kokkos::View a("A4", N2, N2, N2, N2); } - time4 = timer.seconds()/R; + time4 = timer.seconds() / R; } { Kokkos::Timer timer; - for(int r=0; r a("A5",N2,N2,N1,N1,N2); + for (int r = 0; r < R; r++) { + Kokkos::View a("A5", N2, N2, N1, N1, N2); } - time5 = timer.seconds()/R; + time5 = timer.seconds() / R; } { Kokkos::Timer timer; - for(int r=0; r a("A6",N2,N1,N1,N1,N1,N2); + for (int r = 0; r < R; r++) { + Kokkos::View a("A6", N2, N1, N1, N1, N1, N2); } - time6 = timer.seconds()/R; + time6 = timer.seconds() / R; } { Kokkos::Timer timer; - for(int r=0; r a("A7",N2,N1,N1,N1,N1,N1,N1); + for (int r = 0; r < R; r++) { + Kokkos::View a("A7", N2, N1, N1, N1, N1, N1, N1); } - time7 = timer.seconds()/R; + time7 = timer.seconds() / R; } { Kokkos::Timer timer; - for(int r=0; r a("A8",N1,N1,N1,N1,N1,N1,N1,N1); + for (int r = 0; r < R; r++) { + Kokkos::View a("A8", N1, N1, N1, N1, N1, N1, N1, + N1); } - time8 = timer.seconds()/R; + time8 = timer.seconds() / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { Kokkos::Timer timer; - for(int r=0;r(10,1); + run_allocateview_tests(10, 1); printf("Create View Performance for LayoutRight:\n"); - run_allocateview_tests(10,1); + run_allocateview_tests(10, 1); } -} +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy.hpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy.hpp index eff31c69bb..8e7bf25e80 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy.hpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,204 +49,213 @@ namespace Test { -template -double deepcopy_view (ViewTypeA& a, ViewTypeB& b, int repeat){ +template +double deepcopy_view(ViewTypeA& a, ViewTypeB& b, int repeat) { Kokkos::Timer timer; - for(int i=0; i +template void run_deepcopyview_tests123(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N3 = N2*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N3 = N2 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time1,time2,time3,time_raw = 100000.0; + double time1, time2, time3, time_raw = 100000.0; { - Kokkos::View a("A1",N8); - Kokkos::View b("B1",N8); - time1 = deepcopy_view(a,b,R)/R; + Kokkos::View a("A1", N8); + Kokkos::View b("B1", N8); + time1 = deepcopy_view(a, b, R) / R; } { - Kokkos::View a("A2",N4,N4); - Kokkos::View b("B2",N4,N4); - time2 = deepcopy_view(a,b,R)/R; + Kokkos::View a("A2", N4, N4); + Kokkos::View b("B2", N4, N4); + time2 = deepcopy_view(a, b, R) / R; } { - Kokkos::View a("A3",N3,N3,N2); - Kokkos::View b("B3",N3,N3,N2); - time3 = deepcopy_view(a,b,R)/R; + Kokkos::View a("A3", N3, N3, N2); + Kokkos::View b("B3", N3, N3, N2); + time3 = deepcopy_view(a, b, R) / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); - Kokkos::View b("B1",N8); - double* const a_ptr = a.data(); + Kokkos::View a("A1", N8); + Kokkos::View b("B1", N8); + double* const a_ptr = a.data(); const double* const b_ptr = b.data(); Kokkos::Timer timer; - for(int r=0;r +template void run_deepcopyview_tests45(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time4,time5,time_raw = 100000.0; + double time4, time5, time_raw = 100000.0; { - Kokkos::View a("A4",N2,N2,N2,N2); - Kokkos::View b("B4",N2,N2,N2,N2); - time4 = deepcopy_view(a,b,R)/R; + Kokkos::View a("A4", N2, N2, N2, N2); + Kokkos::View b("B4", N2, N2, N2, N2); + time4 = deepcopy_view(a, b, R) / R; } { - Kokkos::View a("A5",N2,N2,N1,N1,N2); - Kokkos::View b("B5",N2,N2,N1,N1,N2); - time5 = deepcopy_view(a,b,R)/R; + Kokkos::View a("A5", N2, N2, N1, N1, N2); + Kokkos::View b("B5", N2, N2, N1, N1, N2); + time5 = deepcopy_view(a, b, R) / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); - Kokkos::View b("B1",N8); - double* const a_ptr = a.data(); + Kokkos::View a("A1", N8); + Kokkos::View b("B1", N8); + double* const a_ptr = a.data(); const double* const b_ptr = b.data(); Kokkos::Timer timer; - for(int r=0;r +template void run_deepcopyview_tests6(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time6,time_raw = 100000.0; + double time6, time_raw = 100000.0; { - Kokkos::View a("A6",N2,N1,N1,N1,N1,N2); - Kokkos::View b("B6",N2,N1,N1,N1,N1,N2); - time6 = deepcopy_view(a,b,R)/R; + Kokkos::View a("A6", N2, N1, N1, N1, N1, N2); + Kokkos::View b("B6", N2, N1, N1, N1, N1, N2); + time6 = deepcopy_view(a, b, R) / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); - Kokkos::View b("B1",N8); - double* const a_ptr = a.data(); + Kokkos::View a("A1", N8); + Kokkos::View b("B1", N8); + double* const a_ptr = a.data(); const double* const b_ptr = b.data(); Kokkos::Timer timer; - for(int r=0;r +template void run_deepcopyview_tests7(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time7,time_raw = 100000.0; + double time7, time_raw = 100000.0; { - Kokkos::View a("A7",N2,N1,N1,N1,N1,N1,N1); - Kokkos::View b("B7",N2,N1,N1,N1,N1,N1,N1); - time7 = deepcopy_view(a,b,R)/R; + Kokkos::View a("A7", N2, N1, N1, N1, N1, N1, N1); + Kokkos::View b("B7", N2, N1, N1, N1, N1, N1, N1); + time7 = deepcopy_view(a, b, R) / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); - Kokkos::View b("B1",N8); - double* const a_ptr = a.data(); + Kokkos::View a("A1", N8); + Kokkos::View b("B1", N8); + double* const a_ptr = a.data(); const double* const b_ptr = b.data(); Kokkos::Timer timer; - for(int r=0;r +template void run_deepcopyview_tests8(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time8,time_raw = 100000.0; + double time8, time_raw = 100000.0; { - Kokkos::View a("A8",N1,N1,N1,N1,N1,N1,N1,N1); - Kokkos::View b("B8",N1,N1,N1,N1,N1,N1,N1,N1); - time8 = deepcopy_view(a,b,R)/R; + Kokkos::View a("A8", N1, N1, N1, N1, N1, N1, N1, + N1); + Kokkos::View b("B8", N1, N1, N1, N1, N1, N1, N1, + N1); + time8 = deepcopy_view(a, b, R) / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); - Kokkos::View b("B1",N8); - double* const a_ptr = a.data(); + Kokkos::View a("A1", N8); + Kokkos::View b("B1", N8); + double* const a_ptr = a.data(); const double* const b_ptr = b.data(); Kokkos::Timer timer; - for(int r=0;r +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_LeftLeft_Rank123 ) { +TEST(default_exec, ViewDeepCopy_LeftLeft_Rank123) { printf("DeepCopy Performance for LayoutLeft to LayoutLeft:\n"); - run_deepcopyview_tests123(10,1); -} + run_deepcopyview_tests123(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a45.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a45.cpp index b7fa71b06f..3f9b694461 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a45.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a45.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_LeftLeft_Rank45 ) { +TEST(default_exec, ViewDeepCopy_LeftLeft_Rank45) { printf("DeepCopy Performance for LayoutLeft to LayoutLeft:\n"); - run_deepcopyview_tests45(10,1); -} + run_deepcopyview_tests45(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a6.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a6.cpp index ee86af41b0..ac364c31cb 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a6.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a6.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_LeftLeft_Rank6 ) { +TEST(default_exec, ViewDeepCopy_LeftLeft_Rank6) { printf("DeepCopy Performance for LayoutLeft to LayoutLeft:\n"); - run_deepcopyview_tests6(10,1); -} + run_deepcopyview_tests6(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a7.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a7.cpp index 5a7a78a196..94f30bac9f 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a7.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a7.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_LeftLeft_Rank7 ) { +TEST(default_exec, ViewDeepCopy_LeftLeft_Rank7) { printf("DeepCopy Performance for LayoutLeft to LayoutLeft:\n"); - run_deepcopyview_tests7(10,1); -} + run_deepcopyview_tests7(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a8.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a8.cpp index cc0d7a6c2a..b916169f1b 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a8.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a8.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_LeftLeft_Rank8 ) { +TEST(default_exec, ViewDeepCopy_LeftLeft_Rank8) { printf("DeepCopy Performance for LayoutLeft to LayoutLeft:\n"); - run_deepcopyview_tests8(10,1); -} + run_deepcopyview_tests8(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b123.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b123.cpp index eb9921d090..f314cb0ff4 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b123.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b123.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_RightRight_Rank123 ) { +TEST(default_exec, ViewDeepCopy_RightRight_Rank123) { printf("DeepCopy Performance for LayoutRight to LayoutRight:\n"); - run_deepcopyview_tests123(10,1); -} + run_deepcopyview_tests123(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b45.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b45.cpp index b805c4c7fc..5d06f060af 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b45.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b45.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_RightRight_Rank45 ) { +TEST(default_exec, ViewDeepCopy_RightRight_Rank45) { printf("DeepCopy Performance for LayoutRight to LayoutRight:\n"); - run_deepcopyview_tests45(10,1); -} + run_deepcopyview_tests45(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b6.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b6.cpp index 8f350f4895..0e28fee631 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b6.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b6.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_RightRight_Rank6 ) { +TEST(default_exec, ViewDeepCopy_RightRight_Rank6) { printf("DeepCopy Performance for LayoutRight to LayoutRight:\n"); - run_deepcopyview_tests6(10,1); -} + run_deepcopyview_tests6(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b7.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b7.cpp index 6f82e178f9..37e1325fc4 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b7.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b7.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_RightRight_Rank7 ) { +TEST(default_exec, ViewDeepCopy_RightRight_Rank7) { printf("DeepCopy Performance for LayoutRight to LayoutRight:\n"); - run_deepcopyview_tests7(10,1); -} + run_deepcopyview_tests7(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b8.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b8.cpp index ef165c9a35..986c39aaf4 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b8.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b8.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_RightRight_Rank8 ) { +TEST(default_exec, ViewDeepCopy_RightRight_Rank8) { printf("DeepCopy Performance for LayoutRight to LayoutRight:\n"); - run_deepcopyview_tests8(10,1); -} + run_deepcopyview_tests8(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c123.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c123.cpp index ebc924d9f0..b98563ee42 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c123.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c123.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_LeftRight_Rank123 ) { +TEST(default_exec, ViewDeepCopy_LeftRight_Rank123) { printf("DeepCopy Performance for LayoutLeft to LayoutRight:\n"); - run_deepcopyview_tests123(10,1); -} + run_deepcopyview_tests123(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c45.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c45.cpp index a8a7935640..a0ef11e09b 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c45.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c45.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_LeftRight_Rank45 ) { +TEST(default_exec, ViewDeepCopy_LeftRight_Rank45) { printf("DeepCopy Performance for LayoutLeft to LayoutRight:\n"); - run_deepcopyview_tests45(10,1); -} + run_deepcopyview_tests45(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c6.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c6.cpp index c65c17c55b..fea5dde73a 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c6.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c6.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_LeftRight_Rank6 ) { +TEST(default_exec, ViewDeepCopy_LeftRight_Rank6) { printf("DeepCopy Performance for LayoutLeft to LayoutRight:\n"); - run_deepcopyview_tests6(10,1); -} + run_deepcopyview_tests6(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c7.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c7.cpp index 48fcf053e6..a8c8d866f9 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c7.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c7.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_LeftRight_Rank7 ) { +TEST(default_exec, ViewDeepCopy_LeftRight_Rank7) { printf("DeepCopy Performance for LayoutLeft to LayoutRight:\n"); - run_deepcopyview_tests7(10,1); -} + run_deepcopyview_tests7(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c8.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c8.cpp index 46e5798c8f..e5abdaa5d8 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c8.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c8.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_LeftRight_Rank8 ) { +TEST(default_exec, ViewDeepCopy_LeftRight_Rank8) { printf("DeepCopy Performance for LayoutLeft to LayoutRight:\n"); - run_deepcopyview_tests8(10,1); -} + run_deepcopyview_tests8(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d123.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d123.cpp index ad0f455cfc..2b58f8dd1f 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d123.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d123.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_RightLeft_Rank123 ) { +TEST(default_exec, ViewDeepCopy_RightLeft_Rank123) { printf("DeepCopy Performance for LayoutRight to LayoutLeft:\n"); - run_deepcopyview_tests123(10,1); -} + run_deepcopyview_tests123(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d45.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d45.cpp index 4853e343dd..fe34e4fd1a 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d45.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d45.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_RightLeft_Rank45 ) { +TEST(default_exec, ViewDeepCopy_RightLeft_Rank45) { printf("DeepCopy Performance for LayoutRight to LayoutLeft:\n"); - run_deepcopyview_tests45(10,1); -} + run_deepcopyview_tests45(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d6.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d6.cpp index 1ce1041458..115b223e68 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d6.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d6.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_RightLeft_Rank6 ) { +TEST(default_exec, ViewDeepCopy_RightLeft_Rank6) { printf("DeepCopy Performance for LayoutRight to LayoutLeft:\n"); - run_deepcopyview_tests6(10,1); -} + run_deepcopyview_tests6(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d7.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d7.cpp index af73733e64..51e88795e7 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d7.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d7.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_RightLeft_Rank7 ) { +TEST(default_exec, ViewDeepCopy_RightLeft_Rank7) { printf("DeepCopy Performance for LayoutRight to LayoutLeft:\n"); - run_deepcopyview_tests7(10,1); -} + run_deepcopyview_tests7(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d8.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d8.cpp index 3c9b9934cb..2a53cdef21 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d8.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d8.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_RightLeft_Rank8 ) { +TEST(default_exec, ViewDeepCopy_RightLeft_Rank8) { printf("DeepCopy Performance for LayoutRight to LayoutLeft:\n"); - run_deepcopyview_tests8(10,1); -} + run_deepcopyview_tests8(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewFill.hpp b/lib/kokkos/core/perf_test/PerfTest_ViewFill.hpp index b17356f0c8..38be4bb212 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewFill.hpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewFill.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,186 +49,195 @@ namespace Test { -template -double fill_view (ViewType& a, typename ViewType::const_value_type& val, int repeat){ +template +double fill_view(ViewType& a, typename ViewType::const_value_type& val, + int repeat) { Kokkos::Timer timer; - for(int i=0; i +template void run_fillview_tests123(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N3 = N2*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N3 = N2 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time1,time2,time3,time_raw = 100000.0; + double time1, time2, time3, time_raw = 100000.0; { - Kokkos::View a("A1",N8); - time1 = fill_view(a,1.1,R)/R; + Kokkos::View a("A1", N8); + time1 = fill_view(a, 1.1, R) / R; } { - Kokkos::View a("A2",N4,N4); - time2 = fill_view(a,1.1,R)/R; + Kokkos::View a("A2", N4, N4); + time2 = fill_view(a, 1.1, R) / R; } { - Kokkos::View a("A3",N3,N3,N2); - time3 = fill_view(a,1.1,R)/R; + Kokkos::View a("A3", N3, N3, N2); + time3 = fill_view(a, 1.1, R) / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); + Kokkos::View a("A1", N8); double* a_ptr = a.data(); Kokkos::Timer timer; - for(int r=0;r +template void run_fillview_tests45(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time4,time5,time_raw = 100000.0; + double time4, time5, time_raw = 100000.0; { - Kokkos::View a("A4",N2,N2,N2,N2); - time4 = fill_view(a,1.1,R)/R; + Kokkos::View a("A4", N2, N2, N2, N2); + time4 = fill_view(a, 1.1, R) / R; } { - Kokkos::View a("A5",N2,N2,N1,N1,N2); - time5 = fill_view(a,1.1,R)/R; + Kokkos::View a("A5", N2, N2, N1, N1, N2); + time5 = fill_view(a, 1.1, R) / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); + Kokkos::View a("A1", N8); double* a_ptr = a.data(); Kokkos::Timer timer; - for(int r=0;r +template void run_fillview_tests6(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time6,time_raw = 100000.0; + double time6, time_raw = 100000.0; { - Kokkos::View a("A6",N2,N1,N1,N1,N1,N2); - time6 = fill_view(a,1.1,R)/R; + Kokkos::View a("A6", N2, N1, N1, N1, N1, N2); + time6 = fill_view(a, 1.1, R) / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); + Kokkos::View a("A1", N8); double* a_ptr = a.data(); Kokkos::Timer timer; - for(int r=0;r +template void run_fillview_tests7(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time7,time_raw = 100000.0; + double time7, time_raw = 100000.0; { - Kokkos::View a("A7",N2,N1,N1,N1,N1,N1,N1); - time7 = fill_view(a,1.1,R)/R; + Kokkos::View a("A7", N2, N1, N1, N1, N1, N1, N1); + time7 = fill_view(a, 1.1, R) / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); + Kokkos::View a("A1", N8); double* a_ptr = a.data(); Kokkos::Timer timer; - for(int r=0;r +template void run_fillview_tests8(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time8,time_raw = 100000.0; + double time8, time_raw = 100000.0; { - Kokkos::View a("A8",N1,N1,N1,N1,N1,N1,N1,N1); - time8 = fill_view(a,1.1,R)/R; + Kokkos::View a("A8", N1, N1, N1, N1, N1, N1, N1, + N1); + time8 = fill_view(a, 1.1, R) / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); + Kokkos::View a("A1", N8); double* a_ptr = a.data(); Kokkos::Timer timer; - for(int r=0;r namespace Test { -TEST_F( default_exec, ViewFill_Rank123 ) { +TEST(default_exec, ViewFill_Rank123) { printf("ViewFill Performance for LayoutLeft:\n"); - run_fillview_tests123(10,1); + run_fillview_tests123(10, 1); printf("ViewFill Performance for LayoutRight:\n"); - run_fillview_tests123(10,1); -} + run_fillview_tests123(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewFill_45.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewFill_45.cpp index e1d1b6900d..53ac509da8 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewFill_45.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewFill_45.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,10 +45,10 @@ #include namespace Test { -TEST_F( default_exec, ViewFill_Rank45 ) { +TEST(default_exec, ViewFill_Rank45) { printf("ViewFill Performance for LayoutLeft:\n"); - run_fillview_tests45(10,1); + run_fillview_tests45(10, 1); printf("ViewFill Performance for LayoutRight:\n"); - run_fillview_tests45(10,1); -} + run_fillview_tests45(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewFill_6.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewFill_6.cpp index 571867937e..f0a2e248f2 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewFill_6.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewFill_6.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,10 +45,10 @@ #include namespace Test { -TEST_F( default_exec, ViewFill_Rank6 ) { +TEST(default_exec, ViewFill_Rank6) { printf("ViewFill Performance for LayoutLeft:\n"); - run_fillview_tests6(10,1); + run_fillview_tests6(10, 1); printf("ViewFill Performance for LayoutRight:\n"); - run_fillview_tests6(10,1); -} + run_fillview_tests6(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewFill_7.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewFill_7.cpp index 9b89c8fc7b..675d9e636f 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewFill_7.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewFill_7.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,10 +45,10 @@ #include namespace Test { -TEST_F( default_exec, ViewFill_Rank7 ) { +TEST(default_exec, ViewFill_Rank7) { printf("ViewFill Performance for LayoutLeft:\n"); - run_fillview_tests7(10,1); + run_fillview_tests7(10, 1); printf("ViewFill Performance for LayoutRight:\n"); - run_fillview_tests7(10,1); -} + run_fillview_tests7(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewFill_8.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewFill_8.cpp index 4d3df50354..35e1e81c43 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewFill_8.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewFill_8.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,10 +45,10 @@ #include namespace Test { -TEST_F( default_exec, ViewFill_Rank8 ) { +TEST(default_exec, ViewFill_Rank8) { printf("ViewFill Performance for LayoutLeft:\n"); - run_fillview_tests8(10,1); + run_fillview_tests8(10, 1); printf("ViewFill Performance for LayoutRight:\n"); - run_fillview_tests8(10,1); -} + run_fillview_tests8(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewResize.hpp b/lib/kokkos/core/perf_test/PerfTest_ViewResize.hpp index b5019b467a..2ea81b5046 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewResize.hpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewResize.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,230 +49,340 @@ namespace Test { -template +template void run_resizeview_tests123(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N3 = N2*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N3 = N2 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time1,time2,time3,time_raw = 100000.0; + double time1, time2, time3, time_raw = 100000.0; + double time1_noinit, time2_noinit, time3_noinit; { - Kokkos::View a("A1",N8); + Kokkos::View a("A1", N8); Kokkos::Timer timer; - for(int r=0; r a_(a); - Kokkos::resize(a_,int(N8*1.1)); + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(a_, int(N8 * 1.1)); } - time1 = timer.seconds()/R; + time1 = timer.seconds() / R; } { - Kokkos::View a("A2",N4,N4); + Kokkos::View a("A2", N4, N4); Kokkos::Timer timer; - for(int r=0; r a_(a); - Kokkos::resize(a_,int(N4*1.1),N4); + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(a_, int(N4 * 1.1), N4); } - time2 = timer.seconds()/R; + time2 = timer.seconds() / R; } { - Kokkos::View a("A3",N3,N3,N2); + Kokkos::View a("A3", N3, N3, N2); Kokkos::Timer timer; - for(int r=0; r a_(a); - Kokkos::resize(a_,int(N3*1.1),N3,N2); + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(a_, int(N3 * 1.1), N3, N2); } - time3 = timer.seconds()/R; + time3 = timer.seconds() / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); + Kokkos::View a("A1", N8); + Kokkos::Timer timer; + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(Kokkos::WithoutInitializing, a_, int(N8 * 1.1)); + } + time1_noinit = timer.seconds() / R; + } + { + Kokkos::View a("A2", N4, N4); + Kokkos::Timer timer; + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(Kokkos::WithoutInitializing, a_, int(N4 * 1.1), N4); + } + time2_noinit = timer.seconds() / R; + } + { + Kokkos::View a("A3", N3, N3, N2); + Kokkos::Timer timer; + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(Kokkos::WithoutInitializing, a_, int(N3 * 1.1), N3, N2); + } + time3_noinit = timer.seconds() / R; + } +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) + { + Kokkos::View a("A1", N8); double* a_ptr = a.data(); Kokkos::Timer timer; - for(int r=0;r a1(Kokkos::ViewAllocateWithoutInitializing("A1"),int(N8*1.1)); + for (int r = 0; r < R; r++) { + Kokkos::View a1( + Kokkos::ViewAllocateWithoutInitializing("A1"), int(N8 * 1.1)); double* a1_ptr = a1.data(); - Kokkos::parallel_for(N8, KOKKOS_LAMBDA (const int& i) { - a1_ptr[i] = a_ptr[i]; - }); + Kokkos::parallel_for( + N8, KOKKOS_LAMBDA(const int& i) { a1_ptr[i] = a_ptr[i]; }); Kokkos::fence(); } Kokkos::fence(); - time_raw = timer.seconds()/R; + time_raw = timer.seconds() / R; } - #endif - double size = 1.0*N8*8/1024/1024; - printf(" Raw: %lf s %lf MB %lf GB/s\n",time_raw,size,2.0*size/1024/time_raw); - printf(" Rank1: %lf s %lf MB %lf GB/s\n",time1,size,2.0*size/1024/time1); - printf(" Rank2: %lf s %lf MB %lf GB/s\n",time2,size,2.0*size/1024/time2); - printf(" Rank3: %lf s %lf MB %lf GB/s\n",time3,size,2.0*size/1024/time3); +#endif + double size = 1.0 * N8 * 8 / 1024 / 1024; + printf(" Raw: %lf s %lf MB %lf GB/s\n", time_raw, size, + 2.0 * size / 1024 / time_raw); + printf(" Rank1: %lf s %lf MB %lf GB/s\n", time1, size, + 2.0 * size / 1024 / time1); + printf(" Rank2: %lf s %lf MB %lf GB/s\n", time2, size, + 2.0 * size / 1024 / time2); + printf(" Rank3: %lf s %lf MB %lf GB/s\n", time3, size, + 2.0 * size / 1024 / time3); + printf(" Rank1 (WithoutInitializing): %lf s %lf MB %lf GB/s\n", + time1_noinit, size, 2.0 * size / 1024 / time1_noinit); + printf(" Rank2 (WithoutInitializing): %lf s %lf MB %lf GB/s\n", + time2_noinit, size, 2.0 * size / 1024 / time2_noinit); + printf(" Rank3 (WithoutInitializing): %lf s %lf MB %lf GB/s\n", + time3_noinit, size, 2.0 * size / 1024 / time3_noinit); } -template +template void run_resizeview_tests45(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time4,time5,time_raw = 100000.0; + double time4, time5, time_raw = 100000.0; + double time4_noinit, time5_noinit; + { + Kokkos::View a("A4", N2, N2, N2, N2); + Kokkos::Timer timer; + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(a_, int(N2 * 1.1), N2, N2, N2); + } + time4 = timer.seconds() / R; + } { - Kokkos::View a("A4",N2,N2,N2,N2); + Kokkos::View a("A5", N2, N2, N1, N1, N2); Kokkos::Timer timer; - for(int r=0; r a_(a); - Kokkos::resize(a_,int(N2*1.1),N2,N2,N2); + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(a_, int(N2 * 1.1), N2, N1, N1, N2); } - time4 = timer.seconds()/R; + time5 = timer.seconds() / R; } { - Kokkos::View a("A5",N2,N2,N1,N1,N2); + Kokkos::View a("A4", N2, N2, N2, N2); Kokkos::Timer timer; - for(int r=0; r a_(a); - Kokkos::resize(a_,int(N2*1.1),N2,N1,N1,N2); + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(Kokkos::WithoutInitializing, a_, int(N2 * 1.1), N2, N2, + N2); } - time5 = timer.seconds()/R; + time4_noinit = timer.seconds() / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); + Kokkos::View a("A5", N2, N2, N1, N1, N2); + Kokkos::Timer timer; + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(Kokkos::WithoutInitializing, a_, int(N2 * 1.1), N2, N1, N1, + N2); + } + time5_noinit = timer.seconds() / R; + } +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) + { + Kokkos::View a("A1", N8); double* a_ptr = a.data(); Kokkos::Timer timer; - for(int r=0;r a1(Kokkos::ViewAllocateWithoutInitializing("A1"),int(N8*1.1)); + for (int r = 0; r < R; r++) { + Kokkos::View a1( + Kokkos::ViewAllocateWithoutInitializing("A1"), int(N8 * 1.1)); double* a1_ptr = a1.data(); - Kokkos::parallel_for(N8, KOKKOS_LAMBDA (const int& i) { - a1_ptr[i] = a_ptr[i]; - }); + Kokkos::parallel_for( + N8, KOKKOS_LAMBDA(const int& i) { a1_ptr[i] = a_ptr[i]; }); Kokkos::fence(); } Kokkos::fence(); - time_raw = timer.seconds()/R; + time_raw = timer.seconds() / R; } - #endif - double size = 1.0*N8*8/1024/1024; - printf(" Raw: %lf s %lf MB %lf GB/s\n",time_raw,size,2.0*size/1024/time_raw); - printf(" Rank4: %lf s %lf MB %lf GB/s\n",time4,size,2.0*size/1024/time4); - printf(" Rank5: %lf s %lf MB %lf GB/s\n",time5,size,2.0*size/1024/time5); +#endif + double size = 1.0 * N8 * 8 / 1024 / 1024; + printf(" Raw: %lf s %lf MB %lf GB/s\n", time_raw, size, + 2.0 * size / 1024 / time_raw); + printf(" Rank4: %lf s %lf MB %lf GB/s\n", time4, size, + 2.0 * size / 1024 / time4); + printf(" Rank5: %lf s %lf MB %lf GB/s\n", time5, size, + 2.0 * size / 1024 / time5); + printf(" Rank4 (WithoutInitializing): %lf s %lf MB %lf GB/s\n", + time4_noinit, size, 2.0 * size / 1024 / time4_noinit); + printf(" Rank5 (WithoutInitializing): %lf s %lf MB %lf GB/s\n", + time5_noinit, size, 2.0 * size / 1024 / time5_noinit); } -template +template void run_resizeview_tests6(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time6,time_raw = 100000.0; + double time6, time6_noinit, time_raw = 100000.0; + { + Kokkos::View a("A6", N2, N1, N1, N1, N1, N2); + Kokkos::Timer timer; + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(a_, int(N2 * 1.1), N1, N1, N1, N1, N2); + } + time6 = timer.seconds() / R; + } { - Kokkos::View a("A6",N2,N1,N1,N1,N1,N2); + Kokkos::View a("A6", N2, N1, N1, N1, N1, N2); Kokkos::Timer timer; - for(int r=0; r a_(a); - Kokkos::resize(a_,int(N2*1.1),N1,N1,N1,N1,N2); + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(Kokkos::WithoutInitializing, a_, int(N2 * 1.1), N1, N1, N1, + N1, N2); } - time6 = timer.seconds()/R; + time6_noinit = timer.seconds() / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); + Kokkos::View a("A1", N8); double* a_ptr = a.data(); Kokkos::Timer timer; - for(int r=0;r a1(Kokkos::ViewAllocateWithoutInitializing("A1"),int(N8*1.1)); + for (int r = 0; r < R; r++) { + Kokkos::View a1( + Kokkos::ViewAllocateWithoutInitializing("A1"), int(N8 * 1.1)); double* a1_ptr = a1.data(); - Kokkos::parallel_for(N8, KOKKOS_LAMBDA (const int& i) { - a1_ptr[i] = a_ptr[i]; - }); + Kokkos::parallel_for( + N8, KOKKOS_LAMBDA(const int& i) { a1_ptr[i] = a_ptr[i]; }); Kokkos::fence(); } Kokkos::fence(); - time_raw = timer.seconds()/R; + time_raw = timer.seconds() / R; } - #endif - double size = 1.0*N8*8/1024/1024; - printf(" Raw: %lf s %lf MB %lf GB/s\n",time_raw,size,2.0*size/1024/time_raw); - printf(" Rank6: %lf s %lf MB %lf GB/s\n",time6,size,2.0*size/1024/time6); +#endif + double size = 1.0 * N8 * 8 / 1024 / 1024; + printf(" Raw: %lf s %lf MB %lf GB/s\n", time_raw, size, + 2.0 * size / 1024 / time_raw); + printf(" Rank6: %lf s %lf MB %lf GB/s\n", time6, size, + 2.0 * size / 1024 / time6); + printf(" Rank6 (WithoutInitializing): %lf s %lf MB %lf GB/s\n", + time6_noinit, size, 2.0 * size / 1024 / time6_noinit); } -template +template void run_resizeview_tests7(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time7,time_raw = 100000.0; + double time7, time7_noinit, time_raw = 100000.0; + { + Kokkos::View a("A7", N2, N1, N1, N1, N1, N1, N1); + Kokkos::Timer timer; + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(a_, int(N2 * 1.1), N1, N1, N1, N1, N1, N1); + } + time7 = timer.seconds() / R; + } { - Kokkos::View a("A7",N2,N1,N1,N1,N1,N1,N1); + Kokkos::View a("A7", N2, N1, N1, N1, N1, N1, N1); Kokkos::Timer timer; - for(int r=0; r a_(a); - Kokkos::resize(a_,int(N2*1.1),N1,N1,N1,N1,N1,N1); + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(Kokkos::WithoutInitializing, a_, int(N2 * 1.1), N1, N1, N1, + N1, N1, N1); } - time7 = timer.seconds()/R; + time7_noinit = timer.seconds() / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); + Kokkos::View a("A1", N8); double* a_ptr = a.data(); Kokkos::Timer timer; - for(int r=0;r a1(Kokkos::ViewAllocateWithoutInitializing("A1"),int(N8*1.1)); + for (int r = 0; r < R; r++) { + Kokkos::View a1( + Kokkos::ViewAllocateWithoutInitializing("A1"), int(N8 * 1.1)); double* a1_ptr = a1.data(); - Kokkos::parallel_for(N8, KOKKOS_LAMBDA (const int& i) { - a1_ptr[i] = a_ptr[i]; - }); + Kokkos::parallel_for( + N8, KOKKOS_LAMBDA(const int& i) { a1_ptr[i] = a_ptr[i]; }); Kokkos::fence(); } Kokkos::fence(); - time_raw = timer.seconds()/R; + time_raw = timer.seconds() / R; } - #endif - double size = 1.0*N8*8/1024/1024; - printf(" Raw: %lf s %lf MB %lf GB/s\n",time_raw,size,2.0*size/1024/time_raw); - printf(" Rank7: %lf s %lf MB %lf GB/s\n",time7,size,2.0*size/1024/time7); +#endif + double size = 1.0 * N8 * 8 / 1024 / 1024; + printf(" Raw: %lf s %lf MB %lf GB/s\n", time_raw, size, + 2.0 * size / 1024 / time_raw); + printf(" Rank7: %lf s %lf MB %lf GB/s\n", time7, size, + 2.0 * size / 1024 / time7); + printf(" Rank7 (WithoutInitializing): %lf s %lf MB %lf GB/s\n", + time7_noinit, size, 2.0 * size / 1024 / time7_noinit); } -template +template void run_resizeview_tests8(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time8,time_raw = 100000.0; + double time8, time8_noinit, time_raw = 100000.0; + { + Kokkos::View a("A8", N1, N1, N1, N1, N1, N1, N1, + N1); + Kokkos::Timer timer; + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(a_, int(N1 * 1.1), N1, N1, N1, N1, N1, N1, N1); + } + time8 = timer.seconds() / R; + } { - Kokkos::View a("A8",N1,N1,N1,N1,N1,N1,N1,N1); + Kokkos::View a("A8", N1, N1, N1, N1, N1, N1, N1, + N1); Kokkos::Timer timer; - for(int r=0; r a_(a); - Kokkos::resize(a_,int(N1*1.1),N1,N1,N1,N1,N1,N1,N1); + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(Kokkos::WithoutInitializing, a_, int(N1 * 1.1), N1, N1, N1, + N1, N1, N1, N1); } - time8 = timer.seconds()/R; + time8_noinit = timer.seconds() / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); + Kokkos::View a("A1", N8); double* a_ptr = a.data(); Kokkos::Timer timer; - for(int r=0;r a1(Kokkos::ViewAllocateWithoutInitializing("A1"),int(N8*1.1)); + for (int r = 0; r < R; r++) { + Kokkos::View a1( + Kokkos::ViewAllocateWithoutInitializing("A1"), int(N8 * 1.1)); double* a1_ptr = a1.data(); - Kokkos::parallel_for(N8, KOKKOS_LAMBDA (const int& i) { - a1_ptr[i] = a_ptr[i]; - }); + Kokkos::parallel_for( + N8, KOKKOS_LAMBDA(const int& i) { a1_ptr[i] = a_ptr[i]; }); Kokkos::fence(); } Kokkos::fence(); - time_raw = timer.seconds()/R; + time_raw = timer.seconds() / R; } - #endif - double size = 1.0*N8*8/1024/1024; - printf(" Raw: %lf s %lf MB %lf GB/s\n",time_raw,size,2.0*size/1024/time_raw); - printf(" Rank8: %lf s %lf MB %lf GB/s\n",time8,size,2.0*size/1024/time8); +#endif + double size = 1.0 * N8 * 8 / 1024 / 1024; + printf(" Raw: %lf s %lf MB %lf GB/s\n", time_raw, size, + 2.0 * size / 1024 / time_raw); + printf(" Rank8: %lf s %lf MB %lf GB/s\n", time8, size, + 2.0 * size / 1024 / time8); + printf(" Rank8 (WithoutInitializing): %lf s %lf MB %lf GB/s\n", + time8_noinit, size, 2.0 * size / 1024 / time8_noinit); } -} +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewResize_123.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewResize_123.cpp index 61b7edf373..1dc4f285f5 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewResize_123.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewResize_123.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,11 +46,11 @@ namespace Test { -TEST_F( default_exec, ViewResize_Rank123 ) { +TEST(default_exec, ViewResize_Rank123) { printf("Resize View Performance for LayoutLeft:\n"); - run_resizeview_tests123(10,1); + run_resizeview_tests123(10, 1); printf("Resize View Performance for LayoutRight:\n"); - run_resizeview_tests123(10,1); + run_resizeview_tests123(10, 1); } -} +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewResize_45.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewResize_45.cpp index 172f9474d9..3754a5bb14 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewResize_45.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewResize_45.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,11 +46,11 @@ namespace Test { -TEST_F( default_exec, ViewResize_Rank_45 ) { +TEST(default_exec, ViewResize_Rank_45) { printf("Resize View Performance for LayoutLeft:\n"); - run_resizeview_tests45(10,1); + run_resizeview_tests45(10, 1); printf("Resize View Performance for LayoutRight:\n"); - run_resizeview_tests45(10,1); + run_resizeview_tests45(10, 1); } -} +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewResize_6.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewResize_6.cpp index d4f8fb2af0..1b8d6fbc8a 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewResize_6.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewResize_6.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,11 +46,11 @@ namespace Test { -TEST_F( default_exec, ViewResize_Rank6 ) { +TEST(default_exec, ViewResize_Rank6) { printf("Resize View Performance for LayoutLeft:\n"); - run_resizeview_tests6(10,1); + run_resizeview_tests6(10, 1); printf("Resize View Performance for LayoutRight:\n"); - run_resizeview_tests6(10,1); + run_resizeview_tests6(10, 1); } -} +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewResize_7.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewResize_7.cpp index f7b9b5b545..f8efa195fc 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewResize_7.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewResize_7.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,11 +46,11 @@ namespace Test { -TEST_F( default_exec, ViewResize_Rank7 ) { +TEST(default_exec, ViewResize_Rank7) { printf("Resize View Performance for LayoutLeft:\n"); - run_resizeview_tests7(10,1); + run_resizeview_tests7(10, 1); printf("Resize View Performance for LayoutRight:\n"); - run_resizeview_tests7(10,1); + run_resizeview_tests7(10, 1); } -} +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewResize_8.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewResize_8.cpp index 877fcef933..afeeb64356 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewResize_8.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewResize_8.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,11 +46,11 @@ namespace Test { -TEST_F( default_exec, ViewResize_Rank8 ) { +TEST(default_exec, ViewResize_Rank8) { printf("Resize View Performance for LayoutLeft:\n"); - run_resizeview_tests8(10,1); + run_resizeview_tests8(10, 1); printf("Resize View Performance for LayoutRight:\n"); - run_resizeview_tests8(10,1); + run_resizeview_tests8(10, 1); } -} +} // namespace Test diff --git a/lib/kokkos/core/perf_test/test_atomic.cpp b/lib/kokkos/core/perf_test/test_atomic.cpp index 24e4f015d3..7699d7b91c 100644 --- a/lib/kokkos/core/perf_test/test_atomic.cpp +++ b/lib/kokkos/core/perf_test/test_atomic.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -50,335 +51,323 @@ typedef Kokkos::DefaultExecutionSpace exec_space; -#define RESET 0 -#define BRIGHT 1 -#define DIM 2 -#define UNDERLINE 3 -#define BLINK 4 -#define REVERSE 7 -#define HIDDEN 8 - -#define BLACK 0 -#define RED 1 -#define GREEN 2 -#define YELLOW 3 -#define BLUE 4 -#define MAGENTA 5 -#define CYAN 6 -#define GREY 7 -#define WHITE 8 - -void textcolor(int attr, int fg, int bg) -{ char command[40]; - - /* Command is the control command to the terminal */ - sprintf(command, "%c[%d;%d;%dm", 0x1B, attr, fg + 30, bg + 40); - printf("%s", command); +#define RESET 0 +#define BRIGHT 1 +#define DIM 2 +#define UNDERLINE 3 +#define BLINK 4 +#define REVERSE 7 +#define HIDDEN 8 + +#define BLACK 0 +#define RED 1 +#define GREEN 2 +#define YELLOW 3 +#define BLUE 4 +#define MAGENTA 5 +#define CYAN 6 +#define GREY 7 +#define WHITE 8 + +void textcolor(int attr, int fg, int bg) { + char command[40]; + + /* Command is the control command to the terminal */ + sprintf(command, "%c[%d;%d;%dm", 0x1B, attr, fg + 30, bg + 40); + printf("%s", command); } -void textcolor_standard() {textcolor(RESET, BLACK, WHITE);} +void textcolor_standard() { textcolor(RESET, BLACK, WHITE); } - -template -struct ZeroFunctor{ +template +struct ZeroFunctor { typedef DEVICE_TYPE execution_space; - typedef typename Kokkos::View type; - typedef typename Kokkos::View::HostMirror h_type; + typedef typename Kokkos::View type; + typedef typename Kokkos::View::HostMirror h_type; type data; KOKKOS_INLINE_FUNCTION - void operator()(int) const { - data() = 0; - } + void operator()(int) const { data() = 0; } }; //--------------------------------------------------- //--------------atomic_fetch_add--------------------- //--------------------------------------------------- -template -struct AddFunctor{ +template +struct AddFunctor { typedef DEVICE_TYPE execution_space; - typedef Kokkos::View type; + typedef Kokkos::View type; type data; KOKKOS_INLINE_FUNCTION - void operator()(int) const { - Kokkos::atomic_fetch_add(&data(),(T)1); - } + void operator()(int) const { Kokkos::atomic_fetch_add(&data(), (T)1); } }; -template +template T AddLoop(int loop) { - struct ZeroFunctor f_zero; - typename ZeroFunctor::type data("Data"); - typename ZeroFunctor::h_type h_data("HData"); + struct ZeroFunctor f_zero; + typename ZeroFunctor::type data("Data"); + typename ZeroFunctor::h_type h_data("HData"); f_zero.data = data; - Kokkos::parallel_for(1,f_zero); + Kokkos::parallel_for(1, f_zero); exec_space().fence(); - struct AddFunctor f_add; + struct AddFunctor f_add; f_add.data = data; - Kokkos::parallel_for(loop,f_add); + Kokkos::parallel_for(loop, f_add); exec_space().fence(); - Kokkos::deep_copy(h_data,data); + Kokkos::deep_copy(h_data, data); T val = h_data(); return val; } -template -struct AddNonAtomicFunctor{ +template +struct AddNonAtomicFunctor { typedef DEVICE_TYPE execution_space; - typedef Kokkos::View type; + typedef Kokkos::View type; type data; KOKKOS_INLINE_FUNCTION - void operator()(int) const { - data()+=(T)1; - } + void operator()(int) const { data() += (T)1; } }; -template +template T AddLoopNonAtomic(int loop) { - struct ZeroFunctor f_zero; - typename ZeroFunctor::type data("Data"); - typename ZeroFunctor::h_type h_data("HData"); + struct ZeroFunctor f_zero; + typename ZeroFunctor::type data("Data"); + typename ZeroFunctor::h_type h_data("HData"); f_zero.data = data; - Kokkos::parallel_for(1,f_zero); + Kokkos::parallel_for(1, f_zero); exec_space().fence(); - struct AddNonAtomicFunctor f_add; + struct AddNonAtomicFunctor f_add; f_add.data = data; - Kokkos::parallel_for(loop,f_add); + Kokkos::parallel_for(loop, f_add); exec_space().fence(); - Kokkos::deep_copy(h_data,data); + Kokkos::deep_copy(h_data, data); T val = h_data(); return val; } -template +template T AddLoopSerial(int loop) { T* data = new T[1]; data[0] = 0; - for(int i=0;i -struct CASFunctor{ +template +struct CASFunctor { typedef DEVICE_TYPE execution_space; - typedef Kokkos::View type; + typedef Kokkos::View type; type data; KOKKOS_INLINE_FUNCTION void operator()(int) const { - T old = data(); - T newval, assumed; - do { - assumed = old; - newval = assumed + (T)1; - old = Kokkos::atomic_compare_exchange(&data(), assumed, newval); - } - while( old != assumed ); + T old = data(); + T newval, assumed; + do { + assumed = old; + newval = assumed + (T)1; + old = Kokkos::atomic_compare_exchange(&data(), assumed, newval); + } while (old != assumed); } }; -template +template T CASLoop(int loop) { - struct ZeroFunctor f_zero; - typename ZeroFunctor::type data("Data"); - typename ZeroFunctor::h_type h_data("HData"); + struct ZeroFunctor f_zero; + typename ZeroFunctor::type data("Data"); + typename ZeroFunctor::h_type h_data("HData"); f_zero.data = data; - Kokkos::parallel_for(1,f_zero); + Kokkos::parallel_for(1, f_zero); exec_space().fence(); - struct CASFunctor f_cas; + struct CASFunctor f_cas; f_cas.data = data; - Kokkos::parallel_for(loop,f_cas); + Kokkos::parallel_for(loop, f_cas); exec_space().fence(); - Kokkos::deep_copy(h_data,data); + Kokkos::deep_copy(h_data, data); T val = h_data(); return val; } -template -struct CASNonAtomicFunctor{ +template +struct CASNonAtomicFunctor { typedef DEVICE_TYPE execution_space; - typedef Kokkos::View type; + typedef Kokkos::View type; type data; KOKKOS_INLINE_FUNCTION void operator()(int) const { - volatile T assumed; - volatile T newval; - bool fail=1; - do { - assumed = data(); - newval = assumed + (T)1; - if(data()==assumed) { - data() = newval; - fail = 0; - } - } - while(fail); + volatile T assumed; + volatile T newval; + bool fail = 1; + do { + assumed = data(); + newval = assumed + (T)1; + if (data() == assumed) { + data() = newval; + fail = 0; + } + } while (fail); } }; -template +template T CASLoopNonAtomic(int loop) { - struct ZeroFunctor f_zero; - typename ZeroFunctor::type data("Data"); - typename ZeroFunctor::h_type h_data("HData"); + struct ZeroFunctor f_zero; + typename ZeroFunctor::type data("Data"); + typename ZeroFunctor::h_type h_data("HData"); f_zero.data = data; - Kokkos::parallel_for(1,f_zero); + Kokkos::parallel_for(1, f_zero); exec_space().fence(); - struct CASNonAtomicFunctor f_cas; + struct CASNonAtomicFunctor f_cas; f_cas.data = data; - Kokkos::parallel_for(loop,f_cas); + Kokkos::parallel_for(loop, f_cas); exec_space().fence(); - Kokkos::deep_copy(h_data,data); + Kokkos::deep_copy(h_data, data); T val = h_data(); return val; } -template +template T CASLoopSerial(int loop) { T* data = new T[1]; data[0] = 0; - for(int i=0;i -struct ExchFunctor{ +template +struct ExchFunctor { typedef DEVICE_TYPE execution_space; - typedef Kokkos::View type; + typedef Kokkos::View type; type data, data2; KOKKOS_INLINE_FUNCTION void operator()(int i) const { - T old = Kokkos::atomic_exchange(&data(),(T)i); - Kokkos::atomic_fetch_add(&data2(),old); + T old = Kokkos::atomic_exchange(&data(), (T)i); + Kokkos::atomic_fetch_add(&data2(), old); } }; -template +template T ExchLoop(int loop) { - struct ZeroFunctor f_zero; - typename ZeroFunctor::type data("Data"); - typename ZeroFunctor::h_type h_data("HData"); + struct ZeroFunctor f_zero; + typename ZeroFunctor::type data("Data"); + typename ZeroFunctor::h_type h_data("HData"); f_zero.data = data; - Kokkos::parallel_for(1,f_zero); + Kokkos::parallel_for(1, f_zero); exec_space().fence(); - typename ZeroFunctor::type data2("Data"); - typename ZeroFunctor::h_type h_data2("HData"); + typename ZeroFunctor::type data2("Data"); + typename ZeroFunctor::h_type h_data2("HData"); f_zero.data = data2; - Kokkos::parallel_for(1,f_zero); + Kokkos::parallel_for(1, f_zero); exec_space().fence(); - struct ExchFunctor f_exch; - f_exch.data = data; + struct ExchFunctor f_exch; + f_exch.data = data; f_exch.data2 = data2; - Kokkos::parallel_for(loop,f_exch); + Kokkos::parallel_for(loop, f_exch); exec_space().fence(); - Kokkos::deep_copy(h_data,data); - Kokkos::deep_copy(h_data2,data2); + Kokkos::deep_copy(h_data, data); + Kokkos::deep_copy(h_data2, data2); T val = h_data() + h_data2(); return val; } -template -struct ExchNonAtomicFunctor{ +template +struct ExchNonAtomicFunctor { typedef DEVICE_TYPE execution_space; - typedef Kokkos::View type; + typedef Kokkos::View type; type data, data2; KOKKOS_INLINE_FUNCTION void operator()(int i) const { - T old = data(); - data()=(T) i; - data2()+=old; + T old = data(); + data() = (T)i; + data2() += old; } }; - -template +template T ExchLoopNonAtomic(int loop) { - struct ZeroFunctor f_zero; - typename ZeroFunctor::type data("Data"); - typename ZeroFunctor::h_type h_data("HData"); + struct ZeroFunctor f_zero; + typename ZeroFunctor::type data("Data"); + typename ZeroFunctor::h_type h_data("HData"); f_zero.data = data; - Kokkos::parallel_for(1,f_zero); + Kokkos::parallel_for(1, f_zero); exec_space().fence(); - typename ZeroFunctor::type data2("Data"); - typename ZeroFunctor::h_type h_data2("HData"); + typename ZeroFunctor::type data2("Data"); + typename ZeroFunctor::h_type h_data2("HData"); f_zero.data = data2; - Kokkos::parallel_for(1,f_zero); + Kokkos::parallel_for(1, f_zero); exec_space().fence(); - struct ExchNonAtomicFunctor f_exch; - f_exch.data = data; + struct ExchNonAtomicFunctor f_exch; + f_exch.data = data; f_exch.data2 = data2; - Kokkos::parallel_for(loop,f_exch); + Kokkos::parallel_for(loop, f_exch); exec_space().fence(); - Kokkos::deep_copy(h_data,data); - Kokkos::deep_copy(h_data2,data2); + Kokkos::deep_copy(h_data, data); + Kokkos::deep_copy(h_data2, data2); T val = h_data() + h_data2(); return val; } -template +template T ExchLoopSerial(int loop) { - T* data = new T[1]; + T* data = new T[1]; T* data2 = new T[1]; - data[0] = 0; + data[0] = 0; data2[0] = 0; - for(int i=0;i +template T LoopVariant(int loop, int test) { switch (test) { case 1: return AddLoop(loop); @@ -388,7 +377,7 @@ T LoopVariant(int loop, int test) { return 0; } -template +template T LoopVariantSerial(int loop, int test) { switch (test) { case 1: return AddLoopSerial(loop); @@ -398,7 +387,7 @@ T LoopVariantSerial(int loop, int test) { return 0; } -template +template T LoopVariantNonAtomic(int loop, int test) { switch (test) { case 1: return AddLoopNonAtomic(loop); @@ -408,100 +397,105 @@ T LoopVariantNonAtomic(int loop, int test) { return 0; } -template +template void Loop(int loop, int test, const char* type_name) { - LoopVariant(loop,test); + LoopVariant(loop, test); Kokkos::Impl::Timer timer; - T res = LoopVariant(loop,test); + T res = LoopVariant(loop, test); double time = timer.seconds(); timer.reset(); - T resNonAtomic = LoopVariantNonAtomic(loop,test); + T resNonAtomic = LoopVariantNonAtomic(loop, test); double timeNonAtomic = timer.seconds(); timer.reset(); - T resSerial = LoopVariantSerial(loop,test); + T resSerial = LoopVariantSerial(loop, test); double timeSerial = timer.seconds(); - time *=1e6/loop; - timeNonAtomic*=1e6/loop; - timeSerial *=1e6/loop; - //textcolor_standard(); + time *= 1e6 / loop; + timeNonAtomic *= 1e6 / loop; + timeSerial *= 1e6 / loop; + // textcolor_standard(); bool passed = true; - if(resSerial!=res) passed = false; - //if(!passed) textcolor(RESET,BLACK,YELLOW); - printf("%s Test %i %s --- Loop: %i Value (S,A,NA): %e %e %e Time: %7.4e %7.4e %7.4e Size of Type %i)", - type_name,test,passed?"PASSED":"FAILED",loop, - 1.0*resSerial,1.0*res,1.0*resNonAtomic, - timeSerial,time,timeNonAtomic,(int)sizeof(T)); - //if(!passed) textcolor_standard(); + if (resSerial != res) passed = false; + // if(!passed) textcolor(RESET,BLACK,YELLOW); + printf( + "%s Test %i %s --- Loop: %i Value (S,A,NA): %e %e %e Time: %7.4e %7.4e " + "%7.4e Size of Type %i)", + type_name, test, passed ? "PASSED" : "FAILED", loop, 1.0 * resSerial, + 1.0 * res, 1.0 * resNonAtomic, timeSerial, time, timeNonAtomic, + (int)sizeof(T)); + // if(!passed) textcolor_standard(); printf("\n"); } - -template +template void Test(int loop, int test, const char* type_name) { - if(test==-1) { - Loop(loop,1,type_name); - Loop(loop,2,type_name); - Loop(loop,3,type_name); + if (test == -1) { + Loop(loop, 1, type_name); + Loop(loop, 2, type_name); + Loop(loop, 3, type_name); - } - else - Loop(loop,test,type_name); + } else + Loop(loop, test, type_name); } -int main(int argc, char* argv[]) -{ +int main(int argc, char* argv[]) { int type = -1; int loop = 100000; int test = -1; - for(int i=0;i(loop,test,"int "); + if (type == -1) all_tests = true; + while (type < 100) { + if (type == 1) { + Test(loop, test, "int "); } - if(type==2) { - Test(loop,test,"long int "); + if (type == 2) { + Test(loop, test, "long int "); } - if(type==3) { - Test(loop,test,"long long int "); + if (type == 3) { + Test(loop, test, "long long int "); } - if(type==4) { - Test(loop,test,"unsigned int "); + if (type == 4) { + Test(loop, test, "unsigned int "); } - if(type==5) { - Test(loop,test,"unsigned long int "); + if (type == 5) { + Test(loop, test, "unsigned long int "); } - if(type==6) { - Test(loop,test,"unsigned long long int "); + if (type == 6) { + Test(loop, test, "unsigned long long int "); } - if(type==10) { - //Test(loop,test,"float "); + if (type == 10) { + // Test(loop,test,"float "); } - if(type==11) { - Test(loop,test,"double "); + if (type == 11) { + Test(loop, test, "double "); } - if(!all_tests) type=100; - else type++; + if (!all_tests) + type = 100; + else + type++; } Kokkos::finalize(); - } - diff --git a/lib/kokkos/core/perf_test/test_mempool.cpp b/lib/kokkos/core/perf_test/test_mempool.cpp index c47730ec69..ad8622e7a6 100644 --- a/lib/kokkos/core/perf_test/test_mempool.cpp +++ b/lib/kokkos/core/perf_test/test_mempool.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -49,310 +50,271 @@ #include #include -using ExecSpace = Kokkos::DefaultExecutionSpace ; -using MemorySpace = Kokkos::DefaultExecutionSpace::memory_space ; +using ExecSpace = Kokkos::DefaultExecutionSpace; +using MemorySpace = Kokkos::DefaultExecutionSpace::memory_space; -using MemoryPool = Kokkos::MemoryPool< ExecSpace > ; +using MemoryPool = Kokkos::MemoryPool; struct TestFunctor { - - typedef Kokkos::View< uintptr_t * , ExecSpace > ptrs_type ; + typedef Kokkos::View ptrs_type; enum : unsigned { chunk = 32 }; - MemoryPool pool ; - ptrs_type ptrs ; - unsigned chunk_span ; - unsigned fill_stride ; - unsigned range_iter ; - unsigned repeat_inner ; - - TestFunctor( size_t total_alloc_size - , unsigned min_superblock_size - , unsigned number_alloc - , unsigned arg_stride_alloc - , unsigned arg_chunk_span - , unsigned arg_repeat ) - : pool() - , ptrs() - , chunk_span(0) - , fill_stride(0) - , repeat_inner(0) - { - MemorySpace m ; - - const unsigned min_block_size = chunk ; - const unsigned max_block_size = chunk * arg_chunk_span ; - pool = MemoryPool( m , total_alloc_size - , min_block_size - , max_block_size - , min_superblock_size ); - - ptrs = ptrs_type( Kokkos::view_alloc( m , "ptrs") , number_alloc ); - fill_stride = arg_stride_alloc ; - chunk_span = arg_chunk_span ; - range_iter = fill_stride * number_alloc ; - repeat_inner = arg_repeat ; - } + MemoryPool pool; + ptrs_type ptrs; + unsigned chunk_span; + unsigned fill_stride; + unsigned range_iter; + unsigned repeat_inner; + + TestFunctor(size_t total_alloc_size, unsigned min_superblock_size, + unsigned number_alloc, unsigned arg_stride_alloc, + unsigned arg_chunk_span, unsigned arg_repeat) + : pool(), ptrs(), chunk_span(0), fill_stride(0), repeat_inner(0) { + MemorySpace m; + + const unsigned min_block_size = chunk; + const unsigned max_block_size = chunk * arg_chunk_span; + pool = MemoryPool(m, total_alloc_size, min_block_size, max_block_size, + min_superblock_size); + + ptrs = ptrs_type(Kokkos::view_alloc(m, "ptrs"), number_alloc); + fill_stride = arg_stride_alloc; + chunk_span = arg_chunk_span; + range_iter = fill_stride * number_alloc; + repeat_inner = arg_repeat; + } //---------------------------------------- - typedef long value_type ; + typedef long value_type; //---------------------------------------- struct TagFill {}; KOKKOS_INLINE_FUNCTION - void operator()( TagFill , int i , value_type & update ) const noexcept - { - if ( 0 == i % fill_stride ) { + void operator()(TagFill, int i, value_type& update) const noexcept { + if (0 == i % fill_stride) { + const int j = i / fill_stride; - const int j = i / fill_stride ; + const unsigned size_alloc = chunk * (1 + (j % chunk_span)); - const unsigned size_alloc = chunk * ( 1 + ( j % chunk_span ) ); + ptrs(j) = (uintptr_t)pool.allocate(size_alloc); - ptrs(j) = (uintptr_t) pool.allocate(size_alloc); - - if ( ptrs(j) ) ++update ; - } + if (ptrs(j)) ++update; } + } - bool test_fill() - { - typedef Kokkos::RangePolicy< ExecSpace , TagFill > policy ; + bool test_fill() { + typedef Kokkos::RangePolicy policy; - long result = 0 ; + long result = 0; - Kokkos::parallel_reduce( policy(0,range_iter), *this , result ); + Kokkos::parallel_reduce(policy(0, range_iter), *this, result); - if ( result == long(ptrs.extent(0)) ) return true; - pool.print_state( std::cerr ); - return false; - } + if (result == long(ptrs.extent(0))) return true; + pool.print_state(std::cerr); + return false; + } //---------------------------------------- struct TagDel {}; KOKKOS_INLINE_FUNCTION - void operator()( TagDel , int i ) const noexcept - { - if ( 0 == i % fill_stride ) { - - const int j = i / fill_stride ; + void operator()(TagDel, int i) const noexcept { + if (0 == i % fill_stride) { + const int j = i / fill_stride; - const unsigned size_alloc = chunk * ( 1 + ( j % chunk_span ) ); + const unsigned size_alloc = chunk * (1 + (j % chunk_span)); - pool.deallocate( (void*) ptrs(j) , size_alloc ); - } + pool.deallocate((void*)ptrs(j), size_alloc); } + } - void test_del() - { - typedef Kokkos::RangePolicy< ExecSpace , TagDel > policy ; + void test_del() { + typedef Kokkos::RangePolicy policy; - Kokkos::parallel_for( policy(0,range_iter), *this ); - Kokkos::fence(); - } + Kokkos::parallel_for(policy(0, range_iter), *this); + Kokkos::fence(); + } //---------------------------------------- struct TagAllocDealloc {}; KOKKOS_INLINE_FUNCTION - void operator()( TagAllocDealloc , int i , long & update ) const noexcept - { - if ( 0 == i % fill_stride ) { - - const int j = i / fill_stride ; - - if ( 0 == j % 3 ) { + void operator()(TagAllocDealloc, int i, long& update) const noexcept { + if (0 == i % fill_stride) { + const int j = i / fill_stride; - for ( unsigned k = 0 ; k < repeat_inner ; ++k ) { + if (0 == j % 3) { + for (unsigned k = 0; k < repeat_inner; ++k) { + const unsigned size_alloc = chunk * (1 + (j % chunk_span)); - const unsigned size_alloc = chunk * ( 1 + ( j % chunk_span ) ); + pool.deallocate((void*)ptrs(j), size_alloc); - pool.deallocate( (void*) ptrs(j) , size_alloc ); + ptrs(j) = (uintptr_t)pool.allocate(size_alloc); - ptrs(j) = (uintptr_t) pool.allocate(size_alloc); - - if ( 0 == ptrs(j) ) update++ ; - } + if (0 == ptrs(j)) update++; } } } + } - bool test_alloc_dealloc() - { - typedef Kokkos::RangePolicy< ExecSpace , TagAllocDealloc > policy ; + bool test_alloc_dealloc() { + typedef Kokkos::RangePolicy policy; - long error_count = 0 ; + long error_count = 0; - Kokkos::parallel_reduce( policy(0,range_iter), *this , error_count ); + Kokkos::parallel_reduce(policy(0, range_iter), *this, error_count); - return 0 == error_count ; - } + return 0 == error_count; + } }; +int main(int argc, char* argv[]) { + static const char help_flag[] = "--help"; + static const char alloc_size_flag[] = "--alloc_size="; + static const char super_size_flag[] = "--super_size="; + static const char chunk_span_flag[] = "--chunk_span="; + static const char fill_stride_flag[] = "--fill_stride="; + static const char fill_level_flag[] = "--fill_level="; + static const char repeat_outer_flag[] = "--repeat_outer="; + static const char repeat_inner_flag[] = "--repeat_inner="; + long total_alloc_size = 1000000; + int min_superblock_size = 10000; + int chunk_span = 5; + int fill_stride = 1; + int fill_level = 70; + int repeat_outer = 1; + int repeat_inner = 1; -int main( int argc , char* argv[] ) -{ - static const char help_flag[] = "--help" ; - static const char alloc_size_flag[] = "--alloc_size=" ; - static const char super_size_flag[] = "--super_size=" ; - static const char chunk_span_flag[] = "--chunk_span=" ; - static const char fill_stride_flag[] = "--fill_stride=" ; - static const char fill_level_flag[] = "--fill_level=" ; - static const char repeat_outer_flag[] = "--repeat_outer=" ; - static const char repeat_inner_flag[] = "--repeat_inner=" ; - - long total_alloc_size = 1000000 ; - int min_superblock_size = 10000 ; - int chunk_span = 5 ; - int fill_stride = 1 ; - int fill_level = 70 ; - int repeat_outer = 1 ; - int repeat_inner = 1 ; - - int ask_help = 0 ; + int ask_help = 0; - for(int i=1;i> actual_superblock_bytes_lg2; + auto superblock_mask = actual_superblock_bytes - 1; + auto nsuperblocks = + (total_alloc_size + superblock_mask) >> actual_superblock_bytes_lg2; auto actual_total_bytes = nsuperblocks * actual_superblock_bytes; - auto bytes_wanted = (actual_total_bytes * fill_level) / 100; - auto chunk_spans = bytes_wanted / chunk_span_bytes; - auto number_alloc = int( chunk_spans * chunk_span ); + auto bytes_wanted = (actual_total_bytes * fill_level) / 100; + auto chunk_spans = bytes_wanted / chunk_span_bytes; + auto number_alloc = int(chunk_spans * chunk_span); - if ( ask_help ) { + if (ask_help) { std::cout << "command line options:" - << " " << help_flag - << " " << alloc_size_flag << "##" + << " " << help_flag << " " << alloc_size_flag << "##" << " " << super_size_flag << "##" << " " << fill_stride_flag << "##" << " " << fill_level_flag << "##" << " " << chunk_span_flag << "##" << " " << repeat_outer_flag << "##" - << " " << repeat_inner_flag << "##" - << std::endl ; + << " " << repeat_inner_flag << "##" << std::endl; return 0; } - Kokkos::initialize(argc,argv); + Kokkos::initialize(argc, argv); - double sum_fill_time = 0; + double sum_fill_time = 0; double sum_cycle_time = 0; - double sum_both_time = 0; - double min_fill_time = std::numeric_limits::max(); + double sum_both_time = 0; + double min_fill_time = std::numeric_limits::max(); double min_cycle_time = std::numeric_limits::max(); - double min_both_time = std::numeric_limits::max(); - //one alloc in fill, alloc/dealloc pair in repeat_inner - for ( int i = 0 ; i < repeat_outer ; ++i ) { + double min_both_time = std::numeric_limits::max(); + // one alloc in fill, alloc/dealloc pair in repeat_inner + for (int i = 0; i < repeat_outer; ++i) { + TestFunctor functor(total_alloc_size, min_superblock_size, number_alloc, + fill_stride, chunk_span, repeat_inner); - TestFunctor functor( total_alloc_size - , min_superblock_size - , number_alloc - , fill_stride - , chunk_span - , repeat_inner ); + Kokkos::Impl::Timer timer; - Kokkos::Impl::Timer timer ; - - if ( ! functor.test_fill() ) { + if (!functor.test_fill()) { Kokkos::abort("fill "); } auto t0 = timer.seconds(); - if ( ! functor.test_alloc_dealloc() ) { + if (!functor.test_alloc_dealloc()) { Kokkos::abort("alloc/dealloc "); } - auto t1 = timer.seconds(); - auto this_fill_time = t0; + auto t1 = timer.seconds(); + auto this_fill_time = t0; auto this_cycle_time = t1 - t0; - auto this_both_time = t1; + auto this_both_time = t1; sum_fill_time += this_fill_time; sum_cycle_time += this_cycle_time; sum_both_time += this_both_time; - min_fill_time = std::min(min_fill_time, this_fill_time); + min_fill_time = std::min(min_fill_time, this_fill_time); min_cycle_time = std::min(min_cycle_time, this_cycle_time); - min_both_time = std::min(min_both_time, this_both_time); + min_both_time = std::min(min_both_time, this_both_time); } Kokkos::finalize(); - printf( "\"mempool: alloc super stride level span inner outer number\" %ld %d %d %d %d %d %d %d\n" - , total_alloc_size - , min_superblock_size - , fill_stride - , fill_level - , chunk_span - , repeat_inner - , repeat_outer - , number_alloc ); - - auto avg_fill_time = sum_fill_time / repeat_outer; + printf( + "\"mempool: alloc super stride level span inner outer number\" %ld %d %d " + "%d %d %d %d %d\n", + total_alloc_size, min_superblock_size, fill_stride, fill_level, + chunk_span, repeat_inner, repeat_outer, number_alloc); + + auto avg_fill_time = sum_fill_time / repeat_outer; auto avg_cycle_time = sum_cycle_time / repeat_outer; - auto avg_both_time = sum_both_time / repeat_outer; + auto avg_both_time = sum_both_time / repeat_outer; - printf( "\"mempool: fill time (min, avg)\" %.8f %.8f\n" - , min_fill_time - , avg_fill_time ); + printf("\"mempool: fill time (min, avg)\" %.8f %.8f\n", min_fill_time, + avg_fill_time); - printf( "\"mempool: cycle time (min, avg)\" %.8f %.8f\n" - , min_cycle_time - , avg_cycle_time ); + printf("\"mempool: cycle time (min, avg)\" %.8f %.8f\n", min_cycle_time, + avg_cycle_time); - printf( "\"mempool: test time (min, avg)\" %.8f %.8f\n" - , min_both_time - , avg_both_time ); + printf("\"mempool: test time (min, avg)\" %.8f %.8f\n", min_both_time, + avg_both_time); - printf( "\"mempool: fill ops per second (max, avg)\" %g %g\n" - , number_alloc / min_fill_time - , number_alloc / avg_fill_time ); + printf("\"mempool: fill ops per second (max, avg)\" %g %g\n", + number_alloc / min_fill_time, number_alloc / avg_fill_time); - printf( "\"mempool: cycle ops per second (max, avg)\" %g %g\n" - , (2 * number_alloc * repeat_inner) / min_cycle_time - , (2 * number_alloc * repeat_inner) / avg_cycle_time ); + printf("\"mempool: cycle ops per second (max, avg)\" %g %g\n", + (2 * number_alloc * repeat_inner) / min_cycle_time, + (2 * number_alloc * repeat_inner) / avg_cycle_time); } - diff --git a/lib/kokkos/core/perf_test/test_taskdag.cpp b/lib/kokkos/core/perf_test/test_taskdag.cpp index 41198edfe1..a97edc59e8 100644 --- a/lib/kokkos/core/perf_test/test_taskdag.cpp +++ b/lib/kokkos/core/perf_test/test_taskdag.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -43,13 +44,10 @@ #include -#if ! defined( KOKKOS_ENABLE_TASKDAG ) || \ - defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS ) +#if !defined(KOKKOS_ENABLE_TASKDAG) || \ + defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS) -int main() -{ - return 0 ; -} +int main() { return 0; } #else @@ -60,187 +58,160 @@ int main() #include -using ExecSpace = Kokkos::DefaultExecutionSpace ; +using ExecSpace = Kokkos::DefaultExecutionSpace; -inline -long eval_fib( long n ) -{ +inline long eval_fib(long n) { constexpr long mask = 0x03; - long fib[4] = { 0, 1, 0, 0 }; + long fib[4] = {0, 1, 0, 0}; - for ( long i = 2; i <= n; ++i ) { - fib[ i & mask ] = fib[ ( i - 1 ) & mask ] + fib[ ( i - 2 ) & mask ]; + for (long i = 2; i <= n; ++i) { + fib[i & mask] = fib[(i - 1) & mask] + fib[(i - 2) & mask]; } - return fib[ n & mask ]; + return fib[n & mask]; } -inline -long fib_alloc_count( long n ) -{ +inline long fib_alloc_count(long n) { constexpr long mask = 0x03; - long count[4] = { 1, 1, 0, 0 }; + long count[4] = {1, 1, 0, 0}; - for ( long i = 2; i <= n; ++i ) { - count[ i & mask ] = 2 // this task plus the 'when_all' task - + count[ ( i - 1 ) & mask ] - + count[ ( i - 2 ) & mask ]; + for (long i = 2; i <= n; ++i) { + count[i & mask] = 2 // this task plus the 'when_all' task + + count[(i - 1) & mask] + count[(i - 2) & mask]; } - return count[ n & mask ]; + return count[n & mask]; } -template< class Scheduler > +template struct TestFib { + using MemorySpace = typename Scheduler::memory_space; + using MemberType = typename Scheduler::member_type; + using FutureType = Kokkos::BasicFuture; - using MemorySpace = typename Scheduler::memory_space ; - using MemberType = typename Scheduler::member_type ; - using FutureType = Kokkos::BasicFuture< long , Scheduler > ; - - typedef long value_type ; + typedef long value_type; - FutureType dep[2] ; - const value_type n ; + FutureType dep[2]; + const value_type n; KOKKOS_INLINE_FUNCTION - TestFib( const value_type arg_n ) - : dep{} , n( arg_n ) {} + TestFib(const value_type arg_n) : dep{}, n(arg_n) {} KOKKOS_INLINE_FUNCTION - void operator()( MemberType & member, value_type & result ) noexcept - { - auto& sched = member.scheduler(); - if ( n < 2 ) { - result = n ; - } - else if ( ! dep[0].is_null() && ! dep[1].is_null() ) { - result = dep[0].get() + dep[1].get(); - } - else { - // Spawn new children and respawn myself to sum their results. - // Spawn lower value at higher priority as it has a shorter - // path to completion. - - dep[1] = Kokkos::task_spawn - ( Kokkos::TaskSingle( sched, Kokkos::TaskPriority::High ) - , TestFib( n - 2 ) ); - - dep[0] = Kokkos::task_spawn - ( Kokkos::TaskSingle( sched ) - , TestFib( n - 1 ) ); - - auto fib_all = sched.when_all( dep, 2 ); - - if ( ! dep[0].is_null() && ! dep[1].is_null() && ! fib_all.is_null() ) { - // High priority to retire this branch. - Kokkos::respawn( this, fib_all, Kokkos::TaskPriority::High ); - } - else { - Kokkos::abort("Failed nested task spawn (allocation)"); - } + void operator()(MemberType& member, value_type& result) noexcept { + auto& sched = member.scheduler(); + if (n < 2) { + result = n; + } else if (!dep[0].is_null() && !dep[1].is_null()) { + result = dep[0].get() + dep[1].get(); + } else { + // Spawn new children and respawn myself to sum their results. + // Spawn lower value at higher priority as it has a shorter + // path to completion. + + dep[1] = Kokkos::task_spawn( + Kokkos::TaskSingle(sched, Kokkos::TaskPriority::High), + TestFib(n - 2)); + + dep[0] = Kokkos::task_spawn(Kokkos::TaskSingle(sched), TestFib(n - 1)); + + auto fib_all = sched.when_all(dep, 2); + + if (!dep[0].is_null() && !dep[1].is_null() && !fib_all.is_null()) { + // High priority to retire this branch. + Kokkos::respawn(this, fib_all, Kokkos::TaskPriority::High); + } else { + Kokkos::abort("Failed nested task spawn (allocation)"); } } + } }; +int main(int argc, char* argv[]) { + static const char help[] = "--help"; + static const char alloc_size[] = "--alloc_size="; + static const char super_size[] = "--super_size="; + static const char repeat_outer[] = "--repeat_outer="; + static const char input_value[] = "--input="; + long total_alloc_size = 1000000; + int min_superblock_size = 10000; + int test_repeat_outer = 1; + int fib_input = 4; -int main( int argc , char* argv[] ) -{ - static const char help[] = "--help" ; - static const char alloc_size[] = "--alloc_size=" ; - static const char super_size[] = "--super_size=" ; - static const char repeat_outer[] = "--repeat_outer=" ; - static const char input_value[] = "--input=" ; + int ask_help = 0; - long total_alloc_size = 1000000 ; - int min_superblock_size = 10000 ; - int test_repeat_outer = 1 ; - int fib_input = 4 ; + for (int i = 1; i < argc; i++) { + const char* const a = argv[i]; - int ask_help = 0 ; + if (!strncmp(a, help, strlen(help))) ask_help = 1; - for(int i=1;i; - typedef TestFib< Scheduler > Functor ; + typedef TestFib Functor; - Kokkos::initialize(argc,argv); + Kokkos::initialize(argc, argv); { - - Scheduler sched( Functor::MemorySpace() - , total_alloc_size - , min_block_size - , max_block_size - , min_superblock_size - ); + Scheduler sched(Functor::MemorySpace(), total_alloc_size, min_block_size, + max_block_size, min_superblock_size); Functor::FutureType f = - Kokkos::host_spawn( Kokkos::TaskSingle( sched ) - , Functor( fib_input ) - ); + Kokkos::host_spawn(Kokkos::TaskSingle(sched), Functor(fib_input)); - Kokkos::wait( sched ); + Kokkos::wait(sched); test_result = f.get(); - //task_count_max = sched.allocated_task_count_max(); - //task_count_accum = sched.allocated_task_count_accum(); + // task_count_max = sched.allocated_task_count_max(); + // task_count_accum = sched.allocated_task_count_accum(); - //if ( number_alloc != task_count_accum ) { + // if ( number_alloc != task_count_accum ) { // std::cout << " number_alloc( " << number_alloc << " )" // << " != task_count_accum( " << task_count_accum << " )" // << std::endl ; //} - if ( fib_output != test_result ) { + if (fib_output != test_result) { std::cout << " answer( " << fib_output << " )" - << " != result( " << test_result << " )" - << std::endl ; + << " != result( " << test_result << " )" << std::endl; } - if ( fib_output != test_result) { // || number_alloc != task_count_accum ) { + if (fib_output != test_result) { // || number_alloc != task_count_accum ) { printf(" TEST FAILED\n"); return -1; } @@ -248,41 +219,34 @@ int main( int argc , char* argv[] ) double min_time = std::numeric_limits::max(); double time_sum = 0; - for ( int i = 0 ; i < test_repeat_outer ; ++i ) { - Kokkos::Impl::Timer timer ; + for (int i = 0; i < test_repeat_outer; ++i) { + Kokkos::Impl::Timer timer; Functor::FutureType ftmp = - Kokkos::host_spawn( Kokkos::TaskSingle( sched ) - , Functor( fib_input ) - ); + Kokkos::host_spawn(Kokkos::TaskSingle(sched), Functor(fib_input)); - Kokkos::wait( sched ); + Kokkos::wait(sched); auto this_time = timer.seconds(); - min_time = std::min(min_time, this_time); + min_time = std::min(min_time, this_time); time_sum += this_time; } auto avg_time = time_sum / test_repeat_outer; - printf( "\"taskdag: alloc super repeat input output task-accum task-max\" %ld %d %d %d %ld %ld %ld\n" - , total_alloc_size - , min_superblock_size - , test_repeat_outer - , fib_input - , fib_output - , task_count_accum - , task_count_max ); - - printf( "\"taskdag: time (min, avg)\" %g %g\n", min_time, avg_time); - printf( "\"taskdag: tasks per second (max, avg)\" %g %g\n" - , number_alloc / min_time - , number_alloc / avg_time ); - } // end scope to destroy scheduler prior to finalize + printf( + "\"taskdag: alloc super repeat input output task-accum task-max\" %ld " + "%d %d %d %ld %ld %ld\n", + total_alloc_size, min_superblock_size, test_repeat_outer, fib_input, + fib_output, task_count_accum, task_count_max); + + printf("\"taskdag: time (min, avg)\" %g %g\n", min_time, avg_time); + printf("\"taskdag: tasks per second (max, avg)\" %g %g\n", + number_alloc / min_time, number_alloc / avg_time); + } // end scope to destroy scheduler prior to finalize Kokkos::finalize(); - return 0 ; + return 0; } #endif - diff --git a/lib/kokkos/core/src/CMakeLists.txt b/lib/kokkos/core/src/CMakeLists.txt index a941c5da0c..eb058a982e 100644 --- a/lib/kokkos/core/src/CMakeLists.txt +++ b/lib/kokkos/core/src/CMakeLists.txt @@ -1,124 +1,81 @@ - - -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) - -#----------------------------------------------------------------------------- - -SET(TRILINOS_INCDIR ${CMAKE_INSTALL_PREFIX}/${${PROJECT_NAME}_INSTALL_INCLUDE_DIR}) - -#----------------------------------------------------------------------------- - -IF(KOKKOS_LEGACY_TRIBITS) - - MESSAGE("LEGACY STUFF GETTING CALLED") - - IF(KOKKOS_ENABLE_EXPLICIT_INSTANTIATION) - MESSAGE("GOING INTO ETI DIR") - ADD_SUBDIRECTORY(eti) - INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/eti") - ENDIF() - - ASSERT_DEFINED(${PROJECT_NAME}_ENABLE_CXX11) - ASSERT_DEFINED(${PACKAGE_NAME}_ENABLE_CUDA) - - SET(HEADERS_PUBLIC "") - SET(HEADERS_PRIVATE "") - SET(SOURCES "") - - FILE(GLOB HEADERS_PUBLIC Kokkos*.hpp) - LIST( APPEND HEADERS_PUBLIC ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}_config.h ) - - #----------------------------------------------------------------------------- - - FILE(GLOB HEADERS_IMPL impl/*.hpp) - FILE(GLOB SOURCES_IMPL impl/*.cpp) - - LIST(APPEND HEADERS_PRIVATE ${HEADERS_IMPL} ) - LIST(APPEND SOURCES ${SOURCES_IMPL} ) - - INSTALL(FILES ${HEADERS_IMPL} DESTINATION ${TRILINOS_INCDIR}/impl/) - - #----------------------------------------------------------------------------- - - FILE(GLOB HEADERS_THREADS Threads/*.hpp) - FILE(GLOB SOURCES_THREADS Threads/*.cpp) - - LIST(APPEND HEADERS_PRIVATE ${HEADERS_THREADS} ) - LIST(APPEND SOURCES ${SOURCES_THREADS} ) - - INSTALL(FILES ${HEADERS_THREADS} DESTINATION ${TRILINOS_INCDIR}/Threads/) - - #----------------------------------------------------------------------------- - - FILE(GLOB HEADERS_OPENMP OpenMP/*.hpp) - FILE(GLOB SOURCES_OPENMP OpenMP/*.cpp) - - LIST(APPEND HEADERS_PRIVATE ${HEADERS_OPENMP} ) - LIST(APPEND SOURCES ${SOURCES_OPENMP} ) - - INSTALL(FILES ${HEADERS_OPENMP} DESTINATION ${TRILINOS_INCDIR}/OpenMP/) - - #----------------------------------------------------------------------------- - - FILE(GLOB HEADERS_HPX HPX/*.hpp) - FILE(GLOB SOURCES_HPX HPX/*.cpp) - - LIST(APPEND HEADERS_PRIVATE ${HEADERS_HPX} ) - LIST(APPEND SOURCES ${SOURCES_HPX} ) - - INSTALL(FILES ${HEADERS_HPX} DESTINATION ${TRILINOS_INCDIR}/HPX/) - - #----------------------------------------------------------------------------- - - FILE(GLOB HEADERS_CUDA Cuda/*.hpp) - FILE(GLOB SOURCES_CUDA Cuda/*.cpp) - - LIST(APPEND HEADERS_PRIVATE ${HEADERS_CUDA} ) - LIST(APPEND SOURCES ${SOURCES_CUDA} ) - - INSTALL(FILES ${HEADERS_CUDA} DESTINATION ${TRILINOS_INCDIR}/Cuda/) - - #----------------------------------------------------------------------------- - FILE(GLOB HEADERS_QTHREADS Qthreads/*.hpp) - FILE(GLOB SOURCES_QTHREADS Qthreads/*.cpp) - - LIST(APPEND HEADERS_PRIVATE ${HEADERS_QTHREADS} ) - LIST(APPEND SOURCES ${SOURCES_QTHREADS} ) - - IF(KOKKOS_ENABLE_EXPLICIT_INSTANTIATION) - LIST(APPEND SOURCES ${ETI_SOURCES} ) - ENDIF() - - INSTALL(FILES ${HEADERS_QTHREADS} DESTINATION ${TRILINOS_INCDIR}/Qthreads/) - - TRIBITS_ADD_LIBRARY( - kokkoscore - HEADERS ${HEADERS_PUBLIC} - NOINSTALLHEADERS ${HEADERS_PRIVATE} - SOURCES ${SOURCES} - DEPLIBS - ) - -#----------------------------------------------------------------------------- -# In the new build system, sources are calculated by Makefile.kokkos -else() - - INSTALL (DIRECTORY - "${CMAKE_CURRENT_SOURCE_DIR}/" - DESTINATION ${TRILINOS_INCDIR} - FILES_MATCHING PATTERN "*.hpp" - ) - - TRIBITS_ADD_LIBRARY( - kokkoscore - SOURCES ${KOKKOS_CORE_SRCS} - DEPLIBS - ) - -endif() -#----------------------------------------------------------------------------- - -# build and install pkgconfig file -CONFIGURE_FILE(kokkos.pc.in kokkos.pc @ONLY) -INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/kokkos.pc DESTINATION lib/pkgconfig) +#I have to leave these here for tribits +KOKKOS_INCLUDE_DIRECTORIES( + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${KOKKOS_TOP_BUILD_DIR} +) + +INSTALL (DIRECTORY + "${CMAKE_CURRENT_SOURCE_DIR}/" + DESTINATION ${KOKKOS_HEADER_DIR} + FILES_MATCHING PATTERN "*.hpp" +) + +SET(KOKKOS_CORE_SRCS) +APPEND_GLOB(KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/impl/*.cpp) + +IF (KOKKOS_ENABLE_ROCM) + APPEND_GLOB(KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/ROCm/*.cpp) + IF (KOKKOS_ENABLE_ETI) + APPEND_GLOB(KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/eti/ROCm/*.cpp) + ENDIF() +ENDIF() + +IF (KOKKOS_ENABLE_CUDA) + APPEND_GLOB(KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/Cuda/*.cpp) + IF (KOKKOS_ENABLE_ETI) + APPEND_GLOB(KOKKOS_CORE_SRC ${CMAKE_CURRENT_SOURCE_DIR/eti/Cuda/*.cpp) + ENDIF() +ENDIF() + +IF (KOKKOS_ENABLE_OPENMP) + APPEND_GLOB(KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/OpenMP/*.cpp) + IF (KOKKOS_ENABLE_ETI) + APPEND_GLOB(KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/eti/OpenMP/*.cpp) + ENDIF() +ENDIF() + +IF (KOKKOS_ENABLE_PTHREAD) + APPEND_GLOB(KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/Threads/*.cpp) + IF (KOKKOS_ENABLE_ETI) + APPEND_GLOB(KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/eti/Threads/*.cpp) + ENDIF() +ENDIF() + +IF (KOKKOS_ENABLE_HPX) + APPEND_GLOB(KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/HPX/*.cpp) +ENDIF() + +IF (NOT KOKKOS_ENABLE_MEMKIND) + LIST(REMOVE_ITEM KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/impl/Kokkos_HBWSpace.cpp) +ENDIF() + +IF (KOKKOS_ENABLE_SERIAL) + IF (KOKKOS_ENABLE_ETI) + APPEND_GLOB(KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/eti/Serial/*.cpp) + ENDIF() +ELSE() + LIST(REMOVE_ITEM KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/impl/Kokkos_Serial.cpp) + LIST(REMOVE_ITEM KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/impl/Kokkos_Serial_task.cpp) +ENDIF() + +KOKKOS_ADD_LIBRARY( + kokkoscore + SOURCES ${KOKKOS_CORE_SRCS} +) + +SET_TARGET_PROPERTIES(kokkoscore PROPERTIES VERSION ${Kokkos_VERSION}) + +KOKKOS_LIB_INCLUDE_DIRECTORIES(kokkoscore + ${KOKKOS_TOP_BUILD_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} +) + +KOKKOS_LINK_TPL(kokkoscore PUBLIC HWLOC) +KOKKOS_LINK_TPL(kokkoscore PUBLIC MEMKIND) +KOKKOS_LINK_TPL(kokkoscore PUBLIC CUDA) +KOKKOS_LINK_TPL(kokkoscore PUBLIC HPX) +KOKKOS_LINK_TPL(kokkoscore PUBLIC LIBDL) +KOKKOS_LINK_TPL(kokkoscore PUBLIC LIBRT) +KOKKOS_LINK_TPL(kokkoscore PUBLIC PTHREAD) diff --git a/lib/kokkos/core/src/Cuda/KokkosExp_Cuda_IterateTile.hpp b/lib/kokkos/core/src/Cuda/KokkosExp_Cuda_IterateTile.hpp index 8a83dfff4a..3706263921 100644 --- a/lib/kokkos/core/src/Cuda/KokkosExp_Cuda_IterateTile.hpp +++ b/lib/kokkos/core/src/Cuda/KokkosExp_Cuda_IterateTile.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,7 +46,7 @@ #define KOKKOS_CUDA_EXP_ITERATE_TILE_HPP #include -#if defined( __CUDACC__ ) && defined( KOKKOS_ENABLE_CUDA ) +#if defined(__CUDACC__) && defined(KOKKOS_ENABLE_CUDA) #include #include @@ -55,181 +56,182 @@ //#include // Including the file above, leads to following type of errors: -// /home/ndellin/kokkos/core/src/Cuda/Kokkos_CudaExec.hpp(84): error: incomplete type is not allowed -// As a result, recreate cuda_parallel_launch and associated code +// /home/ndellin/kokkos/core/src/Cuda/Kokkos_CudaExec.hpp(84): error: incomplete +// type is not allowed As a result, recreate cuda_parallel_launch and associated +// code #if defined(KOKKOS_ENABLE_PROFILING) #include #include #endif -namespace Kokkos { namespace Impl { +namespace Kokkos { +namespace Impl { // ------------------------------------------------------------------ // -template< class DriverType > -__global__ -static void cuda_parallel_launch( const DriverType driver ) -{ +template +__global__ static void cuda_parallel_launch(const DriverType driver) { driver(); } -template< class DriverType > -struct CudaLaunch -{ - inline - CudaLaunch( const DriverType & driver - , const dim3 & grid - , const dim3 & block - ) - { - cuda_parallel_launch< DriverType ><<< grid , block >>>(driver); +template +struct CudaLaunch { + inline CudaLaunch(const DriverType& driver, const dim3& grid, + const dim3& block) { + cuda_parallel_launch<<>>(driver); } - }; // ------------------------------------------------------------------ // -template< int N , typename RP , typename Functor , typename Tag > +template struct apply_impl; -//Rank 2 +// Rank 2 // Specializations for void tag type -template< typename RP , typename Functor > -struct apply_impl<2,RP,Functor,void > -{ +template +struct apply_impl<2, RP, Functor, void> { using index_type = typename RP::index_type; - __device__ - apply_impl( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} - - inline __device__ - void exec_range() const - { -// LL - if (RP::inner_direction == RP::Left) { - for ( index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0] ) { - m_func(offset_0 , offset_1); + __device__ apply_impl(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} + + inline __device__ void exec_range() const { + // LL + if (RP::inner_direction == RP::Left) { + for (index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; + tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; + tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0]) { + m_func(offset_0, offset_1); + } } } } } - } -// LR - else { - for ( index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0] ) { - - for ( index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1] ) { - m_func(offset_0 , offset_1); + // LR + else { + for (index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; + tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0]) { + for (index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; + tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1]) { + m_func(offset_0, offset_1); + } } } } } - } - - } //end exec_range -private: - const RP & m_rp; - const Functor & m_func; + } // end exec_range + private: + const RP& m_rp; + const Functor& m_func; }; // Specializations for tag type -template< typename RP , typename Functor , typename Tag > -struct apply_impl<2,RP,Functor,Tag> -{ +template +struct apply_impl<2, RP, Functor, Tag> { using index_type = typename RP::index_type; - inline __device__ - apply_impl( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} - - inline __device__ - void exec_range() const - { - if (RP::inner_direction == RP::Left) { - // Loop over size maxnumblocks until full range covered - for ( index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0] ) { - m_func(Tag(), offset_0 , offset_1); + inline __device__ apply_impl(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} + + inline __device__ void exec_range() const { + if (RP::inner_direction == RP::Left) { + // Loop over size maxnumblocks until full range covered + for (index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; + tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; + tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0]) { + m_func(Tag(), offset_0, offset_1); + } } } } - } - } - else { - for ( index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0] ) { - - for ( index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1] ) { - m_func(Tag(), offset_0 , offset_1); + } else { + for (index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; + tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0]) { + for (index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; + tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1]) { + m_func(Tag(), offset_0, offset_1); + } } } } } - } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; - -//Rank 3 +// Rank 3 // Specializations for void tag type -template< typename RP , typename Functor > -struct apply_impl<3,RP,Functor,void > -{ +template +struct apply_impl<3, RP, Functor, void> { using index_type = typename RP::index_type; - __device__ - apply_impl( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ apply_impl(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} - inline __device__ - void exec_range() const - { -// LL + inline __device__ void exec_range() const { + // LL if (RP::inner_direction == RP::Left) { - for ( index_type tile_id2 = blockIdx.z; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && threadIdx.z < m_rp.m_tile[2] ) { - - for ( index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0] ) { - m_func(offset_0 , offset_1 , offset_2); + for (index_type tile_id2 = blockIdx.z; tile_id2 < m_rp.m_tile_end[2]; + tile_id2 += gridDim.z) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && threadIdx.z < m_rp.m_tile[2]) { + for (index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; + tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id0 = blockIdx.x; + tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + threadIdx.x < m_rp.m_tile[0]) { + m_func(offset_0, offset_1, offset_2); } } } @@ -237,83 +239,100 @@ struct apply_impl<3,RP,Functor,void > } } } -// LR - else { - for ( index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0] ) { - - for ( index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id2 = blockIdx.z; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && threadIdx.z < m_rp.m_tile[2] ) { - m_func(offset_0 , offset_1 , offset_2); + // LR + else { + for (index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; + tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0]) { + for (index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; + tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id2 = blockIdx.z; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + threadIdx.z < m_rp.m_tile[2]) { + m_func(offset_0, offset_1, offset_2); + } } } } } } } - } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; // Specializations for void tag type -template< typename RP , typename Functor , typename Tag > -struct apply_impl<3,RP,Functor,Tag> -{ +template +struct apply_impl<3, RP, Functor, Tag> { using index_type = typename RP::index_type; - inline __device__ - apply_impl( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + inline __device__ apply_impl(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} - inline __device__ - void exec_range() const - { + inline __device__ void exec_range() const { if (RP::inner_direction == RP::Left) { - for ( index_type tile_id2 = blockIdx.z; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && threadIdx.z < m_rp.m_tile[2] ) { - - for ( index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0] ) { - m_func(Tag(), offset_0 , offset_1 , offset_2); + for (index_type tile_id2 = blockIdx.z; tile_id2 < m_rp.m_tile_end[2]; + tile_id2 += gridDim.z) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && threadIdx.z < m_rp.m_tile[2]) { + for (index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; + tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id0 = blockIdx.x; + tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + threadIdx.x < m_rp.m_tile[0]) { + m_func(Tag(), offset_0, offset_1, offset_2); } } } } } } - } - else { - for ( index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0] ) { - - for ( index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id2 = blockIdx.z; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && threadIdx.z < m_rp.m_tile[2] ) { - m_func(Tag(), offset_0 , offset_1 , offset_2); + } else { + for (index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; + tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0]) { + for (index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; + tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id2 = blockIdx.z; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + threadIdx.z < m_rp.m_tile[2]) { + m_func(Tag(), offset_0, offset_1, offset_2); } } } @@ -322,61 +341,64 @@ struct apply_impl<3,RP,Functor,Tag> } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; - -//Rank 4 +// Rank 4 // Specializations for void tag type -template< typename RP , typename Functor > -struct apply_impl<4,RP,Functor,void > -{ +template +struct apply_impl<4, RP, Functor, void> { using index_type = typename RP::index_type; - __device__ - apply_impl( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ apply_impl(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - inline __device__ - void exec_range() const - { -// LL + inline __device__ void exec_range() const { + // LL if (RP::inner_direction == RP::Left) { - const index_type temp0 = m_rp.m_tile_end[0]; - const index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + const index_type temp0 = m_rp.m_tile_end[0]; + const index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = blockIdx.x % numbl0; const index_type tile_id1 = blockIdx.x / numbl0; - const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; - - for ( index_type tile_id3 = blockIdx.z; tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z ) { - const index_type offset_3 = tile_id3*m_rp.m_tile[3] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && threadIdx.z < m_rp.m_tile[3] ) { - - for ( index_type tile_id2 = blockIdx.y; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && threadIdx.y < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1 ; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0 ; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3); + const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; + + for (index_type tile_id3 = blockIdx.z; tile_id3 < m_rp.m_tile_end[3]; + tile_id3 += gridDim.z) { + const index_type offset_3 = tile_id3 * m_rp.m_tile[3] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && threadIdx.z < m_rp.m_tile[3]) { + for (index_type tile_id2 = blockIdx.y; tile_id2 < m_rp.m_tile_end[2]; + tile_id2 += gridDim.y) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && threadIdx.y < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = i * m_rp.m_tile[0] + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(offset_0, offset_1, offset_2, offset_3); } } } @@ -386,35 +408,44 @@ struct apply_impl<4,RP,Functor,void > } } } -// LR + // LR else { - const index_type temp0 = m_rp.m_tile_end[0]; - const index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + const index_type temp0 = m_rp.m_tile_end[0]; + const index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = blockIdx.x / numbl1; const index_type tile_id1 = blockIdx.x % numbl1; - const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type tile_id2 = blockIdx.y; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && threadIdx.y < m_rp.m_tile[2] ) { - - for ( index_type tile_id3 = blockIdx.z; tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z ) { - const index_type offset_3 = tile_id3*m_rp.m_tile[3] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && threadIdx.z < m_rp.m_tile[3] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3); + const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type tile_id2 = blockIdx.y; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + threadIdx.y < m_rp.m_tile[2]) { + for (index_type tile_id3 = blockIdx.z; + tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z) { + const index_type offset_3 = tile_id3 * m_rp.m_tile[3] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + threadIdx.z < m_rp.m_tile[3]) { + m_func(offset_0, offset_1, offset_2, offset_3); } } } @@ -425,58 +456,62 @@ struct apply_impl<4,RP,Functor,void > } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; // Specializations for void tag type -template< typename RP , typename Functor , typename Tag > -struct apply_impl<4,RP,Functor,Tag> -{ +template +struct apply_impl<4, RP, Functor, Tag> { using index_type = typename RP::index_type; - inline __device__ - apply_impl( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + inline __device__ apply_impl(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - inline __device__ - void exec_range() const - { + inline __device__ void exec_range() const { if (RP::inner_direction == RP::Left) { - const index_type temp0 = m_rp.m_tile_end[0]; - const index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + const index_type temp0 = m_rp.m_tile_end[0]; + const index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = blockIdx.x % numbl0; const index_type tile_id1 = blockIdx.x / numbl0; - const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; - - for ( index_type tile_id3 = blockIdx.z; tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z ) { - const index_type offset_3 = tile_id3*m_rp.m_tile[3] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && threadIdx.z < m_rp.m_tile[3] ) { - - for ( index_type tile_id2 = blockIdx.y; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && threadIdx.y < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(Tag(), offset_0 , offset_1 , offset_2 , offset_3); + const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; + + for (index_type tile_id3 = blockIdx.z; tile_id3 < m_rp.m_tile_end[3]; + tile_id3 += gridDim.z) { + const index_type offset_3 = tile_id3 * m_rp.m_tile[3] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && threadIdx.z < m_rp.m_tile[3]) { + for (index_type tile_id2 = blockIdx.y; tile_id2 < m_rp.m_tile_end[2]; + tile_id2 += gridDim.y) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && threadIdx.y < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = i * m_rp.m_tile[0] + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(Tag(), offset_0, offset_1, offset_2, offset_3); } } } @@ -485,35 +520,43 @@ struct apply_impl<4,RP,Functor,Tag> } } } - } - else { - const index_type temp0 = m_rp.m_tile_end[0]; - const index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + } else { + const index_type temp0 = m_rp.m_tile_end[0]; + const index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = blockIdx.x / numbl1; const index_type tile_id1 = blockIdx.x % numbl1; - const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type tile_id2 = blockIdx.y; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && threadIdx.y < m_rp.m_tile[2] ) { - - for ( index_type tile_id3 = blockIdx.z; tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z ) { - const index_type offset_3 = tile_id3*m_rp.m_tile[3] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && threadIdx.z < m_rp.m_tile[3] ) { - m_func(Tag() , offset_0 , offset_1 , offset_2 , offset_3); + const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + thr_id1 + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type tile_id2 = blockIdx.y; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + threadIdx.y < m_rp.m_tile[2]) { + for (index_type tile_id3 = blockIdx.z; + tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z) { + const index_type offset_3 = tile_id3 * m_rp.m_tile[3] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + threadIdx.z < m_rp.m_tile[3]) { + m_func(Tag(), offset_0, offset_1, offset_2, offset_3); } } } @@ -524,77 +567,83 @@ struct apply_impl<4,RP,Functor,Tag> } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; - -//Rank 5 +// Rank 5 // Specializations for void tag type -template< typename RP , typename Functor > -struct apply_impl<5,RP,Functor,void > -{ +template +struct apply_impl<5, RP, Functor, void> { using index_type = typename RP::index_type; - __device__ - apply_impl( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ apply_impl(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - inline __device__ - void exec_range() const - { -// LL + inline __device__ void exec_range() const { + // LL if (RP::inner_direction == RP::Left) { - - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = blockIdx.x % numbl0; const index_type tile_id1 = blockIdx.x / numbl0; - const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; + const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl2 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl3 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl2 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl2 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl3 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl2) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id2 = blockIdx.y % numbl2; const index_type tile_id3 = blockIdx.y / numbl2; - const index_type thr_id2 = threadIdx.y % m_rp.m_tile[2]; - const index_type thr_id3 = threadIdx.y / m_rp.m_tile[2]; - - for ( index_type tile_id4 = blockIdx.z; tile_id4 < m_rp.m_tile_end[4]; tile_id4 += gridDim.z ) { - const index_type offset_4 = tile_id4*m_rp.m_tile[4] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && threadIdx.z < m_rp.m_tile[4] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1 ; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0 ; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3, offset_4); + const index_type thr_id2 = threadIdx.y % m_rp.m_tile[2]; + const index_type thr_id3 = threadIdx.y / m_rp.m_tile[2]; + + for (index_type tile_id4 = blockIdx.z; tile_id4 < m_rp.m_tile_end[4]; + tile_id4 += gridDim.z) { + const index_type offset_4 = tile_id4 * m_rp.m_tile[4] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && threadIdx.z < m_rp.m_tile[4]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3) { + const index_type offset_3 = + l * m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = j * m_rp.m_tile[1] + thr_id1 + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = i * m_rp.m_tile[0] + + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(offset_0, offset_1, offset_2, offset_3, + offset_4); } } } @@ -606,50 +655,63 @@ struct apply_impl<5,RP,Functor,void > } } } -// LR + // LR else { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = blockIdx.x / numbl1; const index_type tile_id1 = blockIdx.x % numbl1; - const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; + const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl3 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl2 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl3 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl3 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl2 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl3) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id2 = blockIdx.y / numbl3; const index_type tile_id3 = blockIdx.y % numbl3; - const index_type thr_id2 = threadIdx.y / m_rp.m_tile[3]; - const index_type thr_id3 = threadIdx.y % m_rp.m_tile[3]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type tile_id4 = blockIdx.z; tile_id4 < m_rp.m_tile_end[4]; tile_id4 += gridDim.z ) { - const index_type offset_4 = tile_id4*m_rp.m_tile[4] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && threadIdx.z < m_rp.m_tile[4] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3 , offset_4); + const index_type thr_id2 = threadIdx.y / m_rp.m_tile[3]; + const index_type thr_id3 = threadIdx.y % m_rp.m_tile[3]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = l * m_rp.m_tile[3] + thr_id3 + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + thr_id3 < m_rp.m_tile[3]) { + for (index_type tile_id4 = blockIdx.z; + tile_id4 < m_rp.m_tile_end[4]; + tile_id4 += gridDim.z) { + const index_type offset_4 = tile_id4 * m_rp.m_tile[4] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && + threadIdx.z < m_rp.m_tile[4]) { + m_func(offset_0, offset_1, offset_2, offset_3, + offset_4); } } } @@ -662,74 +724,82 @@ struct apply_impl<5,RP,Functor,void > } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; // Specializations for tag type -template< typename RP , typename Functor , typename Tag > -struct apply_impl<5,RP,Functor,Tag> -{ +template +struct apply_impl<5, RP, Functor, Tag> { using index_type = typename RP::index_type; - __device__ - apply_impl( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ apply_impl(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - inline __device__ - void exec_range() const - { -// LL + inline __device__ void exec_range() const { + // LL if (RP::inner_direction == RP::Left) { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = blockIdx.x % numbl0; const index_type tile_id1 = blockIdx.x / numbl0; - const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; + const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl2 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl3 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl2 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl2 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl3 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl2) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id2 = blockIdx.y % numbl2; const index_type tile_id3 = blockIdx.y / numbl2; - const index_type thr_id2 = threadIdx.y % m_rp.m_tile[2]; - const index_type thr_id3 = threadIdx.y / m_rp.m_tile[2]; - - for ( index_type tile_id4 = blockIdx.z; tile_id4 < m_rp.m_tile_end[4]; tile_id4 += gridDim.z ) { - const index_type offset_4 = tile_id4*m_rp.m_tile[4] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && threadIdx.z < m_rp.m_tile[4] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1 ; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0 ; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(Tag() , offset_0 , offset_1 , offset_2 , offset_3, offset_4); + const index_type thr_id2 = threadIdx.y % m_rp.m_tile[2]; + const index_type thr_id3 = threadIdx.y / m_rp.m_tile[2]; + + for (index_type tile_id4 = blockIdx.z; tile_id4 < m_rp.m_tile_end[4]; + tile_id4 += gridDim.z) { + const index_type offset_4 = tile_id4 * m_rp.m_tile[4] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && threadIdx.z < m_rp.m_tile[4]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3) { + const index_type offset_3 = + l * m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = j * m_rp.m_tile[1] + thr_id1 + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = i * m_rp.m_tile[0] + + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(Tag(), offset_0, offset_1, offset_2, offset_3, + offset_4); } } } @@ -741,50 +811,63 @@ struct apply_impl<5,RP,Functor,Tag> } } } -// LR + // LR else { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = blockIdx.x / numbl1; const index_type tile_id1 = blockIdx.x % numbl1; - const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; + const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl3 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl2 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl3 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl3 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl2 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl3) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id2 = blockIdx.y / numbl3; const index_type tile_id3 = blockIdx.y % numbl3; - const index_type thr_id2 = threadIdx.y / m_rp.m_tile[3]; - const index_type thr_id3 = threadIdx.y % m_rp.m_tile[3]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type tile_id4 = blockIdx.z; tile_id4 < m_rp.m_tile_end[4]; tile_id4 += gridDim.z ) { - const index_type offset_4 = tile_id4*m_rp.m_tile[4] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && threadIdx.z < m_rp.m_tile[4] ) { - m_func(Tag() , offset_0 , offset_1 , offset_2 , offset_3 , offset_4); + const index_type thr_id2 = threadIdx.y / m_rp.m_tile[3]; + const index_type thr_id3 = threadIdx.y % m_rp.m_tile[3]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = l * m_rp.m_tile[3] + thr_id3 + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + thr_id3 < m_rp.m_tile[3]) { + for (index_type tile_id4 = blockIdx.z; + tile_id4 < m_rp.m_tile_end[4]; + tile_id4 += gridDim.z) { + const index_type offset_4 = tile_id4 * m_rp.m_tile[4] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && + threadIdx.z < m_rp.m_tile[4]) { + m_func(Tag(), offset_0, offset_1, offset_2, offset_3, + offset_4); } } } @@ -797,91 +880,101 @@ struct apply_impl<5,RP,Functor,Tag> } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; - -//Rank 6 +// Rank 6 // Specializations for void tag type -template< typename RP , typename Functor > -struct apply_impl<6,RP,Functor,void > -{ +template +struct apply_impl<6, RP, Functor, void> { using index_type = typename RP::index_type; - __device__ - apply_impl( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ apply_impl(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - inline __device__ - void exec_range() const - { -// LL + inline __device__ void exec_range() const { + // LL if (RP::inner_direction == RP::Left) { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = blockIdx.x % numbl0; const index_type tile_id1 = blockIdx.x / numbl0; - const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; + const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl2 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl3 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl2 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl2 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl3 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl2) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id2 = blockIdx.y % numbl2; const index_type tile_id3 = blockIdx.y / numbl2; - const index_type thr_id2 = threadIdx.y % m_rp.m_tile[2]; - const index_type thr_id3 = threadIdx.y / m_rp.m_tile[2]; + const index_type thr_id2 = threadIdx.y % m_rp.m_tile[2]; + const index_type thr_id3 = threadIdx.y / m_rp.m_tile[2]; - temp0 = m_rp.m_tile_end[4]; - temp1 = m_rp.m_tile_end[5]; - const index_type numbl4 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl5 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl4 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[4]; + temp1 = m_rp.m_tile_end[5]; + const index_type numbl4 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl5 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl4) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id4 = blockIdx.z % numbl4; const index_type tile_id5 = blockIdx.z / numbl4; - const index_type thr_id4 = threadIdx.z % m_rp.m_tile[4]; - const index_type thr_id5 = threadIdx.z / m_rp.m_tile[4]; - - for ( index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5 ) { - const index_type offset_5 = n*m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; - if ( offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5] ) { - - for ( index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4 ) { - const index_type offset_4 = m*m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1 ; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0 ; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3, offset_4, offset_5); + const index_type thr_id4 = threadIdx.z % m_rp.m_tile[4]; + const index_type thr_id5 = threadIdx.z / m_rp.m_tile[4]; + + for (index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5) { + const index_type offset_5 = + n * m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; + if (offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5]) { + for (index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4) { + const index_type offset_4 = + m * m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = + l * m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = k * m_rp.m_tile[2] + thr_id2 + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + thr_id2 < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = j * m_rp.m_tile[1] + + thr_id1 + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(offset_0, offset_1, offset_2, offset_3, + offset_4, offset_5); } } } @@ -895,65 +988,82 @@ struct apply_impl<6,RP,Functor,void > } } } -// LR + // LR else { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = blockIdx.x / numbl1; const index_type tile_id1 = blockIdx.x % numbl1; - const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; + const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl3 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl2 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl3 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl3 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl2 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl3) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id2 = blockIdx.y / numbl3; const index_type tile_id3 = blockIdx.y % numbl3; - const index_type thr_id2 = threadIdx.y / m_rp.m_tile[3]; - const index_type thr_id3 = threadIdx.y % m_rp.m_tile[3]; + const index_type thr_id2 = threadIdx.y / m_rp.m_tile[3]; + const index_type thr_id3 = threadIdx.y % m_rp.m_tile[3]; - temp0 = m_rp.m_tile_end[4]; - temp1 = m_rp.m_tile_end[5]; - const index_type numbl5 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl4 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl5 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[4]; + temp1 = m_rp.m_tile_end[5]; + const index_type numbl5 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl4 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl5) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id4 = blockIdx.z / numbl5; const index_type tile_id5 = blockIdx.z % numbl5; - const index_type thr_id4 = threadIdx.z / m_rp.m_tile[5]; - const index_type thr_id5 = threadIdx.z % m_rp.m_tile[5]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4 ) { - const index_type offset_4 = m*m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4] ) { - - for ( index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5 ) { - const index_type offset_5 = n*m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; - if ( offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3 , offset_4 , offset_5); + const index_type thr_id4 = threadIdx.z / m_rp.m_tile[5]; + const index_type thr_id5 = threadIdx.z % m_rp.m_tile[5]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = l * m_rp.m_tile[3] + thr_id3 + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + thr_id3 < m_rp.m_tile[3]) { + for (index_type m = tile_id4; m < m_rp.m_tile_end[4]; + m += numbl4) { + const index_type offset_4 = m * m_rp.m_tile[4] + + thr_id4 + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && + thr_id4 < m_rp.m_tile[4]) { + for (index_type n = tile_id5; n < m_rp.m_tile_end[5]; + n += numbl5) { + const index_type offset_5 = + n * m_rp.m_tile[5] + thr_id5 + + (index_type)m_rp.m_lower[5]; + if (offset_5 < m_rp.m_upper[5] && + thr_id5 < m_rp.m_tile[5]) { + m_func(offset_0, offset_1, offset_2, offset_3, + offset_4, offset_5); } } } @@ -968,89 +1078,100 @@ struct apply_impl<6,RP,Functor,void > } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; // Specializations for tag type -template< typename RP , typename Functor , typename Tag > -struct apply_impl<6,RP,Functor,Tag> -{ +template +struct apply_impl<6, RP, Functor, Tag> { using index_type = typename RP::index_type; - __device__ - apply_impl( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ apply_impl(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - inline __device__ - void exec_range() const - { -// LL + inline __device__ void exec_range() const { + // LL if (RP::inner_direction == RP::Left) { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = blockIdx.x % numbl0; const index_type tile_id1 = blockIdx.x / numbl0; - const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; + const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl2 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl3 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl2 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl2 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl3 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl2) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id2 = blockIdx.y % numbl2; const index_type tile_id3 = blockIdx.y / numbl2; - const index_type thr_id2 = threadIdx.y % m_rp.m_tile[2]; - const index_type thr_id3 = threadIdx.y / m_rp.m_tile[2]; + const index_type thr_id2 = threadIdx.y % m_rp.m_tile[2]; + const index_type thr_id3 = threadIdx.y / m_rp.m_tile[2]; - temp0 = m_rp.m_tile_end[4]; - temp1 = m_rp.m_tile_end[5]; - const index_type numbl4 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl5 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl4 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[4]; + temp1 = m_rp.m_tile_end[5]; + const index_type numbl4 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl5 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl4) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id4 = blockIdx.z % numbl4; const index_type tile_id5 = blockIdx.z / numbl4; - const index_type thr_id4 = threadIdx.z % m_rp.m_tile[4]; - const index_type thr_id5 = threadIdx.z / m_rp.m_tile[4]; - - for ( index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5 ) { - const index_type offset_5 = n*m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; - if ( offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5] ) { - - for ( index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4 ) { - const index_type offset_4 = m*m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1 ; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0 ; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(Tag() , offset_0 , offset_1 , offset_2 , offset_3, offset_4, offset_5); + const index_type thr_id4 = threadIdx.z % m_rp.m_tile[4]; + const index_type thr_id5 = threadIdx.z / m_rp.m_tile[4]; + + for (index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5) { + const index_type offset_5 = + n * m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; + if (offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5]) { + for (index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4) { + const index_type offset_4 = + m * m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = + l * m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = k * m_rp.m_tile[2] + thr_id2 + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + thr_id2 < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = j * m_rp.m_tile[1] + + thr_id1 + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(Tag(), offset_0, offset_1, offset_2, + offset_3, offset_4, offset_5); } } } @@ -1064,65 +1185,82 @@ struct apply_impl<6,RP,Functor,Tag> } } } -// LR + // LR else { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = blockIdx.x / numbl1; const index_type tile_id1 = blockIdx.x % numbl1; - const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; + const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl3 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl2 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl3 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl3 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl2 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl3) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id2 = blockIdx.y / numbl3; const index_type tile_id3 = blockIdx.y % numbl3; - const index_type thr_id2 = threadIdx.y / m_rp.m_tile[3]; - const index_type thr_id3 = threadIdx.y % m_rp.m_tile[3]; + const index_type thr_id2 = threadIdx.y / m_rp.m_tile[3]; + const index_type thr_id3 = threadIdx.y % m_rp.m_tile[3]; - temp0 = m_rp.m_tile_end[4]; - temp1 = m_rp.m_tile_end[5]; - const index_type numbl5 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl4 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl5 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[4]; + temp1 = m_rp.m_tile_end[5]; + const index_type numbl5 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl4 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl5) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id4 = blockIdx.z / numbl5; const index_type tile_id5 = blockIdx.z % numbl5; - const index_type thr_id4 = threadIdx.z / m_rp.m_tile[5]; - const index_type thr_id5 = threadIdx.z % m_rp.m_tile[5]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4 ) { - const index_type offset_4 = m*m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4] ) { - - for ( index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5 ) { - const index_type offset_5 = n*m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; - if ( offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5] ) { - m_func(Tag() , offset_0 , offset_1 , offset_2 , offset_3 , offset_4 , offset_5); + const index_type thr_id4 = threadIdx.z / m_rp.m_tile[5]; + const index_type thr_id5 = threadIdx.z % m_rp.m_tile[5]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = l * m_rp.m_tile[3] + thr_id3 + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + thr_id3 < m_rp.m_tile[3]) { + for (index_type m = tile_id4; m < m_rp.m_tile_end[4]; + m += numbl4) { + const index_type offset_4 = m * m_rp.m_tile[4] + + thr_id4 + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && + thr_id4 < m_rp.m_tile[4]) { + for (index_type n = tile_id5; n < m_rp.m_tile_end[5]; + n += numbl5) { + const index_type offset_5 = + n * m_rp.m_tile[5] + thr_id5 + + (index_type)m_rp.m_lower[5]; + if (offset_5 < m_rp.m_upper[5] && + thr_id5 < m_rp.m_tile[5]) { + m_func(Tag(), offset_0, offset_1, offset_2, + offset_3, offset_4, offset_5); } } } @@ -1137,127 +1275,118 @@ struct apply_impl<6,RP,Functor,Tag> } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; // ---------------------------------------------------------------------------------- -template < typename RP - , typename Functor - , typename Tag - > -struct DeviceIterateTile -{ - using index_type = typename RP::index_type; +template +struct DeviceIterateTile { + using index_type = typename RP::index_type; using array_index_type = typename RP::array_index_type; - using point_type = typename RP::point_type; + using point_type = typename RP::point_type; struct VoidDummy {}; - typedef typename std::conditional< std::is_same::value, VoidDummy, Tag>::type usable_tag; - - DeviceIterateTile( const RP & rp, const Functor & func ) - : m_rp{rp} - , m_func{func} - {} - -private: - inline __device__ - void apply() const - { - apply_impl(m_rp,m_func).exec_range(); - } //end apply - -public: - - inline - __device__ - void operator()(void) const - { - this-> apply(); - } + typedef typename std::conditional::value, VoidDummy, + Tag>::type usable_tag; + + DeviceIterateTile(const RP& rp, const Functor& func) + : m_rp{rp}, m_func{func} {} + + private: + inline __device__ void apply() const { + apply_impl(m_rp, m_func).exec_range(); + } // end apply + + public: + inline __device__ void operator()(void) const { this->apply(); } - inline - void execute() const - { - const array_index_type maxblocks = 65535; //not true for blockIdx.x for newer archs - if ( RP::rank == 2 ) - { - const dim3 block( m_rp.m_tile[0] , m_rp.m_tile[1] , 1); + inline void execute() const { + const array_index_type maxblocks = + 65535; // not true for blockIdx.x for newer archs + if (RP::rank == 2) { + const dim3 block(m_rp.m_tile[0], m_rp.m_tile[1], 1); const dim3 grid( - std::min( ( m_rp.m_upper[0] - m_rp.m_lower[0] + block.x - 1 ) / block.x , maxblocks ) - , std::min( ( m_rp.m_upper[1] - m_rp.m_lower[1] + block.y - 1 ) / block.y , maxblocks ) - , 1 - ); - CudaLaunch< DeviceIterateTile >( *this , grid , block ); - } - else if ( RP::rank == 3 ) - { - const dim3 block( m_rp.m_tile[0] , m_rp.m_tile[1] , m_rp.m_tile[2] ); + std::min((m_rp.m_upper[0] - m_rp.m_lower[0] + block.x - 1) / block.x, + maxblocks), + std::min((m_rp.m_upper[1] - m_rp.m_lower[1] + block.y - 1) / block.y, + maxblocks), + 1); + CudaLaunch(*this, grid, block); + } else if (RP::rank == 3) { + const dim3 block(m_rp.m_tile[0], m_rp.m_tile[1], m_rp.m_tile[2]); const dim3 grid( - std::min( ( m_rp.m_upper[0] - m_rp.m_lower[0] + block.x - 1 ) / block.x , maxblocks ) - , std::min( ( m_rp.m_upper[1] - m_rp.m_lower[1] + block.y - 1 ) / block.y , maxblocks ) - , std::min( ( m_rp.m_upper[2] - m_rp.m_lower[2] + block.z - 1 ) / block.z , maxblocks ) - ); - CudaLaunch< DeviceIterateTile >( *this , grid , block ); - } - else if ( RP::rank == 4 ) - { - // id0,id1 encoded within threadIdx.x; id2 to threadIdx.y; id3 to threadIdx.z - const dim3 block( m_rp.m_tile[0]*m_rp.m_tile[1] , m_rp.m_tile[2] , m_rp.m_tile[3] ); + std::min((m_rp.m_upper[0] - m_rp.m_lower[0] + block.x - 1) / block.x, + maxblocks), + std::min((m_rp.m_upper[1] - m_rp.m_lower[1] + block.y - 1) / block.y, + maxblocks), + std::min((m_rp.m_upper[2] - m_rp.m_lower[2] + block.z - 1) / block.z, + maxblocks)); + CudaLaunch(*this, grid, block); + } else if (RP::rank == 4) { + // id0,id1 encoded within threadIdx.x; id2 to threadIdx.y; id3 to + // threadIdx.z + const dim3 block(m_rp.m_tile[0] * m_rp.m_tile[1], m_rp.m_tile[2], + m_rp.m_tile[3]); const dim3 grid( - std::min( static_cast( m_rp.m_tile_end[0] * m_rp.m_tile_end[1] ) - , static_cast(maxblocks) ) - , std::min( ( m_rp.m_upper[2] - m_rp.m_lower[2] + block.y - 1 ) / block.y , maxblocks ) - , std::min( ( m_rp.m_upper[3] - m_rp.m_lower[3] + block.z - 1 ) / block.z , maxblocks ) - ); - CudaLaunch< DeviceIterateTile >( *this , grid , block ); - } - else if ( RP::rank == 5 ) - { - // id0,id1 encoded within threadIdx.x; id2,id3 to threadIdx.y; id4 to threadIdx.z - const dim3 block( m_rp.m_tile[0]*m_rp.m_tile[1] , m_rp.m_tile[2]*m_rp.m_tile[3] , m_rp.m_tile[4] ); + std::min( + static_cast(m_rp.m_tile_end[0] * m_rp.m_tile_end[1]), + static_cast(maxblocks)), + std::min((m_rp.m_upper[2] - m_rp.m_lower[2] + block.y - 1) / block.y, + maxblocks), + std::min((m_rp.m_upper[3] - m_rp.m_lower[3] + block.z - 1) / block.z, + maxblocks)); + CudaLaunch(*this, grid, block); + } else if (RP::rank == 5) { + // id0,id1 encoded within threadIdx.x; id2,id3 to threadIdx.y; id4 to + // threadIdx.z + const dim3 block(m_rp.m_tile[0] * m_rp.m_tile[1], + m_rp.m_tile[2] * m_rp.m_tile[3], m_rp.m_tile[4]); const dim3 grid( - std::min( static_cast( m_rp.m_tile_end[0] * m_rp.m_tile_end[1] ) - , static_cast(maxblocks) ) - , std::min( static_cast( m_rp.m_tile_end[2] * m_rp.m_tile_end[3] ) - , static_cast(maxblocks) ) - , std::min( ( m_rp.m_upper[4] - m_rp.m_lower[4] + block.z - 1 ) / block.z , maxblocks ) - ); - CudaLaunch< DeviceIterateTile >( *this , grid , block ); - } - else if ( RP::rank == 6 ) - { - // id0,id1 encoded within threadIdx.x; id2,id3 to threadIdx.y; id4,id5 to threadIdx.z - const dim3 block( m_rp.m_tile[0]*m_rp.m_tile[1] , m_rp.m_tile[2]*m_rp.m_tile[3] , m_rp.m_tile[4]*m_rp.m_tile[5] ); + std::min( + static_cast(m_rp.m_tile_end[0] * m_rp.m_tile_end[1]), + static_cast(maxblocks)), + std::min( + static_cast(m_rp.m_tile_end[2] * m_rp.m_tile_end[3]), + static_cast(maxblocks)), + std::min((m_rp.m_upper[4] - m_rp.m_lower[4] + block.z - 1) / block.z, + maxblocks)); + CudaLaunch(*this, grid, block); + } else if (RP::rank == 6) { + // id0,id1 encoded within threadIdx.x; id2,id3 to threadIdx.y; id4,id5 to + // threadIdx.z + const dim3 block(m_rp.m_tile[0] * m_rp.m_tile[1], + m_rp.m_tile[2] * m_rp.m_tile[3], + m_rp.m_tile[4] * m_rp.m_tile[5]); const dim3 grid( - std::min( static_cast( m_rp.m_tile_end[0] * m_rp.m_tile_end[1] ) - , static_cast(maxblocks) ) - , std::min( static_cast( m_rp.m_tile_end[2] * m_rp.m_tile_end[3] ) - , static_cast(maxblocks) ) - , std::min( static_cast( m_rp.m_tile_end[4] * m_rp.m_tile_end[5] ) - , static_cast(maxblocks) ) - ); - CudaLaunch< DeviceIterateTile >( *this , grid , block ); - } - else - { + std::min( + static_cast(m_rp.m_tile_end[0] * m_rp.m_tile_end[1]), + static_cast(maxblocks)), + std::min( + static_cast(m_rp.m_tile_end[2] * m_rp.m_tile_end[3]), + static_cast(maxblocks)), + std::min( + static_cast(m_rp.m_tile_end[4] * m_rp.m_tile_end[5]), + static_cast(maxblocks))); + CudaLaunch(*this, grid, block); + } else { printf("Kokkos::MDRange Error: Exceeded rank bounds with Cuda\n"); Kokkos::abort("Aborting"); } - } //end execute + } // end execute -protected: - const RP m_rp; - const Functor m_func; + protected: + const RP m_rp; + const Functor m_func; }; -} } //end namespace Kokkos::Impl +} // namespace Impl +} // namespace Kokkos #endif #endif - diff --git a/lib/kokkos/core/src/Cuda/KokkosExp_Cuda_IterateTile_Refactor.hpp b/lib/kokkos/core/src/Cuda/KokkosExp_Cuda_IterateTile_Refactor.hpp index 636e05c8ac..cb7f5971ae 100644 --- a/lib/kokkos/core/src/Cuda/KokkosExp_Cuda_IterateTile_Refactor.hpp +++ b/lib/kokkos/core/src/Cuda/KokkosExp_Cuda_IterateTile_Refactor.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,7 +46,7 @@ #define KOKKOS_CUDA_EXP_ITERATE_TILE_REFACTOR_HPP #include -#if defined( __CUDACC__ ) && defined( KOKKOS_ENABLE_CUDA ) +#if defined(__CUDACC__) && defined(KOKKOS_ENABLE_CUDA) #include #include @@ -55,49 +56,52 @@ // #include // Including the file above leads to following type of errors: -// /home/ndellin/kokkos/core/src/Cuda/Kokkos_CudaExec.hpp(84): error: incomplete type is not allowed -// use existing Kokkos functionality, e.g. max blocks, once resolved +// /home/ndellin/kokkos/core/src/Cuda/Kokkos_CudaExec.hpp(84): error: incomplete +// type is not allowed use existing Kokkos functionality, e.g. max blocks, once +// resolved #if defined(KOKKOS_ENABLE_PROFILING) #include #include #endif -namespace Kokkos { namespace Impl { +namespace Kokkos { +namespace Impl { namespace Refactor { // ------------------------------------------------------------------ // // ParallelFor iteration pattern -template< int N , typename RP , typename Functor , typename Tag > +template struct DeviceIterateTile; -//Rank 2 +// Rank 2 // Specializations for void tag type -template< typename RP , typename Functor > -struct DeviceIterateTile<2,RP,Functor,void > -{ +template +struct DeviceIterateTile<2, RP, Functor, void> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} - inline __device__ - void exec_range() const - { + inline __device__ void exec_range() const { // LL if (RP::inner_direction == RP::Left) { - for ( index_type tile_id1 = (index_type)blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && (index_type)threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id0 = (index_type)blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && (index_type)threadIdx.x < m_rp.m_tile[0] ) { - m_func(offset_0 , offset_1); + for (index_type tile_id1 = (index_type)blockIdx.y; + tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + (index_type)threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id0 = (index_type)blockIdx.x; + tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + (index_type)threadIdx.x < m_rp.m_tile[0]) { + m_func(offset_0, offset_1); } } } @@ -105,108 +109,125 @@ struct DeviceIterateTile<2,RP,Functor,void > } // LR else { - for ( index_type tile_id0 = (index_type)blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && (index_type)threadIdx.x < m_rp.m_tile[0] ) { - - for ( index_type tile_id1 = (index_type)blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && (index_type)threadIdx.y < m_rp.m_tile[1] ) { - m_func(offset_0 , offset_1); + for (index_type tile_id0 = (index_type)blockIdx.x; + tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + (index_type)threadIdx.x < m_rp.m_tile[0]) { + for (index_type tile_id1 = (index_type)blockIdx.y; + tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + (index_type)threadIdx.y < m_rp.m_tile[1]) { + m_func(offset_0, offset_1); } } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; // Specializations for tag type -template< typename RP , typename Functor , typename Tag > -struct DeviceIterateTile<2,RP,Functor,Tag> -{ +template +struct DeviceIterateTile<2, RP, Functor, Tag> { using index_type = typename RP::index_type; - inline __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + inline __device__ DeviceIterateTile(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} - inline __device__ - void exec_range() const - { + inline __device__ void exec_range() const { if (RP::inner_direction == RP::Left) { // Loop over size maxnumblocks until full range covered - for ( index_type tile_id1 = (index_type)blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && (index_type)threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id0 = (index_type)blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && (index_type)threadIdx.x < m_rp.m_tile[0] ) { - m_func(Tag(), offset_0 , offset_1); + for (index_type tile_id1 = (index_type)blockIdx.y; + tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + (index_type)threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id0 = (index_type)blockIdx.x; + tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + (index_type)threadIdx.x < m_rp.m_tile[0]) { + m_func(Tag(), offset_0, offset_1); } } } } - } - else { - for ( index_type tile_id0 = (index_type)blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && (index_type)threadIdx.x < m_rp.m_tile[0] ) { - - for ( index_type tile_id1 = (index_type)blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && (index_type)threadIdx.y < m_rp.m_tile[1] ) { - m_func(Tag(), offset_0 , offset_1); + } else { + for (index_type tile_id0 = (index_type)blockIdx.x; + tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + (index_type)threadIdx.x < m_rp.m_tile[0]) { + for (index_type tile_id1 = (index_type)blockIdx.y; + tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + (index_type)threadIdx.y < m_rp.m_tile[1]) { + m_func(Tag(), offset_0, offset_1); } } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; - -//Rank 3 +// Rank 3 // Specializations for void tag type -template< typename RP , typename Functor > -struct DeviceIterateTile<3,RP,Functor,void > -{ +template +struct DeviceIterateTile<3, RP, Functor, void> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} - inline __device__ - void exec_range() const - { + inline __device__ void exec_range() const { // LL if (RP::inner_direction == RP::Left) { - for ( index_type tile_id2 = (index_type)blockIdx.z; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && (index_type)threadIdx.z < m_rp.m_tile[2] ) { - - for ( index_type tile_id1 = (index_type)blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && (index_type)threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id0 = (index_type)blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && (index_type)threadIdx.x < m_rp.m_tile[0] ) { - m_func(offset_0 , offset_1 , offset_2); + for (index_type tile_id2 = (index_type)blockIdx.z; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + (index_type)threadIdx.z < m_rp.m_tile[2]) { + for (index_type tile_id1 = (index_type)blockIdx.y; + tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + (index_type)threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id0 = (index_type)blockIdx.x; + tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + (index_type)threadIdx.x < m_rp.m_tile[0]) { + m_func(offset_0, offset_1, offset_2); } } } @@ -216,18 +237,28 @@ struct DeviceIterateTile<3,RP,Functor,void > } // LR else { - for ( index_type tile_id0 = (index_type)blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && (index_type)threadIdx.x < m_rp.m_tile[0] ) { - - for ( index_type tile_id1 = (index_type)blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && (index_type)threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id2 = (index_type)blockIdx.z; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && (index_type)threadIdx.z < m_rp.m_tile[2] ) { - m_func(offset_0 , offset_1 , offset_2); + for (index_type tile_id0 = (index_type)blockIdx.x; + tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + (index_type)threadIdx.x < m_rp.m_tile[0]) { + for (index_type tile_id1 = (index_type)blockIdx.y; + tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + (index_type)threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id2 = (index_type)blockIdx.z; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + (index_type)threadIdx.z < m_rp.m_tile[2]) { + m_func(offset_0, offset_1, offset_2); } } } @@ -235,61 +266,74 @@ struct DeviceIterateTile<3,RP,Functor,void > } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; // Specializations for void tag type -template< typename RP , typename Functor , typename Tag > -struct DeviceIterateTile<3,RP,Functor,Tag> -{ +template +struct DeviceIterateTile<3, RP, Functor, Tag> { using index_type = typename RP::index_type; - inline __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + inline __device__ DeviceIterateTile(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} - inline __device__ - void exec_range() const - { + inline __device__ void exec_range() const { if (RP::inner_direction == RP::Left) { - for ( index_type tile_id2 = (index_type)blockIdx.z; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && (index_type)threadIdx.z < m_rp.m_tile[2] ) { - - for ( index_type tile_id1 = (index_type)blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && (index_type)threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id0 = (index_type)blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && (index_type)threadIdx.x < m_rp.m_tile[0] ) { - m_func(Tag(), offset_0 , offset_1 , offset_2); + for (index_type tile_id2 = (index_type)blockIdx.z; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + (index_type)threadIdx.z < m_rp.m_tile[2]) { + for (index_type tile_id1 = (index_type)blockIdx.y; + tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + (index_type)threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id0 = (index_type)blockIdx.x; + tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + (index_type)threadIdx.x < m_rp.m_tile[0]) { + m_func(Tag(), offset_0, offset_1, offset_2); } } } } } } - } - else { - for ( index_type tile_id0 = (index_type)blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && (index_type)threadIdx.x < m_rp.m_tile[0] ) { - - for ( index_type tile_id1 = (index_type)blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && (index_type)threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id2 = (index_type)blockIdx.z; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && (index_type)threadIdx.z < m_rp.m_tile[2] ) { - m_func(Tag(), offset_0 , offset_1 , offset_2); + } else { + for (index_type tile_id0 = (index_type)blockIdx.x; + tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + (index_type)threadIdx.x < m_rp.m_tile[0]) { + for (index_type tile_id1 = (index_type)blockIdx.y; + tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + (index_type)threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id2 = (index_type)blockIdx.z; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + (index_type)threadIdx.z < m_rp.m_tile[2]) { + m_func(Tag(), offset_0, offset_1, offset_2); } } } @@ -297,64 +341,72 @@ struct DeviceIterateTile<3,RP,Functor,Tag> } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; - -//Rank 4 +// Rank 4 // Specializations for void tag type -template< typename RP , typename Functor > -struct DeviceIterateTile<4,RP,Functor,void > -{ +template +struct DeviceIterateTile<4, RP, Functor, void> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); // LL if (RP::inner_direction == RP::Left) { - const index_type temp0 = m_rp.m_tile_end[0]; - const index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + const index_type temp0 = m_rp.m_tile_end[0]; + const index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x % numbl0; const index_type tile_id1 = (index_type)blockIdx.x / numbl0; - const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; - - for ( index_type tile_id3 = (index_type)blockIdx.z; tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z ) { - const index_type offset_3 = tile_id3*m_rp.m_tile[3] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && (index_type)threadIdx.z < m_rp.m_tile[3] ) { - - for ( index_type tile_id2 = (index_type)blockIdx.y; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && (index_type)threadIdx.y < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1 ; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0 ; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3); + const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; + + for (index_type tile_id3 = (index_type)blockIdx.z; + tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z) { + const index_type offset_3 = tile_id3 * m_rp.m_tile[3] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + (index_type)threadIdx.z < m_rp.m_tile[3]) { + for (index_type tile_id2 = (index_type)blockIdx.y; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + (index_type)threadIdx.y < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = i * m_rp.m_tile[0] + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(offset_0, offset_1, offset_2, offset_3); } } } @@ -366,33 +418,42 @@ struct DeviceIterateTile<4,RP,Functor,void > } // LR else { - const index_type temp0 = m_rp.m_tile_end[0]; - const index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + const index_type temp0 = m_rp.m_tile_end[0]; + const index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x / numbl1; const index_type tile_id1 = (index_type)blockIdx.x % numbl1; - const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type tile_id2 = (index_type)blockIdx.y; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && (index_type)threadIdx.y < m_rp.m_tile[2] ) { - - for ( index_type tile_id3 = (index_type)blockIdx.z; tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z ) { - const index_type offset_3 = tile_id3*m_rp.m_tile[3] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && (index_type)threadIdx.z < m_rp.m_tile[3] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3); + const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type tile_id2 = (index_type)blockIdx.y; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + (index_type)threadIdx.y < m_rp.m_tile[2]) { + for (index_type tile_id3 = (index_type)blockIdx.z; + tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z) { + const index_type offset_3 = tile_id3 * m_rp.m_tile[3] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + (index_type)threadIdx.z < m_rp.m_tile[3]) { + m_func(offset_0, offset_1, offset_2, offset_3); } } } @@ -402,61 +463,70 @@ struct DeviceIterateTile<4,RP,Functor,void > } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; // Specializations for void tag type -template< typename RP , typename Functor , typename Tag > -struct DeviceIterateTile<4,RP,Functor,Tag> -{ +template +struct DeviceIterateTile<4, RP, Functor, Tag> { using index_type = typename RP::index_type; - inline __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + inline __device__ DeviceIterateTile(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); if (RP::inner_direction == RP::Left) { - const index_type temp0 = m_rp.m_tile_end[0]; - const index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + const index_type temp0 = m_rp.m_tile_end[0]; + const index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x % numbl0; const index_type tile_id1 = (index_type)blockIdx.x / numbl0; - const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; - - for ( index_type tile_id3 = (index_type)blockIdx.z; tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z ) { - const index_type offset_3 = tile_id3*m_rp.m_tile[3] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && (index_type)threadIdx.z < m_rp.m_tile[3] ) { - - for ( index_type tile_id2 = (index_type)blockIdx.y; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && (index_type)threadIdx.y < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(Tag(), offset_0 , offset_1 , offset_2 , offset_3); + const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; + + for (index_type tile_id3 = (index_type)blockIdx.z; + tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z) { + const index_type offset_3 = tile_id3 * m_rp.m_tile[3] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + (index_type)threadIdx.z < m_rp.m_tile[3]) { + for (index_type tile_id2 = (index_type)blockIdx.y; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + (index_type)threadIdx.y < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = i * m_rp.m_tile[0] + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(Tag(), offset_0, offset_1, offset_2, offset_3); } } } @@ -465,35 +535,43 @@ struct DeviceIterateTile<4,RP,Functor,Tag> } } } - } - else { - const index_type temp0 = m_rp.m_tile_end[0]; - const index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + } else { + const index_type temp0 = m_rp.m_tile_end[0]; + const index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x / numbl1; const index_type tile_id1 = (index_type)blockIdx.x % numbl1; - const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type tile_id2 = (index_type)blockIdx.y; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && (index_type)threadIdx.y < m_rp.m_tile[2] ) { - - for ( index_type tile_id3 = (index_type)blockIdx.z; tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z ) { - const index_type offset_3 = tile_id3*m_rp.m_tile[3] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && (index_type)threadIdx.z < m_rp.m_tile[3] ) { - m_func(Tag() , offset_0 , offset_1 , offset_2 , offset_3); + const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + thr_id1 + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type tile_id2 = (index_type)blockIdx.y; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + (index_type)threadIdx.y < m_rp.m_tile[2]) { + for (index_type tile_id3 = (index_type)blockIdx.z; + tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z) { + const index_type offset_3 = tile_id3 * m_rp.m_tile[3] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + (index_type)threadIdx.z < m_rp.m_tile[3]) { + m_func(Tag(), offset_0, offset_1, offset_2, offset_3); } } } @@ -503,80 +581,90 @@ struct DeviceIterateTile<4,RP,Functor,Tag> } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; - -//Rank 5 +// Rank 5 // Specializations for void tag type -template< typename RP , typename Functor > -struct DeviceIterateTile<5,RP,Functor,void > -{ +template +struct DeviceIterateTile<5, RP, Functor, void> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); // LL if (RP::inner_direction == RP::Left) { - - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x % numbl0; const index_type tile_id1 = (index_type)blockIdx.x / numbl0; - const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; + const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl2 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl3 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl2 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl2 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl3 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl2) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id2 = (index_type)blockIdx.y % numbl2; const index_type tile_id3 = (index_type)blockIdx.y / numbl2; - const index_type thr_id2 = (index_type)threadIdx.y % m_rp.m_tile[2]; - const index_type thr_id3 = (index_type)threadIdx.y / m_rp.m_tile[2]; - - for ( index_type tile_id4 = (index_type)blockIdx.z; tile_id4 < m_rp.m_tile_end[4]; tile_id4 += gridDim.z ) { - const index_type offset_4 = tile_id4*m_rp.m_tile[4] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && (index_type)threadIdx.z < m_rp.m_tile[4] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1 ; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0 ; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3, offset_4); + const index_type thr_id2 = (index_type)threadIdx.y % m_rp.m_tile[2]; + const index_type thr_id3 = (index_type)threadIdx.y / m_rp.m_tile[2]; + + for (index_type tile_id4 = (index_type)blockIdx.z; + tile_id4 < m_rp.m_tile_end[4]; tile_id4 += gridDim.z) { + const index_type offset_4 = tile_id4 * m_rp.m_tile[4] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && + (index_type)threadIdx.z < m_rp.m_tile[4]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3) { + const index_type offset_3 = + l * m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = j * m_rp.m_tile[1] + thr_id1 + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = i * m_rp.m_tile[0] + + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(offset_0, offset_1, offset_2, offset_3, + offset_4); } } } @@ -590,48 +678,61 @@ struct DeviceIterateTile<5,RP,Functor,void > } // LR else { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x / numbl1; const index_type tile_id1 = (index_type)blockIdx.x % numbl1; - const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; + const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl3 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl2 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl3 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl3 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl2 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl3) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id2 = (index_type)blockIdx.y / numbl3; const index_type tile_id3 = (index_type)blockIdx.y % numbl3; - const index_type thr_id2 = (index_type)threadIdx.y / m_rp.m_tile[3]; - const index_type thr_id3 = (index_type)threadIdx.y % m_rp.m_tile[3]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type tile_id4 = (index_type)blockIdx.z; tile_id4 < m_rp.m_tile_end[4]; tile_id4 += gridDim.z ) { - const index_type offset_4 = tile_id4*m_rp.m_tile[4] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && (index_type)threadIdx.z < m_rp.m_tile[4] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3 , offset_4); + const index_type thr_id2 = (index_type)threadIdx.y / m_rp.m_tile[3]; + const index_type thr_id3 = (index_type)threadIdx.y % m_rp.m_tile[3]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = l * m_rp.m_tile[3] + thr_id3 + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + thr_id3 < m_rp.m_tile[3]) { + for (index_type tile_id4 = (index_type)blockIdx.z; + tile_id4 < m_rp.m_tile_end[4]; + tile_id4 += gridDim.z) { + const index_type offset_4 = tile_id4 * m_rp.m_tile[4] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && + (index_type)threadIdx.z < m_rp.m_tile[4]) { + m_func(offset_0, offset_1, offset_2, offset_3, + offset_4); } } } @@ -643,77 +744,89 @@ struct DeviceIterateTile<5,RP,Functor,void > } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; // Specializations for tag type -template< typename RP , typename Functor , typename Tag > -struct DeviceIterateTile<5,RP,Functor,Tag> -{ +template +struct DeviceIterateTile<5, RP, Functor, Tag> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); // LL if (RP::inner_direction == RP::Left) { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x % numbl0; const index_type tile_id1 = (index_type)blockIdx.x / numbl0; - const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; + const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl2 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl3 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl2 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl2 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl3 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl2) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id2 = (index_type)blockIdx.y % numbl2; const index_type tile_id3 = (index_type)blockIdx.y / numbl2; - const index_type thr_id2 = (index_type)threadIdx.y % m_rp.m_tile[2]; - const index_type thr_id3 = (index_type)threadIdx.y / m_rp.m_tile[2]; - - for ( index_type tile_id4 = (index_type)blockIdx.z; tile_id4 < m_rp.m_tile_end[4]; tile_id4 += gridDim.z ) { - const index_type offset_4 = tile_id4*m_rp.m_tile[4] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && (index_type)threadIdx.z < m_rp.m_tile[4] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1 ; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0 ; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(Tag() , offset_0 , offset_1 , offset_2 , offset_3, offset_4); + const index_type thr_id2 = (index_type)threadIdx.y % m_rp.m_tile[2]; + const index_type thr_id3 = (index_type)threadIdx.y / m_rp.m_tile[2]; + + for (index_type tile_id4 = (index_type)blockIdx.z; + tile_id4 < m_rp.m_tile_end[4]; tile_id4 += gridDim.z) { + const index_type offset_4 = tile_id4 * m_rp.m_tile[4] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && + (index_type)threadIdx.z < m_rp.m_tile[4]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3) { + const index_type offset_3 = + l * m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = j * m_rp.m_tile[1] + thr_id1 + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = i * m_rp.m_tile[0] + + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(Tag(), offset_0, offset_1, offset_2, offset_3, + offset_4); } } } @@ -727,48 +840,61 @@ struct DeviceIterateTile<5,RP,Functor,Tag> } // LR else { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x / numbl1; const index_type tile_id1 = (index_type)blockIdx.x % numbl1; - const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; + const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl3 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl2 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl3 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl3 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl2 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl3) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id2 = (index_type)blockIdx.y / numbl3; const index_type tile_id3 = (index_type)blockIdx.y % numbl3; - const index_type thr_id2 = (index_type)threadIdx.y / m_rp.m_tile[3]; - const index_type thr_id3 = (index_type)threadIdx.y % m_rp.m_tile[3]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type tile_id4 = (index_type)blockIdx.z; tile_id4 < m_rp.m_tile_end[4]; tile_id4 += gridDim.z ) { - const index_type offset_4 = tile_id4*m_rp.m_tile[4] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && (index_type)threadIdx.z < m_rp.m_tile[4] ) { - m_func(Tag() , offset_0 , offset_1 , offset_2 , offset_3 , offset_4); + const index_type thr_id2 = (index_type)threadIdx.y / m_rp.m_tile[3]; + const index_type thr_id3 = (index_type)threadIdx.y % m_rp.m_tile[3]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = l * m_rp.m_tile[3] + thr_id3 + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + thr_id3 < m_rp.m_tile[3]) { + for (index_type tile_id4 = (index_type)blockIdx.z; + tile_id4 < m_rp.m_tile_end[4]; + tile_id4 += gridDim.z) { + const index_type offset_4 = tile_id4 * m_rp.m_tile[4] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && + (index_type)threadIdx.z < m_rp.m_tile[4]) { + m_func(Tag(), offset_0, offset_1, offset_2, offset_3, + offset_4); } } } @@ -780,94 +906,107 @@ struct DeviceIterateTile<5,RP,Functor,Tag> } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; - -//Rank 6 +// Rank 6 // Specializations for void tag type -template< typename RP , typename Functor > -struct DeviceIterateTile<6,RP,Functor,void > -{ +template +struct DeviceIterateTile<6, RP, Functor, void> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); // LL if (RP::inner_direction == RP::Left) { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x % numbl0; const index_type tile_id1 = (index_type)blockIdx.x / numbl0; - const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; + const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl2 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl3 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl2 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl2 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl3 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl2) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id2 = (index_type)blockIdx.y % numbl2; const index_type tile_id3 = (index_type)blockIdx.y / numbl2; - const index_type thr_id2 = (index_type)threadIdx.y % m_rp.m_tile[2]; - const index_type thr_id3 = (index_type)threadIdx.y / m_rp.m_tile[2]; + const index_type thr_id2 = (index_type)threadIdx.y % m_rp.m_tile[2]; + const index_type thr_id3 = (index_type)threadIdx.y / m_rp.m_tile[2]; - temp0 = m_rp.m_tile_end[4]; - temp1 = m_rp.m_tile_end[5]; - const index_type numbl4 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl5 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl4 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[4]; + temp1 = m_rp.m_tile_end[5]; + const index_type numbl4 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl5 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl4) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id4 = (index_type)blockIdx.z % numbl4; const index_type tile_id5 = (index_type)blockIdx.z / numbl4; - const index_type thr_id4 = (index_type)threadIdx.z % m_rp.m_tile[4]; - const index_type thr_id5 = (index_type)threadIdx.z / m_rp.m_tile[4]; - - for ( index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5 ) { - const index_type offset_5 = n*m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; - if ( offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5] ) { - - for ( index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4 ) { - const index_type offset_4 = m*m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1 ; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0 ; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3, offset_4, offset_5); + const index_type thr_id4 = (index_type)threadIdx.z % m_rp.m_tile[4]; + const index_type thr_id5 = (index_type)threadIdx.z / m_rp.m_tile[4]; + + for (index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5) { + const index_type offset_5 = + n * m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; + if (offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5]) { + for (index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4) { + const index_type offset_4 = + m * m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = + l * m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = k * m_rp.m_tile[2] + thr_id2 + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + thr_id2 < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = j * m_rp.m_tile[1] + + thr_id1 + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(offset_0, offset_1, offset_2, offset_3, + offset_4, offset_5); } } } @@ -883,63 +1022,80 @@ struct DeviceIterateTile<6,RP,Functor,void > } // LR else { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x / numbl1; const index_type tile_id1 = (index_type)blockIdx.x % numbl1; - const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; + const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl3 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl2 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl3 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl3 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl2 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl3) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id2 = (index_type)blockIdx.y / numbl3; const index_type tile_id3 = (index_type)blockIdx.y % numbl3; - const index_type thr_id2 = (index_type)threadIdx.y / m_rp.m_tile[3]; - const index_type thr_id3 = (index_type)threadIdx.y % m_rp.m_tile[3]; + const index_type thr_id2 = (index_type)threadIdx.y / m_rp.m_tile[3]; + const index_type thr_id3 = (index_type)threadIdx.y % m_rp.m_tile[3]; - temp0 = m_rp.m_tile_end[4]; - temp1 = m_rp.m_tile_end[5]; - const index_type numbl5 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl4 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl5 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[4]; + temp1 = m_rp.m_tile_end[5]; + const index_type numbl5 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl4 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl5) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id4 = (index_type)blockIdx.z / numbl5; const index_type tile_id5 = (index_type)blockIdx.z % numbl5; - const index_type thr_id4 = (index_type)threadIdx.z / m_rp.m_tile[5]; - const index_type thr_id5 = (index_type)threadIdx.z % m_rp.m_tile[5]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4 ) { - const index_type offset_4 = m*m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4] ) { - - for ( index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5 ) { - const index_type offset_5 = n*m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; - if ( offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3 , offset_4 , offset_5); + const index_type thr_id4 = (index_type)threadIdx.z / m_rp.m_tile[5]; + const index_type thr_id5 = (index_type)threadIdx.z % m_rp.m_tile[5]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = l * m_rp.m_tile[3] + thr_id3 + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + thr_id3 < m_rp.m_tile[3]) { + for (index_type m = tile_id4; m < m_rp.m_tile_end[4]; + m += numbl4) { + const index_type offset_4 = m * m_rp.m_tile[4] + + thr_id4 + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && + thr_id4 < m_rp.m_tile[4]) { + for (index_type n = tile_id5; n < m_rp.m_tile_end[5]; + n += numbl5) { + const index_type offset_5 = + n * m_rp.m_tile[5] + thr_id5 + + (index_type)m_rp.m_lower[5]; + if (offset_5 < m_rp.m_upper[5] && + thr_id5 < m_rp.m_tile[5]) { + m_func(offset_0, offset_1, offset_2, offset_3, + offset_4, offset_5); } } } @@ -953,92 +1109,106 @@ struct DeviceIterateTile<6,RP,Functor,void > } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; // Specializations for tag type -template< typename RP , typename Functor , typename Tag > -struct DeviceIterateTile<6,RP,Functor,Tag> -{ +template +struct DeviceIterateTile<6, RP, Functor, Tag> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); // LL if (RP::inner_direction == RP::Left) { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x % numbl0; const index_type tile_id1 = (index_type)blockIdx.x / numbl0; - const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; + const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl2 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl3 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl2 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl2 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl3 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl2) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id2 = (index_type)blockIdx.y % numbl2; const index_type tile_id3 = (index_type)blockIdx.y / numbl2; - const index_type thr_id2 = (index_type)threadIdx.y % m_rp.m_tile[2]; - const index_type thr_id3 = (index_type)threadIdx.y / m_rp.m_tile[2]; + const index_type thr_id2 = (index_type)threadIdx.y % m_rp.m_tile[2]; + const index_type thr_id3 = (index_type)threadIdx.y / m_rp.m_tile[2]; - temp0 = m_rp.m_tile_end[4]; - temp1 = m_rp.m_tile_end[5]; - const index_type numbl4 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl5 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl4 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[4]; + temp1 = m_rp.m_tile_end[5]; + const index_type numbl4 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl5 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl4) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id4 = (index_type)blockIdx.z % numbl4; const index_type tile_id5 = (index_type)blockIdx.z / numbl4; - const index_type thr_id4 = (index_type)threadIdx.z % m_rp.m_tile[4]; - const index_type thr_id5 = (index_type)threadIdx.z / m_rp.m_tile[4]; - - for ( index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5 ) { - const index_type offset_5 = n*m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; - if ( offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5] ) { - - for ( index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4 ) { - const index_type offset_4 = m*m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1 ; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0 ; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(Tag() , offset_0 , offset_1 , offset_2 , offset_3, offset_4, offset_5); + const index_type thr_id4 = (index_type)threadIdx.z % m_rp.m_tile[4]; + const index_type thr_id5 = (index_type)threadIdx.z / m_rp.m_tile[4]; + + for (index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5) { + const index_type offset_5 = + n * m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; + if (offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5]) { + for (index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4) { + const index_type offset_4 = + m * m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = + l * m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = k * m_rp.m_tile[2] + thr_id2 + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + thr_id2 < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = j * m_rp.m_tile[1] + + thr_id1 + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(Tag(), offset_0, offset_1, offset_2, + offset_3, offset_4, offset_5); } } } @@ -1054,63 +1224,80 @@ struct DeviceIterateTile<6,RP,Functor,Tag> } // LR else { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x / numbl1; const index_type tile_id1 = (index_type)blockIdx.x % numbl1; - const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; + const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl3 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl2 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl3 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl3 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl2 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl3) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id2 = (index_type)blockIdx.y / numbl3; const index_type tile_id3 = (index_type)blockIdx.y % numbl3; - const index_type thr_id2 = (index_type)threadIdx.y / m_rp.m_tile[3]; - const index_type thr_id3 = (index_type)threadIdx.y % m_rp.m_tile[3]; + const index_type thr_id2 = (index_type)threadIdx.y / m_rp.m_tile[3]; + const index_type thr_id3 = (index_type)threadIdx.y % m_rp.m_tile[3]; - temp0 = m_rp.m_tile_end[4]; - temp1 = m_rp.m_tile_end[5]; - const index_type numbl5 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl4 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl5 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[4]; + temp1 = m_rp.m_tile_end[5]; + const index_type numbl5 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl4 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl5) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id4 = (index_type)blockIdx.z / numbl5; const index_type tile_id5 = (index_type)blockIdx.z % numbl5; - const index_type thr_id4 = (index_type)threadIdx.z / m_rp.m_tile[5]; - const index_type thr_id5 = (index_type)threadIdx.z % m_rp.m_tile[5]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4 ) { - const index_type offset_4 = m*m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4] ) { - - for ( index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5 ) { - const index_type offset_5 = n*m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; - if ( offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5] ) { - m_func(Tag() , offset_0 , offset_1 , offset_2 , offset_3 , offset_4 , offset_5); + const index_type thr_id4 = (index_type)threadIdx.z / m_rp.m_tile[5]; + const index_type thr_id5 = (index_type)threadIdx.z % m_rp.m_tile[5]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = l * m_rp.m_tile[3] + thr_id3 + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + thr_id3 < m_rp.m_tile[3]) { + for (index_type m = tile_id4; m < m_rp.m_tile_end[4]; + m += numbl4) { + const index_type offset_4 = m * m_rp.m_tile[4] + + thr_id4 + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && + thr_id4 < m_rp.m_tile[4]) { + for (index_type n = tile_id5; n < m_rp.m_tile_end[5]; + n += numbl5) { + const index_type offset_5 = + n * m_rp.m_tile[5] + thr_id5 + + (index_type)m_rp.m_lower[5]; + if (offset_5 < m_rp.m_upper[5] && + thr_id5 < m_rp.m_tile[5]) { + m_func(Tag(), offset_0, offset_1, offset_2, + offset_3, offset_4, offset_5); } } } @@ -1124,168 +1311,175 @@ struct DeviceIterateTile<6,RP,Functor,Tag> } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; -} // Refactor +} // namespace Refactor // ---------------------------------------------------------------------------------- namespace Reduce { -template < typename T > -using is_void = std::is_same< T, void >; +template +using is_void = std::is_same; -template < typename T > -struct is_array_type : std::false_type -{ +template +struct is_array_type : std::false_type { using value_type = T; }; -template < typename T > -struct is_array_type< T* > : std::true_type -{ +template +struct is_array_type : std::true_type { using value_type = T; }; -template < typename T > -struct is_array_type< T[] > : std::true_type -{ +template +struct is_array_type : std::true_type { using value_type = T; }; // ------------------------------------------------------------------ // -template< int N , typename RP , typename Functor , typename Tag , typename ValueType , typename Enable = void > +template struct DeviceIterateTile; // ParallelReduce iteration pattern // Scalar reductions -// num_blocks = min( num_tiles, max_num_blocks ); //i.e. determined by number of tiles and reduction algorithm constraints -// extract n-dim tile offsets (i.e. tile's global starting mulit-index) from the tileid = blockid using tile dimensions -// local indices within a tile extracted from (index_type)threadIdx.x using tile dims, constrained by blocksize -// combine tile and local id info for multi-dim global ids +// num_blocks = min( num_tiles, max_num_blocks ); //i.e. determined by number of +// tiles and reduction algorithm constraints extract n-dim tile offsets (i.e. +// tile's global starting mulit-index) from the tileid = blockid using tile +// dimensions local indices within a tile extracted from (index_type)threadIdx.x +// using tile dims, constrained by blocksize combine tile and local id info for +// multi-dim global ids // Pattern: -// Each block+thread is responsible for a tile+local_id combo (additional when striding by num_blocks) +// Each block+thread is responsible for a tile+local_id combo (additional when +// striding by num_blocks) // 1. create offset arrays -// 2. loop over number of tiles, striding by griddim (equal to num tiles, or max num blocks) +// 2. loop over number of tiles, striding by griddim (equal to num tiles, or max +// num blocks) // 3. temps set for tile_idx and thrd_idx, which will be modified // 4. if LL vs LR: // determine tile starting point offsets (multidim) // determine local index offsets (multidim) // concatentate tile offset + local offset for global multi-dim index -// if offset withinin range bounds AND local offset within tile bounds, call functor +// if offset withinin range bounds AND local offset within tile bounds, call +// functor // ValueType = T -//Rank 2 +// Rank 2 // Specializations for void tag type -template< typename RP , typename Functor , typename ValueType > -struct DeviceIterateTile<2,RP,Functor,void,ValueType, typename std::enable_if< !is_array_type::value >::type > -{ +template +struct DeviceIterateTile< + 2, RP, Functor, void, ValueType, + typename std::enable_if::value>::type> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , ValueType & v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} - - inline __device__ - void exec_range() const - { - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, ValueType& v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} + + inline __device__ void exec_range() const { + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; m_local_offset[i] = (thrd_idx % m_rp.m_tile[i]); thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( m_offset[0], m_offset[1], m_v ); } + if (in_bounds) { + m_func(m_offset[0], m_offset[1], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; - ValueType & m_v; + private: + const RP& m_rp; + const Functor& m_func; + ValueType& m_v; }; - // Specializations for tag type -template< typename RP , typename Functor , typename Tag, typename ValueType > -struct DeviceIterateTile<2,RP,Functor,Tag, ValueType, typename std::enable_if< !is_array_type::value && !is_void< Tag >::value >::type > -{ +template +struct DeviceIterateTile< + 2, RP, Functor, Tag, ValueType, + typename std::enable_if::value && + !is_void::value>::type> { using index_type = typename RP::index_type; - inline __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , ValueType & v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} - - inline __device__ - void exec_range() const - { - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + inline __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, + ValueType& v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} + + inline __device__ void exec_range() const { + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y - m_local_offset[i] = (thrd_idx % m_rp.m_tile[i]); // Move this to first computation, add to m_offset right away + m_local_offset[i] = + (thrd_idx % m_rp.m_tile[i]); // Move this to first computation, + // add to m_offset right away thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( Tag(), m_offset[0], m_offset[1], m_v ); } + if (in_bounds) { + m_func(Tag(), m_offset[0], m_offset[1], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; - ValueType & m_v; + private: + const RP& m_rp; + const Functor& m_func; + ValueType& m_v; }; - -//Rank 3 +// Rank 3 // Specializations for void tag type -template< typename RP , typename Functor , typename ValueType > -struct DeviceIterateTile<3,RP,Functor,void,ValueType , typename std::enable_if< !is_array_type::value >::type > -{ +template +struct DeviceIterateTile< + 3, RP, Functor, void, ValueType, + typename std::enable_if::value>::type> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , ValueType & v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} - - inline __device__ - void exec_range() const - { - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, ValueType& v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} + + inline __device__ void exec_range() const { + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y - m_local_offset[i] = (thrd_idx % m_rp.m_tile[i]); // Move this to first computation, add to m_offset right away + m_local_offset[i] = + (thrd_idx % m_rp.m_tile[i]); // Move this to first computation, + // add to m_offset right away thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( m_offset[0], m_offset[1], m_offset[2], m_v ); } + if (in_bounds) { + m_func(m_offset[0], m_offset[1], m_offset[2], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; - ValueType & m_v; + private: + const RP& m_rp; + const Functor& m_func; + ValueType& m_v; }; - // Specializations for void tag type -template< typename RP , typename Functor , typename Tag, typename ValueType > -struct DeviceIterateTile<3,RP,Functor,Tag, ValueType, typename std::enable_if< !is_array_type::value && !is_void< Tag >::value >::type > -{ +template +struct DeviceIterateTile< + 3, RP, Functor, Tag, ValueType, + typename std::enable_if::value && + !is_void::value>::type> { using index_type = typename RP::index_type; - inline __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , ValueType & v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} - - inline __device__ - void exec_range() const - { - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + inline __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, + ValueType& v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} + + inline __device__ void exec_range() const { + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y - m_local_offset[i] = (thrd_idx % m_rp.m_tile[i]); // Move this to first computation, add to m_offset right away + m_local_offset[i] = + (thrd_idx % m_rp.m_tile[i]); // Move this to first computation, + // add to m_offset right away thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( Tag(), m_offset[0], m_offset[1], m_offset[2], m_v ); } + if (in_bounds) { + m_func(Tag(), m_offset[0], m_offset[1], m_offset[2], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; - ValueType & m_v; + private: + const RP& m_rp; + const Functor& m_func; + ValueType& m_v; }; - -//Rank 4 +// Rank 4 // Specializations for void tag type -template< typename RP , typename Functor , typename ValueType > -struct DeviceIterateTile<4,RP,Functor,void,ValueType , typename std::enable_if< !is_array_type::value >::type > -{ +template +struct DeviceIterateTile< + 4, RP, Functor, void, ValueType, + typename std::enable_if::value>::type> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , ValueType & v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, ValueType& v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -1534,58 +1754,64 @@ struct DeviceIterateTile<4,RP,Functor,void,ValueType , typename std::enable_if< thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_v ); } + if (in_bounds) { + m_func(m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; - ValueType & m_v; + private: + const RP& m_rp; + const Functor& m_func; + ValueType& m_v; }; - // Specializations for void tag type -template< typename RP , typename Functor , typename Tag, typename ValueType > -struct DeviceIterateTile<4,RP,Functor,Tag,ValueType, typename std::enable_if< !is_array_type::value && !is_void< Tag >::value >::type > -{ +template +struct DeviceIterateTile< + 4, RP, Functor, Tag, ValueType, + typename std::enable_if::value && + !is_void::value>::type> { using index_type = typename RP::index_type; - inline __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , ValueType & v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + inline __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, + ValueType& v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -1611,59 +1841,64 @@ struct DeviceIterateTile<4,RP,Functor,Tag,ValueType, typename std::enable_if< !i thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_v ); } + if (in_bounds) { + m_func(Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], + m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; - ValueType & m_v; + private: + const RP& m_rp; + const Functor& m_func; + ValueType& m_v; }; - -//Rank 5 +// Rank 5 // Specializations for void tag type -template< typename RP , typename Functor , typename ValueType > -struct DeviceIterateTile<5,RP,Functor,void,ValueType , typename std::enable_if< !is_array_type::value >::type > -{ +template +struct DeviceIterateTile< + 5, RP, Functor, void, ValueType, + typename std::enable_if::value>::type> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , ValueType & v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, ValueType& v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -1689,58 +1928,64 @@ struct DeviceIterateTile<5,RP,Functor,void,ValueType , typename std::enable_if< thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_offset[4], m_v ); } + if (in_bounds) { + m_func(m_offset[0], m_offset[1], m_offset[2], m_offset[3], + m_offset[4], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; - ValueType & m_v; + private: + const RP& m_rp; + const Functor& m_func; + ValueType& m_v; }; - // Specializations for tag type -template< typename RP , typename Functor , typename Tag, typename ValueType > -struct DeviceIterateTile<5,RP,Functor,Tag,ValueType, typename std::enable_if< !is_array_type::value && !is_void< Tag >::value >::type > -{ +template +struct DeviceIterateTile< + 5, RP, Functor, Tag, ValueType, + typename std::enable_if::value && + !is_void::value>::type> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , ValueType & v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, ValueType& v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -1766,59 +2015,64 @@ struct DeviceIterateTile<5,RP,Functor,Tag,ValueType, typename std::enable_if< !i thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_offset[4], m_v ); } + if (in_bounds) { + m_func(Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], + m_offset[4], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; - ValueType & m_v; + private: + const RP& m_rp; + const Functor& m_func; + ValueType& m_v; }; - -//Rank 6 +// Rank 6 // Specializations for void tag type -template< typename RP , typename Functor , typename ValueType > -struct DeviceIterateTile<6,RP,Functor,void,ValueType , typename std::enable_if< !is_array_type::value >::type > -{ +template +struct DeviceIterateTile< + 6, RP, Functor, void, ValueType, + typename std::enable_if::value>::type> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , ValueType & v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, ValueType& v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -1844,58 +2102,64 @@ struct DeviceIterateTile<6,RP,Functor,void,ValueType , typename std::enable_if< thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_offset[4], m_offset[5], m_v ); } + if (in_bounds) { + m_func(m_offset[0], m_offset[1], m_offset[2], m_offset[3], + m_offset[4], m_offset[5], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; - ValueType & m_v; + private: + const RP& m_rp; + const Functor& m_func; + ValueType& m_v; }; - // Specializations for tag type -template< typename RP , typename Functor , typename Tag, typename ValueType > -struct DeviceIterateTile<6,RP,Functor,Tag,ValueType, typename std::enable_if< !is_array_type::value && !is_void< Tag >::value >::type > -{ +template +struct DeviceIterateTile< + 6, RP, Functor, Tag, ValueType, + typename std::enable_if::value && + !is_void::value>::type> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , ValueType & v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, ValueType& v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -1921,130 +2189,138 @@ struct DeviceIterateTile<6,RP,Functor,Tag,ValueType, typename std::enable_if< !i thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_offset[4], m_offset[5], m_v ); } + if (in_bounds) { + m_func(Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], + m_offset[4], m_offset[5], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; - ValueType & m_v; + private: + const RP& m_rp; + const Functor& m_func; + ValueType& m_v; }; - // ValueType = T[], T* -//Rank 2 +// Rank 2 // Specializations for void tag type -template< typename RP , typename Functor , typename ValueType > -struct DeviceIterateTile<2,RP,Functor,void,ValueType, typename std::enable_if< is_array_type::value >::type > -{ +template +struct DeviceIterateTile< + 2, RP, Functor, void, ValueType, + typename std::enable_if::value>::type> { using index_type = typename RP::index_type; - using value_type = typename is_array_type< ValueType >::value_type; - - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , value_type* v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} - - inline __device__ - void exec_range() const - { - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + using value_type = typename is_array_type::value_type; + + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, value_type* v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} + + inline __device__ void exec_range() const { + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y - m_local_offset[i] = (thrd_idx % m_rp.m_tile[i]); // Move this to first computation, add to m_offset right away + m_local_offset[i] = + (thrd_idx % m_rp.m_tile[i]); // Move this to first computation, + // add to m_offset right away thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( m_offset[0], m_offset[1], m_v ); } + if (in_bounds) { + m_func(m_offset[0], m_offset[1], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; value_type* m_v; }; - // Specializations for tag type -template< typename RP , typename Functor , typename Tag, typename ValueType > -struct DeviceIterateTile<2,RP,Functor,Tag, ValueType, typename std::enable_if< is_array_type::value && !is_void< Tag >::value >::type > -{ +template +struct DeviceIterateTile< + 2, RP, Functor, Tag, ValueType, + typename std::enable_if::value && + !is_void::value>::type> { using index_type = typename RP::index_type; - using value_type = typename is_array_type< ValueType >::value_type; - - inline __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , value_type* v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} - - inline __device__ - void exec_range() const - { - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + using value_type = typename is_array_type::value_type; + + inline __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, + value_type* v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} + + inline __device__ void exec_range() const { + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -2070,128 +2349,139 @@ struct DeviceIterateTile<2,RP,Functor,Tag, ValueType, typename std::enable_if< i thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( Tag(), m_offset[0], m_offset[1], m_v ); } + if (in_bounds) { + m_func(Tag(), m_offset[0], m_offset[1], m_v); + } } - } //end for loop over num_tiles - product of tiles in each direction + } // end for loop over num_tiles - product of tiles in each direction } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; value_type* m_v; }; - -//Rank 3 +// Rank 3 // Specializations for void tag type -template< typename RP , typename Functor , typename ValueType > -struct DeviceIterateTile<3,RP,Functor,void,ValueType , typename std::enable_if< is_array_type::value >::type > -{ +template +struct DeviceIterateTile< + 3, RP, Functor, void, ValueType, + typename std::enable_if::value>::type> { using index_type = typename RP::index_type; - using value_type = typename is_array_type< ValueType >::value_type; - - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , value_type* v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} - - inline __device__ - void exec_range() const - { - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + using value_type = typename is_array_type::value_type; + + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, value_type* v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} + + inline __device__ void exec_range() const { + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y - m_local_offset[i] = (thrd_idx % m_rp.m_tile[i]); // Move this to first computation, add to m_offset right away + m_local_offset[i] = + (thrd_idx % m_rp.m_tile[i]); // Move this to first computation, + // add to m_offset right away thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( m_offset[0], m_offset[1], m_offset[2], m_v ); } + if (in_bounds) { + m_func(m_offset[0], m_offset[1], m_offset[2], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; value_type* m_v; }; - // Specializations for void tag type -template< typename RP , typename Functor , typename Tag, typename ValueType > -struct DeviceIterateTile<3,RP,Functor,Tag, ValueType, typename std::enable_if< is_array_type::value && !is_void< Tag >::value >::type > -{ +template +struct DeviceIterateTile< + 3, RP, Functor, Tag, ValueType, + typename std::enable_if::value && + !is_void::value>::type> { using index_type = typename RP::index_type; - using value_type = typename is_array_type< ValueType >::value_type; - - inline __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , value_type* v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} - - inline __device__ - void exec_range() const - { - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + using value_type = typename is_array_type::value_type; + + inline __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, + value_type* v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} + + inline __device__ void exec_range() const { + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -2217,60 +2510,64 @@ struct DeviceIterateTile<3,RP,Functor,Tag, ValueType, typename std::enable_if< i thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( Tag(), m_offset[0], m_offset[1], m_offset[2], m_v ); } + if (in_bounds) { + m_func(Tag(), m_offset[0], m_offset[1], m_offset[2], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; value_type* m_v; }; - -//Rank 4 +// Rank 4 // Specializations for void tag type -template< typename RP , typename Functor , typename ValueType > -struct DeviceIterateTile<4,RP,Functor,void,ValueType , typename std::enable_if< is_array_type::value >::type > -{ +template +struct DeviceIterateTile< + 4, RP, Functor, void, ValueType, + typename std::enable_if::value>::type> { using index_type = typename RP::index_type; - using value_type = typename is_array_type< ValueType >::value_type; + using value_type = typename is_array_type::value_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , value_type* v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, value_type* v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -2296,59 +2596,65 @@ struct DeviceIterateTile<4,RP,Functor,void,ValueType , typename std::enable_if< thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_v ); } + if (in_bounds) { + m_func(m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; value_type* m_v; }; - // Specializations for void tag type -template< typename RP , typename Functor , typename Tag, typename ValueType > -struct DeviceIterateTile<4,RP,Functor,Tag,ValueType, typename std::enable_if< is_array_type::value && !is_void< Tag >::value >::type > -{ +template +struct DeviceIterateTile< + 4, RP, Functor, Tag, ValueType, + typename std::enable_if::value && + !is_void::value>::type> { using index_type = typename RP::index_type; - using value_type = typename is_array_type< ValueType >::value_type; + using value_type = typename is_array_type::value_type; - inline __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , value_type* v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + inline __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, + value_type* v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -2374,60 +2684,65 @@ struct DeviceIterateTile<4,RP,Functor,Tag,ValueType, typename std::enable_if< is thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_v ); } + if (in_bounds) { + m_func(Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], + m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; value_type* m_v; }; - -//Rank 5 +// Rank 5 // Specializations for void tag type -template< typename RP , typename Functor , typename ValueType > -struct DeviceIterateTile<5,RP,Functor,void,ValueType , typename std::enable_if< is_array_type::value >::type > -{ +template +struct DeviceIterateTile< + 5, RP, Functor, void, ValueType, + typename std::enable_if::value>::type> { using index_type = typename RP::index_type; - using value_type = typename is_array_type< ValueType >::value_type; + using value_type = typename is_array_type::value_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , value_type* v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, value_type* v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -2453,59 +2772,65 @@ struct DeviceIterateTile<5,RP,Functor,void,ValueType , typename std::enable_if< thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_offset[4], m_v ); } + if (in_bounds) { + m_func(m_offset[0], m_offset[1], m_offset[2], m_offset[3], + m_offset[4], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; value_type* m_v; }; - // Specializations for tag type -template< typename RP , typename Functor , typename Tag, typename ValueType > -struct DeviceIterateTile<5,RP,Functor,Tag,ValueType, typename std::enable_if< is_array_type::value && !is_void< Tag >::value >::type > -{ +template +struct DeviceIterateTile< + 5, RP, Functor, Tag, ValueType, + typename std::enable_if::value && + !is_void::value>::type> { using index_type = typename RP::index_type; - using value_type = typename is_array_type< ValueType >::value_type; + using value_type = typename is_array_type::value_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , value_type* v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, value_type* v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -2531,60 +2860,65 @@ struct DeviceIterateTile<5,RP,Functor,Tag,ValueType, typename std::enable_if< is thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_offset[4], m_v ); } + if (in_bounds) { + m_func(Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], + m_offset[4], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; value_type* m_v; }; - -//Rank 6 +// Rank 6 // Specializations for void tag type -template< typename RP , typename Functor , typename ValueType > -struct DeviceIterateTile<6,RP,Functor,void,ValueType , typename std::enable_if< is_array_type::value >::type > -{ +template +struct DeviceIterateTile< + 6, RP, Functor, void, ValueType, + typename std::enable_if::value>::type> { using index_type = typename RP::index_type; - using value_type = typename is_array_type< ValueType >::value_type; + using value_type = typename is_array_type::value_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , value_type* v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, value_type* v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -2610,59 +2948,65 @@ struct DeviceIterateTile<6,RP,Functor,void,ValueType , typename std::enable_if< thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_offset[4], m_offset[5], m_v ); } + if (in_bounds) { + m_func(m_offset[0], m_offset[1], m_offset[2], m_offset[3], + m_offset[4], m_offset[5], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; value_type* m_v; }; - // Specializations for tag type -template< typename RP , typename Functor , typename Tag, typename ValueType > -struct DeviceIterateTile<6,RP,Functor,Tag,ValueType, typename std::enable_if< is_array_type::value && !is_void< Tag >::value >::type > -{ +template +struct DeviceIterateTile< + 6, RP, Functor, Tag, ValueType, + typename std::enable_if::value && + !is_void::value>::type> { using index_type = typename RP::index_type; - using value_type = typename is_array_type< ValueType >::value_type; + using value_type = typename is_array_type::value_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , value_type* v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, value_type* v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -2688,28 +3036,32 @@ struct DeviceIterateTile<6,RP,Functor,Tag,ValueType, typename std::enable_if< is thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_offset[4], m_offset[5], m_v ); } + if (in_bounds) { + m_func(Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], + m_offset[4], m_offset[5], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; value_type* m_v; }; -} // Reduce +} // namespace Reduce // ---------------------------------------------------------------------------------- -} } //end namespace Kokkos::Impl +} // namespace Impl +} // namespace Kokkos #endif #endif diff --git a/lib/kokkos/core/src/Cuda/Kokkos_CudaSpace.cpp b/lib/kokkos/core/src/Cuda/Kokkos_CudaSpace.cpp index 4c9ed47085..24be022d24 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_CudaSpace.cpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_CudaSpace.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -57,12 +58,12 @@ //#include #include +#include #if defined(KOKKOS_ENABLE_PROFILING) #include #endif - /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -71,68 +72,82 @@ namespace Impl { namespace { - static std::atomic num_uvm_allocations(0) ; +static std::atomic num_uvm_allocations(0); - cudaStream_t get_deep_copy_stream() { - static cudaStream_t s = 0; - if( s == 0) { - cudaStreamCreate ( &s ); - } - return s; - } +cudaStream_t get_deep_copy_stream() { + static cudaStream_t s = 0; + if (s == 0) { + cudaStreamCreate(&s); + } + return s; } +} // namespace -DeepCopy::DeepCopy( void * dst , const void * src , size_t n ) -{ CUDA_SAFE_CALL( cudaMemcpy( dst , src , n , cudaMemcpyDefault ) ); } +DeepCopy::DeepCopy(void *dst, const void *src, + size_t n) { + CUDA_SAFE_CALL(cudaMemcpy(dst, src, n, cudaMemcpyDefault)); +} -DeepCopy::DeepCopy( void * dst , const void * src , size_t n ) -{ CUDA_SAFE_CALL( cudaMemcpy( dst , src , n , cudaMemcpyDefault ) ); } +DeepCopy::DeepCopy(void *dst, const void *src, + size_t n) { + CUDA_SAFE_CALL(cudaMemcpy(dst, src, n, cudaMemcpyDefault)); +} -DeepCopy::DeepCopy( void * dst , const void * src , size_t n ) -{ CUDA_SAFE_CALL( cudaMemcpy( dst , src , n , cudaMemcpyDefault ) ); } +DeepCopy::DeepCopy(void *dst, const void *src, + size_t n) { + CUDA_SAFE_CALL(cudaMemcpy(dst, src, n, cudaMemcpyDefault)); +} -DeepCopy::DeepCopy( const Cuda & instance , void * dst , const void * src , size_t n ) -{ CUDA_SAFE_CALL( cudaMemcpyAsync( dst , src , n , cudaMemcpyDefault , instance.cuda_stream() ) ); } +DeepCopy::DeepCopy(const Cuda &instance, void *dst, + const void *src, size_t n) { + CUDA_SAFE_CALL( + cudaMemcpyAsync(dst, src, n, cudaMemcpyDefault, instance.cuda_stream())); +} -DeepCopy::DeepCopy( const Cuda & instance , void * dst , const void * src , size_t n ) -{ CUDA_SAFE_CALL( cudaMemcpyAsync( dst , src , n , cudaMemcpyDefault , instance.cuda_stream() ) ); } +DeepCopy::DeepCopy(const Cuda &instance, void *dst, + const void *src, size_t n) { + CUDA_SAFE_CALL( + cudaMemcpyAsync(dst, src, n, cudaMemcpyDefault, instance.cuda_stream())); +} -DeepCopy::DeepCopy( const Cuda & instance , void * dst , const void * src , size_t n ) -{ CUDA_SAFE_CALL( cudaMemcpyAsync( dst , src , n , cudaMemcpyDefault , instance.cuda_stream() ) ); } +DeepCopy::DeepCopy(const Cuda &instance, void *dst, + const void *src, size_t n) { + CUDA_SAFE_CALL( + cudaMemcpyAsync(dst, src, n, cudaMemcpyDefault, instance.cuda_stream())); +} -void DeepCopyAsyncCuda( void * dst , const void * src , size_t n) { +void DeepCopyAsyncCuda(void *dst, const void *src, size_t n) { cudaStream_t s = get_deep_copy_stream(); - CUDA_SAFE_CALL( cudaMemcpyAsync( dst , src , n , cudaMemcpyDefault , s ) ); + CUDA_SAFE_CALL(cudaMemcpyAsync(dst, src, n, cudaMemcpyDefault, s)); cudaStreamSynchronize(s); } -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ - namespace Kokkos { -void CudaSpace::access_error() -{ - const std::string msg("Kokkos::CudaSpace::access_error attempt to execute Cuda function from non-Cuda space" ); - Kokkos::Impl::throw_runtime_exception( msg ); +void CudaSpace::access_error() { + const std::string msg( + "Kokkos::CudaSpace::access_error attempt to execute Cuda function from " + "non-Cuda space"); + Kokkos::Impl::throw_runtime_exception(msg); } -void CudaSpace::access_error( const void * const ) -{ - const std::string msg("Kokkos::CudaSpace::access_error attempt to execute Cuda function from non-Cuda space" ); - Kokkos::Impl::throw_runtime_exception( msg ); +void CudaSpace::access_error(const void *const) { + const std::string msg( + "Kokkos::CudaSpace::access_error attempt to execute Cuda function from " + "non-Cuda space"); + Kokkos::Impl::throw_runtime_exception(msg); } - /*--------------------------------------------------------------------------*/ -bool CudaUVMSpace::available() -{ -#if defined( CUDA_VERSION ) && ( 6000 <= CUDA_VERSION ) && !defined(__APPLE__) +bool CudaUVMSpace::available() { +#if defined(CUDA_VERSION) && (6000 <= CUDA_VERSION) && !defined(__APPLE__) enum { UVM_available = true }; #else enum { UVM_available = false }; @@ -142,99 +157,155 @@ bool CudaUVMSpace::available() /*--------------------------------------------------------------------------*/ -int CudaUVMSpace::number_of_allocations() -{ +int CudaUVMSpace::number_of_allocations() { return Kokkos::Impl::num_uvm_allocations.load(); } +#ifdef KOKKOS_IMPL_DEBUG_CUDA_PIN_UVM_TO_HOST +// The purpose of the following variable is to allow a state-based choice +// for pinning UVM allocations to the CPU. For now this is considered +// an experimental debugging capability - with the potential to work around +// some CUDA issues. +bool CudaUVMSpace::kokkos_impl_cuda_pin_uvm_to_host_v = false; -} // namespace Kokkos +bool CudaUVMSpace::cuda_pin_uvm_to_host() { + return CudaUVMSpace::kokkos_impl_cuda_pin_uvm_to_host_v; +} +void CudaUVMSpace::cuda_set_pin_uvm_to_host(bool val) { + CudaUVMSpace::kokkos_impl_cuda_pin_uvm_to_host_v = val; +} +#endif +} // namespace Kokkos + +#ifdef KOKKOS_IMPL_DEBUG_CUDA_PIN_UVM_TO_HOST +bool kokkos_impl_cuda_pin_uvm_to_host() { + return Kokkos::CudaUVMSpace::cuda_pin_uvm_to_host(); +} + +void kokkos_impl_cuda_set_pin_uvm_to_host(bool val) { + Kokkos::CudaUVMSpace::cuda_set_pin_uvm_to_host(val); +} +#endif /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ namespace Kokkos { -CudaSpace::CudaSpace() - : m_device( Kokkos::Cuda().cuda_device() ) -{ -} +CudaSpace::CudaSpace() : m_device(Kokkos::Cuda().cuda_device()) {} -CudaUVMSpace::CudaUVMSpace() - : m_device( Kokkos::Cuda().cuda_device() ) -{ -} +CudaUVMSpace::CudaUVMSpace() : m_device(Kokkos::Cuda().cuda_device()) {} -CudaHostPinnedSpace::CudaHostPinnedSpace() -{ -} +CudaHostPinnedSpace::CudaHostPinnedSpace() {} -void * CudaSpace::allocate( const size_t arg_alloc_size ) const -{ - void * ptr = NULL; +//============================================================================== +// {{{1 - CUDA_SAFE_CALL( cudaMalloc( &ptr, arg_alloc_size ) ); +void *CudaSpace::allocate(const size_t arg_alloc_size) const { + void *ptr = nullptr; - return ptr ; + auto error_code = cudaMalloc(&ptr, arg_alloc_size); + if (error_code != cudaSuccess) { // TODO tag as unlikely branch + cudaGetLastError(); // This is the only way to clear the last error, which + // we should do here since we're turning it into an + // exception here + throw Experimental::CudaRawMemoryAllocationFailure( + arg_alloc_size, error_code, + Experimental::RawMemoryAllocationFailure::AllocationMechanism:: + CudaMalloc); + } + return ptr; } -void * CudaUVMSpace::allocate( const size_t arg_alloc_size ) const -{ - void * ptr = NULL; +void *CudaUVMSpace::allocate(const size_t arg_alloc_size) const { + void *ptr = nullptr; enum { max_uvm_allocations = 65536 }; Cuda::impl_static_fence(); - if ( arg_alloc_size > 0 ) - { + if (arg_alloc_size > 0) { Kokkos::Impl::num_uvm_allocations++; - if ( Kokkos::Impl::num_uvm_allocations.load() > max_uvm_allocations ) { - Kokkos::Impl::throw_runtime_exception( "CudaUVM error: The maximum limit of UVM allocations exceeded (currently 65536)." ) ; + if (Kokkos::Impl::num_uvm_allocations.load() > max_uvm_allocations) { + throw Experimental::CudaRawMemoryAllocationFailure( + arg_alloc_size, 1, + Experimental::RawMemoryAllocationFailure::FailureMode:: + MaximumCudaUVMAllocationsExceeded); } - CUDA_SAFE_CALL( cudaMallocManaged( &ptr, arg_alloc_size , cudaMemAttachGlobal ) ); + auto error_code = + cudaMallocManaged(&ptr, arg_alloc_size, cudaMemAttachGlobal); + +#ifdef KOKKOS_IMPL_DEBUG_CUDA_PIN_UVM_TO_HOST + if (Kokkos::CudaUVMSpace::cuda_pin_uvm_to_host()) + cudaMemAdvise(ptr, arg_alloc_size, cudaMemAdviseSetPreferredLocation, + cudaCpuDeviceId); +#endif + + if (error_code != cudaSuccess) { // TODO tag as unlikely branch + cudaGetLastError(); // This is the only way to clear the last error, + // which we should do here since we're turning it + // into an exception here + throw Experimental::CudaRawMemoryAllocationFailure( + arg_alloc_size, error_code, + Experimental::RawMemoryAllocationFailure::AllocationMechanism:: + CudaMallocManaged); + } } Cuda::impl_static_fence(); - return ptr ; + return ptr; } -void * CudaHostPinnedSpace::allocate( const size_t arg_alloc_size ) const -{ - void * ptr = NULL; +void *CudaHostPinnedSpace::allocate(const size_t arg_alloc_size) const { + void *ptr = nullptr; - CUDA_SAFE_CALL( cudaHostAlloc( &ptr, arg_alloc_size , cudaHostAllocDefault ) ); + auto error_code = cudaHostAlloc(&ptr, arg_alloc_size, cudaHostAllocDefault); + if (error_code != cudaSuccess) { // TODO tag as unlikely branch + cudaGetLastError(); // This is the only way to clear the last error, which + // we should do here since we're turning it into an + // exception here + throw Experimental::CudaRawMemoryAllocationFailure( + arg_alloc_size, error_code, + Experimental::RawMemoryAllocationFailure::AllocationMechanism:: + CudaHostAlloc); + } - return ptr ; + return ptr; } -void CudaSpace::deallocate( void * const arg_alloc_ptr , const size_t /* arg_alloc_size */ ) const -{ +// end allocate() }}}1 +//============================================================================== + +void CudaSpace::deallocate(void *const arg_alloc_ptr, + const size_t /* arg_alloc_size */) const { try { - CUDA_SAFE_CALL( cudaFree( arg_alloc_ptr ) ); - } catch(...) {} + CUDA_SAFE_CALL(cudaFree(arg_alloc_ptr)); + } catch (...) { + } } -void CudaUVMSpace::deallocate( void * const arg_alloc_ptr , const size_t /* arg_alloc_size */ ) const -{ +void CudaUVMSpace::deallocate(void *const arg_alloc_ptr, + const size_t /* arg_alloc_size */) const { Cuda::impl_static_fence(); try { - if ( arg_alloc_ptr != nullptr ) { + if (arg_alloc_ptr != nullptr) { Kokkos::Impl::num_uvm_allocations--; - CUDA_SAFE_CALL( cudaFree( arg_alloc_ptr ) ); + CUDA_SAFE_CALL(cudaFree(arg_alloc_ptr)); } - } catch(...) {} + } catch (...) { + } Cuda::impl_static_fence(); } -void CudaHostPinnedSpace::deallocate( void * const arg_alloc_ptr , const size_t /* arg_alloc_size */ ) const -{ +void CudaHostPinnedSpace::deallocate(void *const arg_alloc_ptr, + const size_t /* arg_alloc_size */) const { try { - CUDA_SAFE_CALL( cudaFreeHost( arg_alloc_ptr ) ); - } catch(...) {} + CUDA_SAFE_CALL(cudaFreeHost(arg_alloc_ptr)); + } catch (...) { + } } -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -243,606 +314,611 @@ namespace Kokkos { namespace Impl { #ifdef KOKKOS_DEBUG -SharedAllocationRecord< void , void > -SharedAllocationRecord< Kokkos::CudaSpace , void >::s_root_record ; +SharedAllocationRecord + SharedAllocationRecord::s_root_record; -SharedAllocationRecord< void , void > -SharedAllocationRecord< Kokkos::CudaUVMSpace , void >::s_root_record ; +SharedAllocationRecord + SharedAllocationRecord::s_root_record; -SharedAllocationRecord< void , void > -SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >::s_root_record ; +SharedAllocationRecord + SharedAllocationRecord::s_root_record; #endif ::cudaTextureObject_t -SharedAllocationRecord< Kokkos::CudaSpace , void >:: -attach_texture_object( const unsigned sizeof_alias - , void * const alloc_ptr - , size_t const alloc_size ) -{ +SharedAllocationRecord::attach_texture_object( + const unsigned sizeof_alias, void *const alloc_ptr, + size_t const alloc_size) { enum { TEXTURE_BOUND_1D = 1u << 27 }; - if ( ( alloc_ptr == 0 ) || ( sizeof_alias * TEXTURE_BOUND_1D <= alloc_size ) ) { - std::ostringstream msg ; + if ((alloc_ptr == 0) || (sizeof_alias * TEXTURE_BOUND_1D <= alloc_size)) { + std::ostringstream msg; msg << "Kokkos::CudaSpace ERROR: Cannot attach texture object to" << " alloc_ptr(" << alloc_ptr << ")" << " alloc_size(" << alloc_size << ")" - << " max_size(" << ( sizeof_alias * TEXTURE_BOUND_1D ) << ")" ; - std::cerr << msg.str() << std::endl ; + << " max_size(" << (sizeof_alias * TEXTURE_BOUND_1D) << ")"; + std::cerr << msg.str() << std::endl; std::cerr.flush(); - Kokkos::Impl::throw_runtime_exception( msg.str() ); + Kokkos::Impl::throw_runtime_exception(msg.str()); } - ::cudaTextureObject_t tex_obj ; + ::cudaTextureObject_t tex_obj; - struct cudaResourceDesc resDesc ; - struct cudaTextureDesc texDesc ; + struct cudaResourceDesc resDesc; + struct cudaTextureDesc texDesc; - memset( & resDesc , 0 , sizeof(resDesc) ); - memset( & texDesc , 0 , sizeof(texDesc) ); + memset(&resDesc, 0, sizeof(resDesc)); + memset(&texDesc, 0, sizeof(texDesc)); - resDesc.resType = cudaResourceTypeLinear ; - resDesc.res.linear.desc = ( sizeof_alias == 4 ? cudaCreateChannelDesc< int >() : - ( sizeof_alias == 8 ? cudaCreateChannelDesc< ::int2 >() : - /* sizeof_alias == 16 */ cudaCreateChannelDesc< ::int4 >() ) ); - resDesc.res.linear.sizeInBytes = alloc_size ; - resDesc.res.linear.devPtr = alloc_ptr ; + resDesc.resType = cudaResourceTypeLinear; + resDesc.res.linear.desc = + (sizeof_alias == 4 + ? cudaCreateChannelDesc() + : (sizeof_alias == 8 + ? cudaCreateChannelDesc< ::int2>() + : + /* sizeof_alias == 16 */ cudaCreateChannelDesc< ::int4>())); + resDesc.res.linear.sizeInBytes = alloc_size; + resDesc.res.linear.devPtr = alloc_ptr; - CUDA_SAFE_CALL( cudaCreateTextureObject( & tex_obj , & resDesc, & texDesc, NULL ) ); + CUDA_SAFE_CALL(cudaCreateTextureObject(&tex_obj, &resDesc, &texDesc, NULL)); - return tex_obj ; + return tex_obj; } -std::string -SharedAllocationRecord< Kokkos::CudaSpace , void >::get_label() const -{ - SharedAllocationHeader header ; +//============================================================================== +// {{{1 - Kokkos::Impl::DeepCopy< Kokkos::HostSpace , Kokkos::CudaSpace >( & header , RecordBase::head() , sizeof(SharedAllocationHeader) ); +std::string SharedAllocationRecord::get_label() const { + SharedAllocationHeader header; - return std::string( header.m_label ); + Kokkos::Impl::DeepCopy( + &header, RecordBase::head(), sizeof(SharedAllocationHeader)); + + return std::string(header.m_label); } -std::string -SharedAllocationRecord< Kokkos::CudaUVMSpace , void >::get_label() const -{ - return std::string( RecordBase::head()->m_label ); +std::string SharedAllocationRecord::get_label() + const { + return std::string(RecordBase::head()->m_label); } std::string -SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >::get_label() const -{ - return std::string( RecordBase::head()->m_label ); +SharedAllocationRecord::get_label() const { + return std::string(RecordBase::head()->m_label); } -SharedAllocationRecord< Kokkos::CudaSpace , void > * -SharedAllocationRecord< Kokkos::CudaSpace , void >:: -allocate( const Kokkos::CudaSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - ) -{ - return new SharedAllocationRecord( arg_space , arg_label , arg_alloc_size ); +// end SharedAllocationRecord::get_label() }}}1 +//============================================================================== + +//============================================================================== +// {{{1 + +SharedAllocationRecord + *SharedAllocationRecord::allocate( + const Kokkos::CudaSpace &arg_space, const std::string &arg_label, + const size_t arg_alloc_size) { + return new SharedAllocationRecord(arg_space, arg_label, arg_alloc_size); } -SharedAllocationRecord< Kokkos::CudaUVMSpace , void > * -SharedAllocationRecord< Kokkos::CudaUVMSpace , void >:: -allocate( const Kokkos::CudaUVMSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - ) -{ - return new SharedAllocationRecord( arg_space , arg_label , arg_alloc_size ); +SharedAllocationRecord + *SharedAllocationRecord::allocate( + const Kokkos::CudaUVMSpace &arg_space, const std::string &arg_label, + const size_t arg_alloc_size) { + return new SharedAllocationRecord(arg_space, arg_label, arg_alloc_size); } -SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void > * -SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >:: -allocate( const Kokkos::CudaHostPinnedSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - ) -{ - return new SharedAllocationRecord( arg_space , arg_label , arg_alloc_size ); +SharedAllocationRecord + *SharedAllocationRecord::allocate( + const Kokkos::CudaHostPinnedSpace &arg_space, + const std::string &arg_label, const size_t arg_alloc_size) { + return new SharedAllocationRecord(arg_space, arg_label, arg_alloc_size); } -void -SharedAllocationRecord< Kokkos::CudaSpace , void >:: -deallocate( SharedAllocationRecord< void , void > * arg_rec ) -{ - delete static_cast(arg_rec); +// end SharedAllocationRecord allocate() }}}1 +//============================================================================== + +//============================================================================== +// {{{1 + +void SharedAllocationRecord::deallocate( + SharedAllocationRecord *arg_rec) { + delete static_cast(arg_rec); } -void -SharedAllocationRecord< Kokkos::CudaUVMSpace , void >:: -deallocate( SharedAllocationRecord< void , void > * arg_rec ) -{ - delete static_cast(arg_rec); +void SharedAllocationRecord::deallocate( + SharedAllocationRecord *arg_rec) { + delete static_cast(arg_rec); } -void -SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >:: -deallocate( SharedAllocationRecord< void , void > * arg_rec ) -{ - delete static_cast(arg_rec); +void SharedAllocationRecord::deallocate( + SharedAllocationRecord *arg_rec) { + delete static_cast(arg_rec); } -SharedAllocationRecord< Kokkos::CudaSpace , void >:: -~SharedAllocationRecord() -{ - #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { +// end SharedAllocationRecord deallocate }}}1 +//============================================================================== - SharedAllocationHeader header ; - Kokkos::Impl::DeepCopy( & header , RecordBase::m_alloc_ptr , sizeof(SharedAllocationHeader) ); +//============================================================================== +// {{{1 + +SharedAllocationRecord::~SharedAllocationRecord() { +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + SharedAllocationHeader header; + Kokkos::Impl::DeepCopy( + &header, RecordBase::m_alloc_ptr, sizeof(SharedAllocationHeader)); Kokkos::Profiling::deallocateData( - Kokkos::Profiling::SpaceHandle(Kokkos::CudaSpace::name()),header.m_label, - data(),size()); + Kokkos::Profiling::SpaceHandle(Kokkos::CudaSpace::name()), + header.m_label, data(), size()); } - #endif +#endif - m_space.deallocate( SharedAllocationRecord< void , void >::m_alloc_ptr - , SharedAllocationRecord< void , void >::m_alloc_size - ); + m_space.deallocate(SharedAllocationRecord::m_alloc_ptr, + SharedAllocationRecord::m_alloc_size); } -SharedAllocationRecord< Kokkos::CudaUVMSpace , void >:: -~SharedAllocationRecord() -{ - #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Cuda::impl_static_fence(); //Make sure I can access the label ... +SharedAllocationRecord::~SharedAllocationRecord() { +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Cuda::impl_static_fence(); // Make sure I can access the label ... Kokkos::Profiling::deallocateData( - Kokkos::Profiling::SpaceHandle(Kokkos::CudaUVMSpace::name()),RecordBase::m_alloc_ptr->m_label, - data(),size()); + Kokkos::Profiling::SpaceHandle(Kokkos::CudaUVMSpace::name()), + RecordBase::m_alloc_ptr->m_label, data(), size()); } - #endif +#endif - m_space.deallocate( SharedAllocationRecord< void , void >::m_alloc_ptr - , SharedAllocationRecord< void , void >::m_alloc_size - ); + m_space.deallocate(SharedAllocationRecord::m_alloc_ptr, + SharedAllocationRecord::m_alloc_size); } -SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >:: -~SharedAllocationRecord() -{ - #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { +SharedAllocationRecord::~SharedAllocationRecord() { +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { Kokkos::Profiling::deallocateData( - Kokkos::Profiling::SpaceHandle(Kokkos::CudaHostPinnedSpace::name()),RecordBase::m_alloc_ptr->m_label, - data(),size()); + Kokkos::Profiling::SpaceHandle(Kokkos::CudaHostPinnedSpace::name()), + RecordBase::m_alloc_ptr->m_label, data(), size()); } - #endif - - m_space.deallocate( SharedAllocationRecord< void , void >::m_alloc_ptr - , SharedAllocationRecord< void , void >::m_alloc_size - ); -} - -SharedAllocationRecord< Kokkos::CudaSpace , void >:: -SharedAllocationRecord( const Kokkos::CudaSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - , const SharedAllocationRecord< void , void >::function_type arg_dealloc - ) - // Pass through allocated [ SharedAllocationHeader , user_memory ] - // Pass through deallocation function - : SharedAllocationRecord< void , void > - ( +#endif + + m_space.deallocate(SharedAllocationRecord::m_alloc_ptr, + SharedAllocationRecord::m_alloc_size); +} + +// end SharedAllocationRecord destructors }}}1 +//============================================================================== + +//============================================================================== +// {{{1 + +SharedAllocationRecord::SharedAllocationRecord( + const Kokkos::CudaSpace &arg_space, const std::string &arg_label, + const size_t arg_alloc_size, + const SharedAllocationRecord::function_type arg_dealloc) + // Pass through allocated [ SharedAllocationHeader , user_memory ] + // Pass through deallocation function + : SharedAllocationRecord( #ifdef KOKKOS_DEBUG - & SharedAllocationRecord< Kokkos::CudaSpace , void >::s_root_record, + &SharedAllocationRecord::s_root_record, #endif - reinterpret_cast( arg_space.allocate( sizeof(SharedAllocationHeader) + arg_alloc_size ) ) - , sizeof(SharedAllocationHeader) + arg_alloc_size - , arg_dealloc - ) - , m_tex_obj( 0 ) - , m_space( arg_space ) -{ - #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::allocateData(Kokkos::Profiling::SpaceHandle(arg_space.name()),arg_label,data(),arg_alloc_size); + Impl::checked_allocation_with_header(arg_space, arg_label, + arg_alloc_size), + sizeof(SharedAllocationHeader) + arg_alloc_size, arg_dealloc), + m_tex_obj(0), + m_space(arg_space) { +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::allocateData( + Kokkos::Profiling::SpaceHandle(arg_space.name()), arg_label, data(), + arg_alloc_size); } - #endif +#endif - SharedAllocationHeader header ; + SharedAllocationHeader header; // Fill in the Header information - header.m_record = static_cast< SharedAllocationRecord< void , void > * >( this ); + header.m_record = static_cast *>(this); - strncpy( header.m_label - , arg_label.c_str() - , SharedAllocationHeader::maximum_label_length - ); + strncpy(header.m_label, arg_label.c_str(), + SharedAllocationHeader::maximum_label_length); // Set last element zero, in case c_str is too long - header.m_label[SharedAllocationHeader::maximum_label_length - 1] = (char) 0; + header.m_label[SharedAllocationHeader::maximum_label_length - 1] = (char)0; // Copy to device memory - Kokkos::Impl::DeepCopy( RecordBase::m_alloc_ptr , & header , sizeof(SharedAllocationHeader) ); -} - -SharedAllocationRecord< Kokkos::CudaUVMSpace , void >:: -SharedAllocationRecord( const Kokkos::CudaUVMSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - , const SharedAllocationRecord< void , void >::function_type arg_dealloc - ) - // Pass through allocated [ SharedAllocationHeader , user_memory ] - // Pass through deallocation function - : SharedAllocationRecord< void , void > - ( + Kokkos::Impl::DeepCopy(RecordBase::m_alloc_ptr, &header, + sizeof(SharedAllocationHeader)); +} + +SharedAllocationRecord::SharedAllocationRecord( + const Kokkos::CudaUVMSpace &arg_space, const std::string &arg_label, + const size_t arg_alloc_size, + const SharedAllocationRecord::function_type arg_dealloc) + // Pass through allocated [ SharedAllocationHeader , user_memory ] + // Pass through deallocation function + : SharedAllocationRecord( #ifdef KOKKOS_DEBUG - & SharedAllocationRecord< Kokkos::CudaUVMSpace , void >::s_root_record, + &SharedAllocationRecord::s_root_record, #endif - reinterpret_cast( arg_space.allocate( sizeof(SharedAllocationHeader) + arg_alloc_size ) ) - , sizeof(SharedAllocationHeader) + arg_alloc_size - , arg_dealloc - ) - , m_tex_obj( 0 ) - , m_space( arg_space ) -{ - #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::allocateData(Kokkos::Profiling::SpaceHandle(arg_space.name()),arg_label,data(),arg_alloc_size); + Impl::checked_allocation_with_header(arg_space, arg_label, + arg_alloc_size), + sizeof(SharedAllocationHeader) + arg_alloc_size, arg_dealloc), + m_tex_obj(0), + m_space(arg_space) { +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::allocateData( + Kokkos::Profiling::SpaceHandle(arg_space.name()), arg_label, data(), + arg_alloc_size); } - #endif - // Fill in the Header information, directly accessible via UVM +#endif + // Fill in the Header information, directly accessible via UVM - RecordBase::m_alloc_ptr->m_record = this ; + RecordBase::m_alloc_ptr->m_record = this; - strncpy( RecordBase::m_alloc_ptr->m_label - , arg_label.c_str() - , SharedAllocationHeader::maximum_label_length - ); + strncpy(RecordBase::m_alloc_ptr->m_label, arg_label.c_str(), + SharedAllocationHeader::maximum_label_length); // Set last element zero, in case c_str is too long - RecordBase::m_alloc_ptr->m_label[SharedAllocationHeader::maximum_label_length - 1] = (char) 0; -} - -SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >:: -SharedAllocationRecord( const Kokkos::CudaHostPinnedSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - , const SharedAllocationRecord< void , void >::function_type arg_dealloc - ) - // Pass through allocated [ SharedAllocationHeader , user_memory ] - // Pass through deallocation function - : SharedAllocationRecord< void , void > - ( + RecordBase::m_alloc_ptr + ->m_label[SharedAllocationHeader::maximum_label_length - 1] = (char)0; +} + +SharedAllocationRecord:: + SharedAllocationRecord( + const Kokkos::CudaHostPinnedSpace &arg_space, + const std::string &arg_label, const size_t arg_alloc_size, + const SharedAllocationRecord::function_type arg_dealloc) + // Pass through allocated [ SharedAllocationHeader , user_memory ] + // Pass through deallocation function + : SharedAllocationRecord( #ifdef KOKKOS_DEBUG - & SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >::s_root_record, + &SharedAllocationRecord::s_root_record, #endif - reinterpret_cast( arg_space.allocate( sizeof(SharedAllocationHeader) + arg_alloc_size ) ) - , sizeof(SharedAllocationHeader) + arg_alloc_size - , arg_dealloc - ) - , m_space( arg_space ) -{ - #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::allocateData(Kokkos::Profiling::SpaceHandle(arg_space.name()),arg_label,data(),arg_alloc_size); + Impl::checked_allocation_with_header(arg_space, arg_label, + arg_alloc_size), + sizeof(SharedAllocationHeader) + arg_alloc_size, arg_dealloc), + m_space(arg_space) { +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::allocateData( + Kokkos::Profiling::SpaceHandle(arg_space.name()), arg_label, data(), + arg_alloc_size); } - #endif - // Fill in the Header information, directly accessible via UVM +#endif + // Fill in the Header information, directly accessible on the host - RecordBase::m_alloc_ptr->m_record = this ; + RecordBase::m_alloc_ptr->m_record = this; - strncpy( RecordBase::m_alloc_ptr->m_label - , arg_label.c_str() - , SharedAllocationHeader::maximum_label_length - ); + strncpy(RecordBase::m_alloc_ptr->m_label, arg_label.c_str(), + SharedAllocationHeader::maximum_label_length); // Set last element zero, in case c_str is too long - RecordBase::m_alloc_ptr->m_label[SharedAllocationHeader::maximum_label_length - 1] = (char) 0; + RecordBase::m_alloc_ptr + ->m_label[SharedAllocationHeader::maximum_label_length - 1] = (char)0; } -//---------------------------------------------------------------------------- +// end SharedAllocationRecord constructors }}}1 +//============================================================================== -void * SharedAllocationRecord< Kokkos::CudaSpace , void >:: -allocate_tracked( const Kokkos::CudaSpace & arg_space - , const std::string & arg_alloc_label - , const size_t arg_alloc_size ) -{ - if ( ! arg_alloc_size ) return (void *) 0 ; +//============================================================================== +// {{{1 - SharedAllocationRecord * const r = - allocate( arg_space , arg_alloc_label , arg_alloc_size ); +void *SharedAllocationRecord::allocate_tracked( + const Kokkos::CudaSpace &arg_space, const std::string &arg_alloc_label, + const size_t arg_alloc_size) { + if (!arg_alloc_size) return (void *)0; - RecordBase::increment( r ); + SharedAllocationRecord *const r = + allocate(arg_space, arg_alloc_label, arg_alloc_size); + + RecordBase::increment(r); return r->data(); } -void SharedAllocationRecord< Kokkos::CudaSpace , void >:: -deallocate_tracked( void * const arg_alloc_ptr ) -{ - if ( arg_alloc_ptr != 0 ) { - SharedAllocationRecord * const r = get_record( arg_alloc_ptr ); +void SharedAllocationRecord::deallocate_tracked( + void *const arg_alloc_ptr) { + if (arg_alloc_ptr != 0) { + SharedAllocationRecord *const r = get_record(arg_alloc_ptr); - RecordBase::decrement( r ); + RecordBase::decrement(r); } } -void * SharedAllocationRecord< Kokkos::CudaSpace , void >:: -reallocate_tracked( void * const arg_alloc_ptr - , const size_t arg_alloc_size ) -{ - SharedAllocationRecord * const r_old = get_record( arg_alloc_ptr ); - SharedAllocationRecord * const r_new = allocate( r_old->m_space , r_old->get_label() , arg_alloc_size ); +void *SharedAllocationRecord::reallocate_tracked( + void *const arg_alloc_ptr, const size_t arg_alloc_size) { + SharedAllocationRecord *const r_old = get_record(arg_alloc_ptr); + SharedAllocationRecord *const r_new = + allocate(r_old->m_space, r_old->get_label(), arg_alloc_size); - Kokkos::Impl::DeepCopy( r_new->data() , r_old->data() - , std::min( r_old->size() , r_new->size() ) ); + Kokkos::Impl::DeepCopy( + r_new->data(), r_old->data(), std::min(r_old->size(), r_new->size())); - RecordBase::increment( r_new ); - RecordBase::decrement( r_old ); + RecordBase::increment(r_new); + RecordBase::decrement(r_old); return r_new->data(); } -void * SharedAllocationRecord< Kokkos::CudaUVMSpace , void >:: -allocate_tracked( const Kokkos::CudaUVMSpace & arg_space - , const std::string & arg_alloc_label - , const size_t arg_alloc_size ) -{ - if ( ! arg_alloc_size ) return (void *) 0 ; +void *SharedAllocationRecord::allocate_tracked( + const Kokkos::CudaUVMSpace &arg_space, const std::string &arg_alloc_label, + const size_t arg_alloc_size) { + if (!arg_alloc_size) return (void *)0; - SharedAllocationRecord * const r = - allocate( arg_space , arg_alloc_label , arg_alloc_size ); + SharedAllocationRecord *const r = + allocate(arg_space, arg_alloc_label, arg_alloc_size); - RecordBase::increment( r ); + RecordBase::increment(r); return r->data(); } -void SharedAllocationRecord< Kokkos::CudaUVMSpace , void >:: -deallocate_tracked( void * const arg_alloc_ptr ) -{ - if ( arg_alloc_ptr != 0 ) { - - SharedAllocationRecord * const r = get_record( arg_alloc_ptr ); +void SharedAllocationRecord::deallocate_tracked( + void *const arg_alloc_ptr) { + if (arg_alloc_ptr != 0) { + SharedAllocationRecord *const r = get_record(arg_alloc_ptr); - RecordBase::decrement( r ); + RecordBase::decrement(r); } } -void * SharedAllocationRecord< Kokkos::CudaUVMSpace , void >:: -reallocate_tracked( void * const arg_alloc_ptr - , const size_t arg_alloc_size ) -{ - SharedAllocationRecord * const r_old = get_record( arg_alloc_ptr ); - SharedAllocationRecord * const r_new = allocate( r_old->m_space , r_old->get_label() , arg_alloc_size ); +void *SharedAllocationRecord::reallocate_tracked( + void *const arg_alloc_ptr, const size_t arg_alloc_size) { + SharedAllocationRecord *const r_old = get_record(arg_alloc_ptr); + SharedAllocationRecord *const r_new = + allocate(r_old->m_space, r_old->get_label(), arg_alloc_size); - Kokkos::Impl::DeepCopy( r_new->data() , r_old->data() - , std::min( r_old->size() , r_new->size() ) ); + Kokkos::Impl::DeepCopy( + r_new->data(), r_old->data(), std::min(r_old->size(), r_new->size())); - RecordBase::increment( r_new ); - RecordBase::decrement( r_old ); + RecordBase::increment(r_new); + RecordBase::decrement(r_old); return r_new->data(); } -void * SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >:: -allocate_tracked( const Kokkos::CudaHostPinnedSpace & arg_space - , const std::string & arg_alloc_label - , const size_t arg_alloc_size ) -{ - if ( ! arg_alloc_size ) return (void *) 0 ; +void * +SharedAllocationRecord::allocate_tracked( + const Kokkos::CudaHostPinnedSpace &arg_space, + const std::string &arg_alloc_label, const size_t arg_alloc_size) { + if (!arg_alloc_size) return (void *)0; - SharedAllocationRecord * const r = - allocate( arg_space , arg_alloc_label , arg_alloc_size ); + SharedAllocationRecord *const r = + allocate(arg_space, arg_alloc_label, arg_alloc_size); - RecordBase::increment( r ); + RecordBase::increment(r); return r->data(); } -void SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >:: -deallocate_tracked( void * const arg_alloc_ptr ) -{ - if ( arg_alloc_ptr != 0 ) { - SharedAllocationRecord * const r = get_record( arg_alloc_ptr ); +void SharedAllocationRecord::deallocate_tracked(void *const + arg_alloc_ptr) { + if (arg_alloc_ptr != 0) { + SharedAllocationRecord *const r = get_record(arg_alloc_ptr); - RecordBase::decrement( r ); + RecordBase::decrement(r); } } -void * SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >:: -reallocate_tracked( void * const arg_alloc_ptr - , const size_t arg_alloc_size ) -{ - SharedAllocationRecord * const r_old = get_record( arg_alloc_ptr ); - SharedAllocationRecord * const r_new = allocate( r_old->m_space , r_old->get_label() , arg_alloc_size ); +void * +SharedAllocationRecord::reallocate_tracked( + void *const arg_alloc_ptr, const size_t arg_alloc_size) { + SharedAllocationRecord *const r_old = get_record(arg_alloc_ptr); + SharedAllocationRecord *const r_new = + allocate(r_old->m_space, r_old->get_label(), arg_alloc_size); - Kokkos::Impl::DeepCopy( r_new->data() , r_old->data() - , std::min( r_old->size() , r_new->size() ) ); + Kokkos::Impl::DeepCopy( + r_new->data(), r_old->data(), std::min(r_old->size(), r_new->size())); - RecordBase::increment( r_new ); - RecordBase::decrement( r_old ); + RecordBase::increment(r_new); + RecordBase::decrement(r_old); return r_new->data(); } -//---------------------------------------------------------------------------- +// end SharedAllocationRecored::(re|de|)allocate_tracked }}}1 +//============================================================================== -SharedAllocationRecord< Kokkos::CudaSpace , void > * -SharedAllocationRecord< Kokkos::CudaSpace , void >::get_record( void * alloc_ptr ) -{ - using RecordCuda = SharedAllocationRecord< Kokkos::CudaSpace , void > ; +//============================================================================== +// {{{1 - using Header = SharedAllocationHeader ; +SharedAllocationRecord * +SharedAllocationRecord::get_record(void *alloc_ptr) { + using RecordCuda = SharedAllocationRecord; + + using Header = SharedAllocationHeader; // Copy the header from the allocation - Header head ; + Header head; - Header const * const head_cuda = alloc_ptr ? Header::get_header( alloc_ptr ) : (Header*) 0 ; + Header const *const head_cuda = + alloc_ptr ? Header::get_header(alloc_ptr) : (Header *)0; - if ( alloc_ptr ) { - Kokkos::Impl::DeepCopy( & head , head_cuda , sizeof(SharedAllocationHeader) ); + if (alloc_ptr) { + Kokkos::Impl::DeepCopy( + &head, head_cuda, sizeof(SharedAllocationHeader)); } - RecordCuda * const record = alloc_ptr ? static_cast< RecordCuda * >( head.m_record ) : (RecordCuda *) 0 ; + RecordCuda *const record = + alloc_ptr ? static_cast(head.m_record) : (RecordCuda *)0; - if ( ! alloc_ptr || record->m_alloc_ptr != head_cuda ) { - Kokkos::Impl::throw_runtime_exception( std::string("Kokkos::Impl::SharedAllocationRecord< Kokkos::CudaSpace , void >::get_record ERROR" ) ); + if (!alloc_ptr || record->m_alloc_ptr != head_cuda) { + Kokkos::Impl::throw_runtime_exception( + std::string("Kokkos::Impl::SharedAllocationRecord< Kokkos::CudaSpace , " + "void >::get_record ERROR")); } - return record ; + return record; } -SharedAllocationRecord< Kokkos::CudaUVMSpace , void > * -SharedAllocationRecord< Kokkos::CudaUVMSpace , void >::get_record( void * alloc_ptr ) -{ - using Header = SharedAllocationHeader ; - using RecordCuda = SharedAllocationRecord< Kokkos::CudaUVMSpace , void > ; +SharedAllocationRecord *SharedAllocationRecord< + Kokkos::CudaUVMSpace, void>::get_record(void *alloc_ptr) { + using Header = SharedAllocationHeader; + using RecordCuda = SharedAllocationRecord; - Header * const h = alloc_ptr ? reinterpret_cast< Header * >( alloc_ptr ) - 1 : (Header *) 0 ; + Header *const h = + alloc_ptr ? reinterpret_cast
    (alloc_ptr) - 1 : (Header *)0; - if ( ! alloc_ptr || h->m_record->m_alloc_ptr != h ) { - Kokkos::Impl::throw_runtime_exception( std::string("Kokkos::Impl::SharedAllocationRecord< Kokkos::CudaUVMSpace , void >::get_record ERROR" ) ); + if (!alloc_ptr || h->m_record->m_alloc_ptr != h) { + Kokkos::Impl::throw_runtime_exception( + std::string("Kokkos::Impl::SharedAllocationRecord< " + "Kokkos::CudaUVMSpace , void >::get_record ERROR")); } - return static_cast< RecordCuda * >( h->m_record ); + return static_cast(h->m_record); } -SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void > * -SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >::get_record( void * alloc_ptr ) -{ - using Header = SharedAllocationHeader ; - using RecordCuda = SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void > ; +SharedAllocationRecord + *SharedAllocationRecord::get_record( + void *alloc_ptr) { + using Header = SharedAllocationHeader; + using RecordCuda = SharedAllocationRecord; - Header * const h = alloc_ptr ? reinterpret_cast< Header * >( alloc_ptr ) - 1 : (Header *) 0 ; + Header *const h = + alloc_ptr ? reinterpret_cast
    (alloc_ptr) - 1 : (Header *)0; - if ( ! alloc_ptr || h->m_record->m_alloc_ptr != h ) { - Kokkos::Impl::throw_runtime_exception( std::string("Kokkos::Impl::SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >::get_record ERROR" ) ); + if (!alloc_ptr || h->m_record->m_alloc_ptr != h) { + Kokkos::Impl::throw_runtime_exception( + std::string("Kokkos::Impl::SharedAllocationRecord< " + "Kokkos::CudaHostPinnedSpace , void >::get_record ERROR")); } - return static_cast< RecordCuda * >( h->m_record ); + return static_cast(h->m_record); } +// end SharedAllocationRecord::get_record() }}}1 +//============================================================================== + +//============================================================================== +// {{{1 + // Iterate records to print orphaned memory ... -void -SharedAllocationRecord< Kokkos::CudaSpace , void >:: -print_records( std::ostream & s , const Kokkos::CudaSpace & , bool detail ) -{ +void SharedAllocationRecord::print_records( + std::ostream &s, const Kokkos::CudaSpace &, bool detail) { #ifdef KOKKOS_DEBUG - SharedAllocationRecord< void , void > * r = & s_root_record ; + SharedAllocationRecord *r = &s_root_record; - char buffer[256] ; + char buffer[256]; - SharedAllocationHeader head ; + SharedAllocationHeader head; - if ( detail ) { + if (detail) { do { - if ( r->m_alloc_ptr ) { - Kokkos::Impl::DeepCopy( & head , r->m_alloc_ptr , sizeof(SharedAllocationHeader) ); - } - else { - head.m_label[0] = 0 ; + if (r->m_alloc_ptr) { + Kokkos::Impl::DeepCopy( + &head, r->m_alloc_ptr, sizeof(SharedAllocationHeader)); + } else { + head.m_label[0] = 0; } - //Formatting dependent on sizeof(uintptr_t) - const char * format_string; + // Formatting dependent on sizeof(uintptr_t) + const char *format_string; if (sizeof(uintptr_t) == sizeof(unsigned long)) { - format_string = "Cuda addr( 0x%.12lx ) list( 0x%.12lx 0x%.12lx ) extent[ 0x%.12lx + %.8ld ] count(%d) dealloc(0x%.12lx) %s\n"; - } - else if (sizeof(uintptr_t) == sizeof(unsigned long long)) { - format_string = "Cuda addr( 0x%.12llx ) list( 0x%.12llx 0x%.12llx ) extent[ 0x%.12llx + %.8ld ] count(%d) dealloc(0x%.12llx) %s\n"; + format_string = + "Cuda addr( 0x%.12lx ) list( 0x%.12lx 0x%.12lx ) extent[ 0x%.12lx " + "+ %.8ld ] count(%d) dealloc(0x%.12lx) %s\n"; + } else if (sizeof(uintptr_t) == sizeof(unsigned long long)) { + format_string = + "Cuda addr( 0x%.12llx ) list( 0x%.12llx 0x%.12llx ) extent[ " + "0x%.12llx + %.8ld ] count(%d) dealloc(0x%.12llx) %s\n"; } - snprintf( buffer , 256 - , format_string - , reinterpret_cast( r ) - , reinterpret_cast( r->m_prev ) - , reinterpret_cast( r->m_next ) - , reinterpret_cast( r->m_alloc_ptr ) - , r->m_alloc_size - , r->m_count - , reinterpret_cast( r->m_dealloc ) - , head.m_label - ); - s << buffer ; - r = r->m_next ; - } while ( r != & s_root_record ); - } - else { + snprintf(buffer, 256, format_string, reinterpret_cast(r), + reinterpret_cast(r->m_prev), + reinterpret_cast(r->m_next), + reinterpret_cast(r->m_alloc_ptr), r->m_alloc_size, + r->m_count, reinterpret_cast(r->m_dealloc), + head.m_label); + s << buffer; + r = r->m_next; + } while (r != &s_root_record); + } else { do { - if ( r->m_alloc_ptr ) { - - Kokkos::Impl::DeepCopy( & head , r->m_alloc_ptr , sizeof(SharedAllocationHeader) ); + if (r->m_alloc_ptr) { + Kokkos::Impl::DeepCopy( + &head, r->m_alloc_ptr, sizeof(SharedAllocationHeader)); - //Formatting dependent on sizeof(uintptr_t) - const char * format_string; + // Formatting dependent on sizeof(uintptr_t) + const char *format_string; if (sizeof(uintptr_t) == sizeof(unsigned long)) { format_string = "Cuda [ 0x%.12lx + %ld ] %s\n"; - } - else if (sizeof(uintptr_t) == sizeof(unsigned long long)) { + } else if (sizeof(uintptr_t) == sizeof(unsigned long long)) { format_string = "Cuda [ 0x%.12llx + %ld ] %s\n"; } - snprintf( buffer , 256 - , format_string - , reinterpret_cast< uintptr_t >( r->data() ) - , r->size() - , head.m_label - ); - } - else { - snprintf( buffer , 256 , "Cuda [ 0 + 0 ]\n" ); + snprintf(buffer, 256, format_string, + reinterpret_cast(r->data()), r->size(), + head.m_label); + } else { + snprintf(buffer, 256, "Cuda [ 0 + 0 ]\n"); } - s << buffer ; - r = r->m_next ; - } while ( r != & s_root_record ); + s << buffer; + r = r->m_next; + } while (r != &s_root_record); } #else - Kokkos::Impl::throw_runtime_exception("SharedAllocationHeader::print_records only works with KOKKOS_DEBUG enabled"); + Kokkos::Impl::throw_runtime_exception( + "SharedAllocationHeader::print_records only works with " + "KOKKOS_DEBUG enabled"); #endif } -void -SharedAllocationRecord< Kokkos::CudaUVMSpace , void >:: -print_records( std::ostream & s , const Kokkos::CudaUVMSpace & , bool detail ) -{ +void SharedAllocationRecord::print_records( + std::ostream &s, const Kokkos::CudaUVMSpace &, bool detail) { #ifdef KOKKOS_DEBUG - SharedAllocationRecord< void , void >::print_host_accessible_records( s , "CudaUVM" , & s_root_record , detail ); + SharedAllocationRecord::print_host_accessible_records( + s, "CudaUVM", &s_root_record, detail); #else - Kokkos::Impl::throw_runtime_exception("SharedAllocationHeader::print_records only works with KOKKOS_DEBUG enabled"); + Kokkos::Impl::throw_runtime_exception( + "SharedAllocationHeader::print_records only works with " + "KOKKOS_DEBUG enabled"); #endif } -void -SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >:: -print_records( std::ostream & s , const Kokkos::CudaHostPinnedSpace & , bool detail ) -{ +void SharedAllocationRecord::print_records( + std::ostream &s, const Kokkos::CudaHostPinnedSpace &, bool detail) { #ifdef KOKKOS_DEBUG - SharedAllocationRecord< void , void >::print_host_accessible_records( s , "CudaHostPinned" , & s_root_record , detail ); + SharedAllocationRecord::print_host_accessible_records( + s, "CudaHostPinned", &s_root_record, detail); #else - Kokkos::Impl::throw_runtime_exception("SharedAllocationHeader::print_records only works with KOKKOS_DEBUG enabled"); + Kokkos::Impl::throw_runtime_exception( + "SharedAllocationHeader::print_records only works with " + "KOKKOS_DEBUG enabled"); #endif } -void* cuda_resize_scratch_space(std::int64_t bytes, bool force_shrink) { - static void* ptr = NULL; +// end SharedAllocationRecord::print_records() }}}1 +//============================================================================== + +void *cuda_resize_scratch_space(std::int64_t bytes, bool force_shrink) { + static void *ptr = NULL; static std::int64_t current_size = 0; - if(current_size == 0) { + if (current_size == 0) { current_size = bytes; - ptr = Kokkos::kokkos_malloc("CudaSpace::ScratchMemory",current_size); + ptr = Kokkos::kokkos_malloc("CudaSpace::ScratchMemory", + current_size); } - if(bytes > current_size) { + if (bytes > current_size) { current_size = bytes; Kokkos::kokkos_free(ptr); - ptr = Kokkos::kokkos_malloc("CudaSpace::ScratchMemory",current_size); + ptr = Kokkos::kokkos_malloc("CudaSpace::ScratchMemory", + current_size); } - if((bytes < current_size) && (force_shrink)) { + if ((bytes < current_size) && (force_shrink)) { current_size = bytes; Kokkos::kokkos_free(ptr); - ptr = Kokkos::kokkos_malloc("CudaSpace::ScratchMemory",current_size); + ptr = Kokkos::kokkos_malloc("CudaSpace::ScratchMemory", + current_size); } return ptr; } -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos #else void KOKKOS_CORE_SRC_CUDA_CUDASPACE_PREVENT_LINK_ERROR() {} -#endif // KOKKOS_ENABLE_CUDA - +#endif // KOKKOS_ENABLE_CUDA diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Alloc.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Alloc.hpp index 5726e02180..e76133fae8 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Alloc.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Alloc.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -52,13 +53,12 @@ namespace Kokkos { namespace Impl { -template< class DestructFunctor > -SharedAllocationRecord * -shared_allocation_record( Kokkos::CudaSpace const & arg_space - , void * const arg_alloc_ptr - , DestructFunctor const & arg_destruct ) -{ - SharedAllocationRecord * const record = SharedAllocationRecord::get_record( arg_alloc_ptr ); +template +SharedAllocationRecord* shared_allocation_record( + Kokkos::CudaSpace const& arg_space, void* const arg_alloc_ptr, + DestructFunctor const& arg_destruct) { + SharedAllocationRecord* const record = + SharedAllocationRecord::get_record(arg_alloc_ptr); // assert: record != 0 @@ -66,115 +66,88 @@ shared_allocation_record( Kokkos::CudaSpace const & arg_space // assert: record->m_destruct_function == 0 - DestructFunctor * const functor = - reinterpret_cast< DestructFunctor * >( - reinterpret_cast< uintptr_t >( record ) + sizeof(SharedAllocationRecord) ); + DestructFunctor* const functor = reinterpret_cast( + reinterpret_cast(record) + sizeof(SharedAllocationRecord)); - new( functor ) DestructFunctor( arg_destruct ); + new (functor) DestructFunctor(arg_destruct); - record->m_destruct_functor = & shared_allocation_destroy< DestructFunctor > ; + record->m_destruct_functor = &shared_allocation_destroy; - return record ; + return record; } - /// class CudaUnmanagedAllocator /// does nothing when deallocate(ptr,size) is called -struct CudaUnmanagedAllocator -{ - static const char * name() - { - return "Cuda Unmanaged Allocator"; - } +struct CudaUnmanagedAllocator { + static const char* name() { return "Cuda Unmanaged Allocator"; } - static void deallocate(void * /*ptr*/, size_t /*size*/) {} + static void deallocate(void* /*ptr*/, size_t /*size*/) {} static bool support_texture_binding() { return true; } }; /// class CudaUnmanagedAllocator /// does nothing when deallocate(ptr,size) is called -struct CudaUnmanagedUVMAllocator -{ - static const char * name() - { - return "Cuda Unmanaged UVM Allocator"; - } +struct CudaUnmanagedUVMAllocator { + static const char* name() { return "Cuda Unmanaged UVM Allocator"; } - static void deallocate(void * /*ptr*/, size_t /*size*/) {} + static void deallocate(void* /*ptr*/, size_t /*size*/) {} static bool support_texture_binding() { return true; } }; /// class CudaUnmanagedHostAllocator /// does nothing when deallocate(ptr,size) is called -class CudaUnmanagedHostAllocator -{ -public: - static const char * name() - { - return "Cuda Unmanaged Host Allocator"; - } +class CudaUnmanagedHostAllocator { + public: + static const char* name() { return "Cuda Unmanaged Host Allocator"; } // Unmanaged deallocate does nothing - static void deallocate(void * /*ptr*/, size_t /*size*/) {} + static void deallocate(void* /*ptr*/, size_t /*size*/) {} }; /// class CudaMallocAllocator -class CudaMallocAllocator -{ -public: - static const char * name() - { - return "Cuda Malloc Allocator"; - } +class CudaMallocAllocator { + public: + static const char* name() { return "Cuda Malloc Allocator"; } static void* allocate(size_t size); - static void deallocate(void * ptr, size_t); + static void deallocate(void* ptr, size_t); - static void * reallocate(void * old_ptr, size_t old_size, size_t new_size); + static void* reallocate(void* old_ptr, size_t old_size, size_t new_size); static bool support_texture_binding() { return true; } }; /// class CudaUVMAllocator -class CudaUVMAllocator -{ -public: - static const char * name() - { - return "Cuda UVM Allocator"; - } +class CudaUVMAllocator { + public: + static const char* name() { return "Cuda UVM Allocator"; } static void* allocate(size_t size); - static void deallocate(void * ptr, size_t); + static void deallocate(void* ptr, size_t); - static void * reallocate(void * old_ptr, size_t old_size, size_t new_size); + static void* reallocate(void* old_ptr, size_t old_size, size_t new_size); static bool support_texture_binding() { return true; } }; /// class CudaHostAllocator -class CudaHostAllocator -{ -public: - static const char * name() - { - return "Cuda Host Allocator"; - } +class CudaHostAllocator { + public: + static const char* name() { return "Cuda Host Allocator"; } static void* allocate(size_t size); - static void deallocate(void * ptr, size_t); + static void deallocate(void* ptr, size_t); - static void * reallocate(void * old_ptr, size_t old_size, size_t new_size); + static void* reallocate(void* old_ptr, size_t old_size, size_t new_size); }; +} // namespace Impl +} // namespace Kokkos -}} // namespace Kokkos::Impl - -#endif //KOKKOS_ENABLE_CUDA - -#endif // #ifndef KOKKOS_CUDA_ALLOCATION_TRACKING_HPP +#endif // KOKKOS_ENABLE_CUDA +#endif // #ifndef KOKKOS_CUDA_ALLOCATION_TRACKING_HPP diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Atomic_Intrinsics.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Atomic_Intrinsics.hpp index 9d4bcbc8cf..8a6c0433c8 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Atomic_Intrinsics.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Atomic_Intrinsics.hpp @@ -32,10 +32,10 @@ LICENSE ASSOCIATED WITH SUBSEQUENT MODIFICATIONS // ************************************************************************ // -// Kokkos v. 2.0 +// Kokkos v. 3.0 // Copyright (2019) Sandia Corporation // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -53,10 +53,10 @@ LICENSE ASSOCIATED WITH SUBSEQUENT MODIFICATIONS // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -82,85 +82,334 @@ LICENSE ASSOCIATED WITH SUBSEQUENT MODIFICATIONS namespace Kokkos { namespace Impl { - #ifndef __simt_scope // Modification: Kokkos GPU atomics should default to `gpu` scope #define __simt_scope "gpu" #endif -#define __simt_fence_signal_() asm volatile("":::"memory") -#define __simt_fence_sc_() asm volatile("fence.sc." __simt_scope ";":::"memory") -#define __simt_fence_() asm volatile("fence." __simt_scope ";":::"memory") - -#define __simt_load_acquire_8_as_32(ptr,ret) asm volatile("ld.acquire." __simt_scope ".b8 %0, [%1];" : "=r"(ret) : "l"(ptr) : "memory") -#define __simt_load_relaxed_8_as_32(ptr,ret) asm volatile("ld.relaxed." __simt_scope ".b8 %0, [%1];" : "=r"(ret) : "l"(ptr) : "memory") -#define __simt_store_release_8_as_32(ptr,desired) asm volatile("st.release." __simt_scope ".b8 [%0], %1;" :: "l"(ptr), "r"(desired) : "memory") -#define __simt_store_relaxed_8_as_32(ptr,desired) asm volatile("st.relaxed." __simt_scope ".b8 [%0], %1;" :: "l"(ptr), "r"(desired) : "memory") - -#define __simt_load_acquire_16(ptr,ret) asm volatile("ld.acquire." __simt_scope ".b16 %0, [%1];" : "=h"(ret) : "l"(ptr) : "memory") -#define __simt_load_relaxed_16(ptr,ret) asm volatile("ld.relaxed." __simt_scope ".b16 %0, [%1];" : "=h"(ret) : "l"(ptr) : "memory") -#define __simt_store_release_16(ptr,desired) asm volatile("st.release." __simt_scope ".b16 [%0], %1;" :: "l"(ptr), "h"(desired) : "memory") -#define __simt_store_relaxed_16(ptr,desired) asm volatile("st.relaxed." __simt_scope ".b16 [%0], %1;" :: "l"(ptr), "h"(desired) : "memory") - -#define __simt_load_acquire_32(ptr,ret) asm volatile("ld.acquire." __simt_scope ".b32 %0, [%1];" : "=r"(ret) : "l"(ptr) : "memory") -#define __simt_load_relaxed_32(ptr,ret) asm volatile("ld.relaxed." __simt_scope ".b32 %0, [%1];" : "=r"(ret) : "l"(ptr) : "memory") -#define __simt_store_release_32(ptr,desired) asm volatile("st.release." __simt_scope ".b32 [%0], %1;" :: "l"(ptr), "r"(desired) : "memory") -#define __simt_store_relaxed_32(ptr,desired) asm volatile("st.relaxed." __simt_scope ".b32 [%0], %1;" :: "l"(ptr), "r"(desired) : "memory") -#define __simt_exch_release_32(ptr,old,desired) asm volatile("atom.exch.release." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(desired) : "memory") -#define __simt_exch_acquire_32(ptr,old,desired) asm volatile("atom.exch.acquire." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(desired) : "memory") -#define __simt_exch_acq_rel_32(ptr,old,desired) asm volatile("atom.exch.acq_rel." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(desired) : "memory") -#define __simt_exch_relaxed_32(ptr,old,desired) asm volatile("atom.exch.relaxed." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(desired) : "memory") -#define __simt_cas_release_32(ptr,old,expected,desired) asm volatile("atom.cas.release." __simt_scope ".b32 %0, [%1], %2, %3;" : "=r"(old) : "l"(ptr), "r"(expected), "r"(desired) : "memory") -#define __simt_cas_acquire_32(ptr,old,expected,desired) asm volatile("atom.cas.acquire." __simt_scope ".b32 %0, [%1], %2, %3;" : "=r"(old) : "l"(ptr), "r"(expected), "r"(desired) : "memory") -#define __simt_cas_acq_rel_32(ptr,old,expected,desired) asm volatile("atom.cas.acq_rel." __simt_scope ".b32 %0, [%1], %2, %3;" : "=r"(old) : "l"(ptr), "r"(expected), "r"(desired) : "memory") -#define __simt_cas_relaxed_32(ptr,old,expected,desired) asm volatile("atom.cas.relaxed." __simt_scope ".b32 %0, [%1], %2, %3;" : "=r"(old) : "l"(ptr), "r"(expected), "r"(desired) : "memory") -#define __simt_add_release_32(ptr,old,addend) asm volatile("atom.add.release." __simt_scope ".u32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(addend) : "memory") -#define __simt_add_acquire_32(ptr,old,addend) asm volatile("atom.add.acquire." __simt_scope ".u32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(addend) : "memory") -#define __simt_add_acq_rel_32(ptr,old,addend) asm volatile("atom.add.acq_rel." __simt_scope ".u32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(addend) : "memory") -#define __simt_add_relaxed_32(ptr,old,addend) asm volatile("atom.add.relaxed." __simt_scope ".u32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(addend) : "memory") -#define __simt_and_release_32(ptr,old,andend) asm volatile("atom.and.release." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(andend) : "memory") -#define __simt_and_acquire_32(ptr,old,andend) asm volatile("atom.and.acquire." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(andend) : "memory") -#define __simt_and_acq_rel_32(ptr,old,andend) asm volatile("atom.and.acq_rel." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(andend) : "memory") -#define __simt_and_relaxed_32(ptr,old,andend) asm volatile("atom.and.relaxed." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(andend) : "memory") -#define __simt_or_release_32(ptr,old,orend) asm volatile("atom.or.release." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(orend) : "memory") -#define __simt_or_acquire_32(ptr,old,orend) asm volatile("atom.or.acquire." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(orend) : "memory") -#define __simt_or_acq_rel_32(ptr,old,orend) asm volatile("atom.or.acq_rel." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(orend) : "memory") -#define __simt_or_relaxed_32(ptr,old,orend) asm volatile("atom.or.relaxed." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(orend) : "memory") -#define __simt_xor_release_32(ptr,old,xorend) asm volatile("atom.xor.release." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(xorend) : "memory") -#define __simt_xor_acquire_32(ptr,old,xorend) asm volatile("atom.xor.acquire." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(xorend) : "memory") -#define __simt_xor_acq_rel_32(ptr,old,xorend) asm volatile("atom.xor.acq_rel." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(xorend) : "memory") -#define __simt_xor_relaxed_32(ptr,old,xorend) asm volatile("atom.xor.relaxed." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(xorend) : "memory") - -#define __simt_load_acquire_64(ptr,ret) asm volatile("ld.acquire." __simt_scope ".b64 %0, [%1];" : "=l"(ret) : "l"(ptr) : "memory") -#define __simt_load_relaxed_64(ptr,ret) asm volatile("ld.relaxed." __simt_scope ".b64 %0, [%1];" : "=l"(ret) : "l"(ptr) : "memory") -#define __simt_store_release_64(ptr,desired) asm volatile("st.release." __simt_scope ".b64 [%0], %1;" :: "l"(ptr), "l"(desired) : "memory") -#define __simt_store_relaxed_64(ptr,desired) asm volatile("st.relaxed." __simt_scope ".b64 [%0], %1;" :: "l"(ptr), "l"(desired) : "memory") -#define __simt_exch_release_64(ptr,old,desired) asm volatile("atom.exch.release." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(desired) : "memory") -#define __simt_exch_acquire_64(ptr,old,desired) asm volatile("atom.exch.acquire." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(desired) : "memory") -#define __simt_exch_acq_rel_64(ptr,old,desired) asm volatile("atom.exch.acq_rel." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(desired) : "memory") -#define __simt_exch_relaxed_64(ptr,old,desired) asm volatile("atom.exch.relaxed." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(desired) : "memory") -#define __simt_cas_release_64(ptr,old,expected,desired) asm volatile("atom.cas.release." __simt_scope ".b64 %0, [%1], %2, %3;" : "=l"(old) : "l"(ptr), "l"(expected), "l"(desired) : "memory") -#define __simt_cas_acquire_64(ptr,old,expected,desired) asm volatile("atom.cas.acquire." __simt_scope ".b64 %0, [%1], %2, %3;" : "=l"(old) : "l"(ptr), "l"(expected), "l"(desired) : "memory") -#define __simt_cas_acq_rel_64(ptr,old,expected,desired) asm volatile("atom.cas.acq_rel." __simt_scope ".b64 %0, [%1], %2, %3;" : "=l"(old) : "l"(ptr), "l"(expected), "l"(desired) : "memory") -#define __simt_cas_relaxed_64(ptr,old,expected,desired) asm volatile("atom.cas.relaxed." __simt_scope ".b64 %0, [%1], %2, %3;" : "=l"(old) : "l"(ptr), "l"(expected), "l"(desired) : "memory") -#define __simt_add_release_64(ptr,old,addend) asm volatile("atom.add.release." __simt_scope ".u64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(addend) : "memory") -#define __simt_add_acquire_64(ptr,old,addend) asm volatile("atom.add.acquire." __simt_scope ".u64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(addend) : "memory") -#define __simt_add_acq_rel_64(ptr,old,addend) asm volatile("atom.add.acq_rel." __simt_scope ".u64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(addend) : "memory") -#define __simt_add_relaxed_64(ptr,old,addend) asm volatile("atom.add.relaxed." __simt_scope ".u64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(addend) : "memory") -#define __simt_and_release_64(ptr,old,andend) asm volatile("atom.and.release." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(andend) : "memory") -#define __simt_and_acquire_64(ptr,old,andend) asm volatile("atom.and.acquire." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(andend) : "memory") -#define __simt_and_acq_rel_64(ptr,old,andend) asm volatile("atom.and.acq_rel." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(andend) : "memory") -#define __simt_and_relaxed_64(ptr,old,andend) asm volatile("atom.and.relaxed." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(andend) : "memory") -#define __simt_or_release_64(ptr,old,orend) asm volatile("atom.or.release." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(orend) : "memory") -#define __simt_or_acquire_64(ptr,old,orend) asm volatile("atom.or.acquire." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(orend) : "memory") -#define __simt_or_acq_rel_64(ptr,old,orend) asm volatile("atom.or.acq_rel." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(orend) : "memory") -#define __simt_or_relaxed_64(ptr,old,orend) asm volatile("atom.or.relaxed." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(orend) : "memory") -#define __simt_xor_release_64(ptr,old,xorend) asm volatile("atom.xor.release." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(xorend) : "memory") -#define __simt_xor_acquire_64(ptr,old,xorend) asm volatile("atom.xor.acquire." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(xorend) : "memory") -#define __simt_xor_acq_rel_64(ptr,old,xorend) asm volatile("atom.xor.acq_rel." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(xorend) : "memory") -#define __simt_xor_relaxed_64(ptr,old,xorend) asm volatile("atom.xor.relaxed." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(xorend) : "memory") - -#define __simt_nanosleep(timeout) asm volatile("nanosleep.u32 %0;" :: "r"(unsigned(timeout)) : ) +#define __simt_fence_signal_() asm volatile("" ::: "memory") +#define __simt_fence_sc_() \ + asm volatile("fence.sc." __simt_scope ";" ::: "memory") +#define __simt_fence_() asm volatile("fence." __simt_scope ";" ::: "memory") + +#define __simt_load_acquire_8_as_32(ptr, ret) \ + asm volatile("ld.acquire." __simt_scope ".b8 %0, [%1];" \ + : "=r"(ret) \ + : "l"(ptr) \ + : "memory") +#define __simt_load_relaxed_8_as_32(ptr, ret) \ + asm volatile("ld.relaxed." __simt_scope ".b8 %0, [%1];" \ + : "=r"(ret) \ + : "l"(ptr) \ + : "memory") +#define __simt_store_release_8_as_32(ptr, desired) \ + asm volatile("st.release." __simt_scope ".b8 [%0], %1;" ::"l"(ptr), \ + "r"(desired) \ + : "memory") +#define __simt_store_relaxed_8_as_32(ptr, desired) \ + asm volatile("st.relaxed." __simt_scope ".b8 [%0], %1;" ::"l"(ptr), \ + "r"(desired) \ + : "memory") + +#define __simt_load_acquire_16(ptr, ret) \ + asm volatile("ld.acquire." __simt_scope ".b16 %0, [%1];" \ + : "=h"(ret) \ + : "l"(ptr) \ + : "memory") +#define __simt_load_relaxed_16(ptr, ret) \ + asm volatile("ld.relaxed." __simt_scope ".b16 %0, [%1];" \ + : "=h"(ret) \ + : "l"(ptr) \ + : "memory") +#define __simt_store_release_16(ptr, desired) \ + asm volatile("st.release." __simt_scope ".b16 [%0], %1;" ::"l"(ptr), \ + "h"(desired) \ + : "memory") +#define __simt_store_relaxed_16(ptr, desired) \ + asm volatile("st.relaxed." __simt_scope ".b16 [%0], %1;" ::"l"(ptr), \ + "h"(desired) \ + : "memory") + +#define __simt_load_acquire_32(ptr, ret) \ + asm volatile("ld.acquire." __simt_scope ".b32 %0, [%1];" \ + : "=r"(ret) \ + : "l"(ptr) \ + : "memory") +#define __simt_load_relaxed_32(ptr, ret) \ + asm volatile("ld.relaxed." __simt_scope ".b32 %0, [%1];" \ + : "=r"(ret) \ + : "l"(ptr) \ + : "memory") +#define __simt_store_release_32(ptr, desired) \ + asm volatile("st.release." __simt_scope ".b32 [%0], %1;" ::"l"(ptr), \ + "r"(desired) \ + : "memory") +#define __simt_store_relaxed_32(ptr, desired) \ + asm volatile("st.relaxed." __simt_scope ".b32 [%0], %1;" ::"l"(ptr), \ + "r"(desired) \ + : "memory") +#define __simt_exch_release_32(ptr, old, desired) \ + asm volatile("atom.exch.release." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(desired) \ + : "memory") +#define __simt_exch_acquire_32(ptr, old, desired) \ + asm volatile("atom.exch.acquire." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(desired) \ + : "memory") +#define __simt_exch_acq_rel_32(ptr, old, desired) \ + asm volatile("atom.exch.acq_rel." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(desired) \ + : "memory") +#define __simt_exch_relaxed_32(ptr, old, desired) \ + asm volatile("atom.exch.relaxed." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(desired) \ + : "memory") +#define __simt_cas_release_32(ptr, old, expected, desired) \ + asm volatile("atom.cas.release." __simt_scope ".b32 %0, [%1], %2, %3;" \ + : "=r"(old) \ + : "l"(ptr), "r"(expected), "r"(desired) \ + : "memory") +#define __simt_cas_acquire_32(ptr, old, expected, desired) \ + asm volatile("atom.cas.acquire." __simt_scope ".b32 %0, [%1], %2, %3;" \ + : "=r"(old) \ + : "l"(ptr), "r"(expected), "r"(desired) \ + : "memory") +#define __simt_cas_acq_rel_32(ptr, old, expected, desired) \ + asm volatile("atom.cas.acq_rel." __simt_scope ".b32 %0, [%1], %2, %3;" \ + : "=r"(old) \ + : "l"(ptr), "r"(expected), "r"(desired) \ + : "memory") +#define __simt_cas_relaxed_32(ptr, old, expected, desired) \ + asm volatile("atom.cas.relaxed." __simt_scope ".b32 %0, [%1], %2, %3;" \ + : "=r"(old) \ + : "l"(ptr), "r"(expected), "r"(desired) \ + : "memory") +#define __simt_add_release_32(ptr, old, addend) \ + asm volatile("atom.add.release." __simt_scope ".u32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(addend) \ + : "memory") +#define __simt_add_acquire_32(ptr, old, addend) \ + asm volatile("atom.add.acquire." __simt_scope ".u32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(addend) \ + : "memory") +#define __simt_add_acq_rel_32(ptr, old, addend) \ + asm volatile("atom.add.acq_rel." __simt_scope ".u32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(addend) \ + : "memory") +#define __simt_add_relaxed_32(ptr, old, addend) \ + asm volatile("atom.add.relaxed." __simt_scope ".u32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(addend) \ + : "memory") +#define __simt_and_release_32(ptr, old, andend) \ + asm volatile("atom.and.release." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(andend) \ + : "memory") +#define __simt_and_acquire_32(ptr, old, andend) \ + asm volatile("atom.and.acquire." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(andend) \ + : "memory") +#define __simt_and_acq_rel_32(ptr, old, andend) \ + asm volatile("atom.and.acq_rel." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(andend) \ + : "memory") +#define __simt_and_relaxed_32(ptr, old, andend) \ + asm volatile("atom.and.relaxed." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(andend) \ + : "memory") +#define __simt_or_release_32(ptr, old, orend) \ + asm volatile("atom.or.release." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(orend) \ + : "memory") +#define __simt_or_acquire_32(ptr, old, orend) \ + asm volatile("atom.or.acquire." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(orend) \ + : "memory") +#define __simt_or_acq_rel_32(ptr, old, orend) \ + asm volatile("atom.or.acq_rel." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(orend) \ + : "memory") +#define __simt_or_relaxed_32(ptr, old, orend) \ + asm volatile("atom.or.relaxed." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(orend) \ + : "memory") +#define __simt_xor_release_32(ptr, old, xorend) \ + asm volatile("atom.xor.release." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(xorend) \ + : "memory") +#define __simt_xor_acquire_32(ptr, old, xorend) \ + asm volatile("atom.xor.acquire." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(xorend) \ + : "memory") +#define __simt_xor_acq_rel_32(ptr, old, xorend) \ + asm volatile("atom.xor.acq_rel." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(xorend) \ + : "memory") +#define __simt_xor_relaxed_32(ptr, old, xorend) \ + asm volatile("atom.xor.relaxed." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(xorend) \ + : "memory") + +#define __simt_load_acquire_64(ptr, ret) \ + asm volatile("ld.acquire." __simt_scope ".b64 %0, [%1];" \ + : "=l"(ret) \ + : "l"(ptr) \ + : "memory") +#define __simt_load_relaxed_64(ptr, ret) \ + asm volatile("ld.relaxed." __simt_scope ".b64 %0, [%1];" \ + : "=l"(ret) \ + : "l"(ptr) \ + : "memory") +#define __simt_store_release_64(ptr, desired) \ + asm volatile("st.release." __simt_scope ".b64 [%0], %1;" ::"l"(ptr), \ + "l"(desired) \ + : "memory") +#define __simt_store_relaxed_64(ptr, desired) \ + asm volatile("st.relaxed." __simt_scope ".b64 [%0], %1;" ::"l"(ptr), \ + "l"(desired) \ + : "memory") +#define __simt_exch_release_64(ptr, old, desired) \ + asm volatile("atom.exch.release." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(desired) \ + : "memory") +#define __simt_exch_acquire_64(ptr, old, desired) \ + asm volatile("atom.exch.acquire." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(desired) \ + : "memory") +#define __simt_exch_acq_rel_64(ptr, old, desired) \ + asm volatile("atom.exch.acq_rel." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(desired) \ + : "memory") +#define __simt_exch_relaxed_64(ptr, old, desired) \ + asm volatile("atom.exch.relaxed." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(desired) \ + : "memory") +#define __simt_cas_release_64(ptr, old, expected, desired) \ + asm volatile("atom.cas.release." __simt_scope ".b64 %0, [%1], %2, %3;" \ + : "=l"(old) \ + : "l"(ptr), "l"(expected), "l"(desired) \ + : "memory") +#define __simt_cas_acquire_64(ptr, old, expected, desired) \ + asm volatile("atom.cas.acquire." __simt_scope ".b64 %0, [%1], %2, %3;" \ + : "=l"(old) \ + : "l"(ptr), "l"(expected), "l"(desired) \ + : "memory") +#define __simt_cas_acq_rel_64(ptr, old, expected, desired) \ + asm volatile("atom.cas.acq_rel." __simt_scope ".b64 %0, [%1], %2, %3;" \ + : "=l"(old) \ + : "l"(ptr), "l"(expected), "l"(desired) \ + : "memory") +#define __simt_cas_relaxed_64(ptr, old, expected, desired) \ + asm volatile("atom.cas.relaxed." __simt_scope ".b64 %0, [%1], %2, %3;" \ + : "=l"(old) \ + : "l"(ptr), "l"(expected), "l"(desired) \ + : "memory") +#define __simt_add_release_64(ptr, old, addend) \ + asm volatile("atom.add.release." __simt_scope ".u64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(addend) \ + : "memory") +#define __simt_add_acquire_64(ptr, old, addend) \ + asm volatile("atom.add.acquire." __simt_scope ".u64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(addend) \ + : "memory") +#define __simt_add_acq_rel_64(ptr, old, addend) \ + asm volatile("atom.add.acq_rel." __simt_scope ".u64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(addend) \ + : "memory") +#define __simt_add_relaxed_64(ptr, old, addend) \ + asm volatile("atom.add.relaxed." __simt_scope ".u64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(addend) \ + : "memory") +#define __simt_and_release_64(ptr, old, andend) \ + asm volatile("atom.and.release." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(andend) \ + : "memory") +#define __simt_and_acquire_64(ptr, old, andend) \ + asm volatile("atom.and.acquire." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(andend) \ + : "memory") +#define __simt_and_acq_rel_64(ptr, old, andend) \ + asm volatile("atom.and.acq_rel." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(andend) \ + : "memory") +#define __simt_and_relaxed_64(ptr, old, andend) \ + asm volatile("atom.and.relaxed." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(andend) \ + : "memory") +#define __simt_or_release_64(ptr, old, orend) \ + asm volatile("atom.or.release." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(orend) \ + : "memory") +#define __simt_or_acquire_64(ptr, old, orend) \ + asm volatile("atom.or.acquire." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(orend) \ + : "memory") +#define __simt_or_acq_rel_64(ptr, old, orend) \ + asm volatile("atom.or.acq_rel." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(orend) \ + : "memory") +#define __simt_or_relaxed_64(ptr, old, orend) \ + asm volatile("atom.or.relaxed." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(orend) \ + : "memory") +#define __simt_xor_release_64(ptr, old, xorend) \ + asm volatile("atom.xor.release." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(xorend) \ + : "memory") +#define __simt_xor_acquire_64(ptr, old, xorend) \ + asm volatile("atom.xor.acquire." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(xorend) \ + : "memory") +#define __simt_xor_acq_rel_64(ptr, old, xorend) \ + asm volatile("atom.xor.acq_rel." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(xorend) \ + : "memory") +#define __simt_xor_relaxed_64(ptr, old, xorend) \ + asm volatile("atom.xor.relaxed." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(xorend) \ + : "memory") + +#define __simt_nanosleep(timeout) \ + asm volatile("nanosleep.u32 %0;" ::"r"(unsigned(timeout)) :) /* definitions @@ -189,309 +438,355 @@ namespace Impl { #endif inline __device__ int __stronger_order_simt_(int a, int b) { - if (b == __ATOMIC_SEQ_CST) return __ATOMIC_SEQ_CST; - if (b == __ATOMIC_RELAXED) return a; - switch (a) { + if (b == __ATOMIC_SEQ_CST) return __ATOMIC_SEQ_CST; + if (b == __ATOMIC_RELAXED) return a; + switch (a) { case __ATOMIC_SEQ_CST: case __ATOMIC_ACQ_REL: return a; case __ATOMIC_CONSUME: - case __ATOMIC_ACQUIRE: if (b != __ATOMIC_ACQUIRE) return __ATOMIC_ACQ_REL; else return __ATOMIC_ACQUIRE; - case __ATOMIC_RELEASE: if (b != __ATOMIC_RELEASE) return __ATOMIC_ACQ_REL; else return __ATOMIC_RELEASE; + case __ATOMIC_ACQUIRE: + if (b != __ATOMIC_ACQUIRE) + return __ATOMIC_ACQ_REL; + else + return __ATOMIC_ACQUIRE; + case __ATOMIC_RELEASE: + if (b != __ATOMIC_RELEASE) + return __ATOMIC_ACQ_REL; + else + return __ATOMIC_RELEASE; case __ATOMIC_RELAXED: return b; default: assert(0); - } - return __ATOMIC_SEQ_CST; + } + return __ATOMIC_SEQ_CST; } /* base */ -#define DO__atomic_load_simt_(bytes, bits) \ -template::type = 0> \ -void __device__ __atomic_load_simt_ (const type *ptr, type *ret, int memorder) { \ - int##bits##_t tmp = 0; \ - switch (memorder) { \ - case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ - case __ATOMIC_CONSUME: \ - case __ATOMIC_ACQUIRE: __simt_load_acquire_##bits(ptr, tmp); break; \ - case __ATOMIC_RELAXED: __simt_load_relaxed_##bits(ptr, tmp); break; \ - default: assert(0); \ - } \ - memcpy(ret, &tmp, bytes); \ -} -DO__atomic_load_simt_(1,32) -DO__atomic_load_simt_(2,16) -DO__atomic_load_simt_(4,32) -DO__atomic_load_simt_(8,64) - -template -type __device__ __atomic_load_n_simt_(const type *ptr, int memorder) { - type ret; - __atomic_load_simt_(ptr, &ret, memorder); - return ret; -} - -#define DO__atomic_store_simt_(bytes, bits) \ -template::type = 0> \ -void __device__ __atomic_store_simt_ (type *ptr, type *val, int memorder) { \ - int##bits##_t tmp = 0; \ - memcpy(&tmp, val, bytes); \ - switch (memorder) { \ - case __ATOMIC_RELEASE: __simt_store_release_##bits(ptr, tmp); break; \ - case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ - case __ATOMIC_RELAXED: __simt_store_relaxed_##bits(ptr, tmp); break; \ - default: assert(0); \ - } \ -} -DO__atomic_store_simt_(1,32) -DO__atomic_store_simt_(2,16) -DO__atomic_store_simt_(4,32) -DO__atomic_store_simt_(8,64) - -template -void __device__ __atomic_store_n_simt_(type *ptr, type val, int memorder) { - __atomic_store_simt_(ptr, &val, memorder); -} - -#define DO__atomic_compare_exchange_simt_(bytes, bits) \ -template::type = 0> \ -bool __device__ __atomic_compare_exchange_simt_ (type *ptr, type *expected, const type *desired, bool, int success_memorder, int failure_memorder) { \ - int##bits##_t tmp = 0, old = 0, old_tmp; \ - memcpy(&tmp, desired, bytes); \ - memcpy(&old, expected, bytes); \ - old_tmp = old; \ - switch (__stronger_order_simt_(success_memorder, failure_memorder)) { \ - case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ - case __ATOMIC_CONSUME: \ - case __ATOMIC_ACQUIRE: __simt_cas_acquire_##bits(ptr, old, old_tmp, tmp); break; \ - case __ATOMIC_ACQ_REL: __simt_cas_acq_rel_##bits(ptr, old, old_tmp, tmp); break; \ - case __ATOMIC_RELEASE: __simt_cas_release_##bits(ptr, old, old_tmp, tmp); break; \ - case __ATOMIC_RELAXED: __simt_cas_relaxed_##bits(ptr, old, old_tmp, tmp); break; \ - default: assert(0); \ - } \ - bool const ret = old == old_tmp; \ - memcpy(expected, &old, bytes); \ - return ret; \ -} +#define DO__atomic_load_simt_(bytes, bits) \ + template ::type = 0> \ + void __device__ __atomic_load_simt_(const type *ptr, type *ret, \ + int memorder) { \ + int##bits##_t tmp = 0; \ + switch (memorder) { \ + case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ + case __ATOMIC_CONSUME: \ + case __ATOMIC_ACQUIRE: __simt_load_acquire_##bits(ptr, tmp); break; \ + case __ATOMIC_RELAXED: __simt_load_relaxed_##bits(ptr, tmp); break; \ + default: assert(0); \ + } \ + memcpy(ret, &tmp, bytes); \ + } +DO__atomic_load_simt_(1, 32) DO__atomic_load_simt_(2, 16) + DO__atomic_load_simt_(4, 32) DO__atomic_load_simt_(8, 64) + + template + type __device__ __atomic_load_n_simt_(const type *ptr, int memorder) { + type ret; + __atomic_load_simt_(ptr, &ret, memorder); + return ret; +} + +#define DO__atomic_store_simt_(bytes, bits) \ + template ::type = 0> \ + void __device__ __atomic_store_simt_(type *ptr, type *val, int memorder) { \ + int##bits##_t tmp = 0; \ + memcpy(&tmp, val, bytes); \ + switch (memorder) { \ + case __ATOMIC_RELEASE: __simt_store_release_##bits(ptr, tmp); break; \ + case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ + case __ATOMIC_RELAXED: __simt_store_relaxed_##bits(ptr, tmp); break; \ + default: assert(0); \ + } \ + } +DO__atomic_store_simt_(1, 32) DO__atomic_store_simt_(2, 16) + DO__atomic_store_simt_(4, 32) DO__atomic_store_simt_(8, 64) + + template + void __device__ + __atomic_store_n_simt_(type *ptr, type val, int memorder) { + __atomic_store_simt_(ptr, &val, memorder); +} + +#define DO__atomic_compare_exchange_simt_(bytes, bits) \ + template ::type = 0> \ + bool __device__ __atomic_compare_exchange_simt_( \ + type *ptr, type *expected, const type *desired, bool, \ + int success_memorder, int failure_memorder) { \ + int##bits##_t tmp = 0, old = 0, old_tmp; \ + memcpy(&tmp, desired, bytes); \ + memcpy(&old, expected, bytes); \ + old_tmp = old; \ + switch (__stronger_order_simt_(success_memorder, failure_memorder)) { \ + case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ + case __ATOMIC_CONSUME: \ + case __ATOMIC_ACQUIRE: \ + __simt_cas_acquire_##bits(ptr, old, old_tmp, tmp); \ + break; \ + case __ATOMIC_ACQ_REL: \ + __simt_cas_acq_rel_##bits(ptr, old, old_tmp, tmp); \ + break; \ + case __ATOMIC_RELEASE: \ + __simt_cas_release_##bits(ptr, old, old_tmp, tmp); \ + break; \ + case __ATOMIC_RELAXED: \ + __simt_cas_relaxed_##bits(ptr, old, old_tmp, tmp); \ + break; \ + default: assert(0); \ + } \ + bool const ret = old == old_tmp; \ + memcpy(expected, &old, bytes); \ + return ret; \ + } DO__atomic_compare_exchange_simt_(4, 32) -DO__atomic_compare_exchange_simt_(8, 64) - -template::type = 0> \ -bool __device__ __atomic_compare_exchange_simt_(type *ptr, type *expected, const type *desired, bool, int success_memorder, int failure_memorder) { - - using R = typename std::conditional::value, volatile uint32_t, uint32_t>::type; - auto const aligned = (R*)((intptr_t)ptr & ~(sizeof(uint32_t) - 1)); - auto const offset = uint32_t((intptr_t)ptr & (sizeof(uint32_t) - 1)) * 8; - auto const mask = ((1 << sizeof(type)*8) - 1) << offset; - - uint32_t old = *expected << offset, old_value; - while (1) { - old_value = (old & mask) >> offset; - if (old_value != *expected) - break; - uint32_t const attempt = (old & ~mask) | (*desired << offset); - if (__atomic_compare_exchange_simt_ (aligned, &old, &attempt, true, success_memorder, failure_memorder)) - return true; - } - *expected = old_value; - return false; -} - -template -bool __device__ __atomic_compare_exchange_n_simt_(type *ptr, type *expected, type desired, bool weak, int success_memorder, int failure_memorder) { - return __atomic_compare_exchange_simt_(ptr, expected, &desired, weak, success_memorder, failure_memorder); -} - -#define DO__atomic_exchange_simt_(bytes, bits) \ -template::type = 0> \ -void __device__ __atomic_exchange_simt_ (type *ptr, type *val, type *ret, int memorder) { \ - int##bits##_t tmp = 0; \ - memcpy(&tmp, val, bytes); \ - switch (memorder) { \ - case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ - case __ATOMIC_CONSUME: \ - case __ATOMIC_ACQUIRE: __simt_exch_acquire_##bits(ptr, tmp, tmp); break; \ - case __ATOMIC_ACQ_REL: __simt_exch_acq_rel_##bits(ptr, tmp, tmp); break; \ - case __ATOMIC_RELEASE: __simt_exch_release_##bits(ptr, tmp, tmp); break; \ - case __ATOMIC_RELAXED: __simt_exch_relaxed_##bits(ptr, tmp, tmp); break; \ - default: assert(0); \ - } \ - memcpy(ret, &tmp, bytes); \ -} -DO__atomic_exchange_simt_(4,32) -DO__atomic_exchange_simt_(8,64) - -template::type = 0> -void __device__ __atomic_exchange_simt_ (type *ptr, type *val, type *ret, int memorder) { - - type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); - while(!__atomic_compare_exchange_simt_(ptr, &expected, val, true, memorder, memorder)) - ; - *ret = expected; -} - -template + DO__atomic_compare_exchange_simt_(8, 64) + + template ::type = 0> + bool __device__ + __atomic_compare_exchange_simt_(type *ptr, type *expected, + const type *desired, bool, + int success_memorder, + int failure_memorder) { + using R = typename std::conditional::value, + volatile uint32_t, uint32_t>::type; + auto const aligned = (R *)((intptr_t)ptr & ~(sizeof(uint32_t) - 1)); + auto const offset = uint32_t((intptr_t)ptr & (sizeof(uint32_t) - 1)) * 8; + auto const mask = ((1 << sizeof(type) * 8) - 1) << offset; + + uint32_t old = *expected << offset, old_value; + while (1) { + old_value = (old & mask) >> offset; + if (old_value != *expected) break; + uint32_t const attempt = (old & ~mask) | (*desired << offset); + if (__atomic_compare_exchange_simt_(aligned, &old, &attempt, true, + success_memorder, failure_memorder)) + return true; + } + *expected = old_value; + return false; +} + +template +bool __device__ __atomic_compare_exchange_n_simt_(type *ptr, type *expected, + type desired, bool weak, + int success_memorder, + int failure_memorder) { + return __atomic_compare_exchange_simt_(ptr, expected, &desired, weak, + success_memorder, failure_memorder); +} + +#define DO__atomic_exchange_simt_(bytes, bits) \ + template ::type = 0> \ + void __device__ __atomic_exchange_simt_(type *ptr, type *val, type *ret, \ + int memorder) { \ + int##bits##_t tmp = 0; \ + memcpy(&tmp, val, bytes); \ + switch (memorder) { \ + case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ + case __ATOMIC_CONSUME: \ + case __ATOMIC_ACQUIRE: __simt_exch_acquire_##bits(ptr, tmp, tmp); break; \ + case __ATOMIC_ACQ_REL: __simt_exch_acq_rel_##bits(ptr, tmp, tmp); break; \ + case __ATOMIC_RELEASE: __simt_exch_release_##bits(ptr, tmp, tmp); break; \ + case __ATOMIC_RELAXED: __simt_exch_relaxed_##bits(ptr, tmp, tmp); break; \ + default: assert(0); \ + } \ + memcpy(ret, &tmp, bytes); \ + } +DO__atomic_exchange_simt_(4, 32) DO__atomic_exchange_simt_(8, 64) + + template ::type = 0> + void __device__ + __atomic_exchange_simt_(type *ptr, type *val, type *ret, int memorder) { + type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); + while (!__atomic_compare_exchange_simt_(ptr, &expected, val, true, memorder, + memorder)) + ; + *ret = expected; +} + +template type __device__ __atomic_exchange_n_simt_(type *ptr, type val, int memorder) { - type ret; - __atomic_exchange_simt_(ptr, &val, &ret, memorder); - return ret; -} - -#define DO__atomic_fetch_add_simt_(bytes, bits) \ -template::type = 0> \ -type __device__ __atomic_fetch_add_simt_ (type *ptr, delta val, int memorder) { \ - type ret; \ - switch (memorder) { \ - case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ - case __ATOMIC_CONSUME: \ - case __ATOMIC_ACQUIRE: __simt_add_acquire_##bits(ptr, ret, val); break; \ - case __ATOMIC_ACQ_REL: __simt_add_acq_rel_##bits(ptr, ret, val); break; \ - case __ATOMIC_RELEASE: __simt_add_release_##bits(ptr, ret, val); break; \ - case __ATOMIC_RELAXED: __simt_add_relaxed_##bits(ptr, ret, val); break; \ - default: assert(0); \ - } \ - return ret; \ -} -DO__atomic_fetch_add_simt_(4, 32) -DO__atomic_fetch_add_simt_(8, 64) - -template::type = 0> -type __device__ __atomic_fetch_add_simt_ (type *ptr, delta val, int memorder) { - - type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); - type const desired = expected + val; - while(!__atomic_compare_exchange_simt_(ptr, &expected, &desired, true, memorder, memorder)) - ; - return expected; -} - -#define DO__atomic_fetch_sub_simt_(bytes, bits) \ -template::type = 0> \ -type __device__ __atomic_fetch_sub_simt_ (type *ptr, delta val, int memorder) { \ - type ret; \ - switch (memorder) { \ - case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ - case __ATOMIC_CONSUME: \ - case __ATOMIC_ACQUIRE: __simt_add_acquire_##bits(ptr, ret, -val); break; \ - case __ATOMIC_ACQ_REL: __simt_add_acq_rel_##bits(ptr, ret, -val); break; \ - case __ATOMIC_RELEASE: __simt_add_release_##bits(ptr, ret, -val); break; \ - case __ATOMIC_RELAXED: __simt_add_relaxed_##bits(ptr, ret, -val); break; \ - default: assert(0); \ - } \ - return ret; \ -} -DO__atomic_fetch_sub_simt_(4,32) -DO__atomic_fetch_sub_simt_(8,64) - -template::type = 0> -type __device__ __atomic_fetch_sub_simt_ (type *ptr, delta val, int memorder) { - - type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); - type const desired = expected - val; - while(!__atomic_compare_exchange_simt_(ptr, &expected, &desired, true, memorder, memorder)) - ; - return expected; -} - -#define DO__atomic_fetch_and_simt_(bytes, bits) \ -template::type = 0> \ -type __device__ __atomic_fetch_and_simt_ (type *ptr, type val, int memorder) { \ - type ret; \ - switch (memorder) { \ - case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ - case __ATOMIC_CONSUME: \ - case __ATOMIC_ACQUIRE: __simt_and_acquire_##bits(ptr, ret, val); break; \ - case __ATOMIC_ACQ_REL: __simt_and_acq_rel_##bits(ptr, ret, val); break; \ - case __ATOMIC_RELEASE: __simt_and_release_##bits(ptr, ret, val); break; \ - case __ATOMIC_RELAXED: __simt_and_relaxed_##bits(ptr, ret, val); break; \ - default: assert(0); \ - } \ - return ret; \ -} -DO__atomic_fetch_and_simt_(4,32) -DO__atomic_fetch_and_simt_(8,64) - -template::type = 0> -type __device__ __atomic_fetch_and_simt_ (type *ptr, delta val, int memorder) { - - type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); - type const desired = expected & val; - while(!__atomic_compare_exchange_simt_(ptr, &expected, &desired, true, memorder, memorder)) - ; - return expected; -} - -#define DO__atomic_fetch_xor_simt_(bytes, bits) \ -template::type = 0> \ -type __device__ __atomic_fetch_xor_simt_ (type *ptr, type val, int memorder) { \ - type ret; \ - switch (memorder) { \ - case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ - case __ATOMIC_CONSUME: \ - case __ATOMIC_ACQUIRE: __simt_xor_acquire_##bits(ptr, ret, val); break; \ - case __ATOMIC_ACQ_REL: __simt_xor_acq_rel_##bits(ptr, ret, val); break; \ - case __ATOMIC_RELEASE: __simt_xor_release_##bits(ptr, ret, val); break; \ - case __ATOMIC_RELAXED: __simt_xor_relaxed_##bits(ptr, ret, val); break; \ - default: assert(0); \ - } \ - return ret; \ -} -DO__atomic_fetch_xor_simt_(4,32) -DO__atomic_fetch_xor_simt_(8,64) - -template::type = 0> -type __device__ __atomic_fetch_xor_simt_ (type *ptr, delta val, int memorder) { - - type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); - type const desired = expected ^ val; - while(!__atomic_compare_exchange_simt_(ptr, &expected, &desired, true, memorder, memorder)) - ; - return expected; -} - -#define DO__atomic_fetch_or_simt_(bytes, bits) \ -template::type = 0> \ -type __device__ __atomic_fetch_or_simt_ (type *ptr, type val, int memorder) { \ - type ret; \ - switch (memorder) { \ - case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ - case __ATOMIC_CONSUME: \ - case __ATOMIC_ACQUIRE: __simt_or_acquire_##bits(ptr, ret, val); break; \ - case __ATOMIC_ACQ_REL: __simt_or_acq_rel_##bits(ptr, ret, val); break; \ - case __ATOMIC_RELEASE: __simt_or_release_##bits(ptr, ret, val); break; \ - case __ATOMIC_RELAXED: __simt_or_relaxed_##bits(ptr, ret, val); break; \ - default: assert(0); \ - } \ - return ret; \ -} -DO__atomic_fetch_or_simt_(4,32) -DO__atomic_fetch_or_simt_(8,64) - -template::type = 0> -type __device__ __atomic_fetch_or_simt_ (type *ptr, delta val, int memorder) { - - type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); - type const desired = expected | val; - while(!__atomic_compare_exchange_simt_(ptr, &expected, &desired, true, memorder, memorder)) - ; - return expected; -} - -template + type ret; + __atomic_exchange_simt_(ptr, &val, &ret, memorder); + return ret; +} + +#define DO__atomic_fetch_add_simt_(bytes, bits) \ + template ::type = 0> \ + type __device__ __atomic_fetch_add_simt_(type *ptr, delta val, \ + int memorder) { \ + type ret; \ + switch (memorder) { \ + case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ + case __ATOMIC_CONSUME: \ + case __ATOMIC_ACQUIRE: __simt_add_acquire_##bits(ptr, ret, val); break; \ + case __ATOMIC_ACQ_REL: __simt_add_acq_rel_##bits(ptr, ret, val); break; \ + case __ATOMIC_RELEASE: __simt_add_release_##bits(ptr, ret, val); break; \ + case __ATOMIC_RELAXED: __simt_add_relaxed_##bits(ptr, ret, val); break; \ + default: assert(0); \ + } \ + return ret; \ + } +DO__atomic_fetch_add_simt_(4, 32) DO__atomic_fetch_add_simt_(8, 64) + + template ::type = 0> + type __device__ + __atomic_fetch_add_simt_(type *ptr, delta val, int memorder) { + type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); + type const desired = expected + val; + while (!__atomic_compare_exchange_simt_(ptr, &expected, &desired, true, + memorder, memorder)) + ; + return expected; +} + +#define DO__atomic_fetch_sub_simt_(bytes, bits) \ + template ::type = 0> \ + type __device__ __atomic_fetch_sub_simt_(type *ptr, delta val, \ + int memorder) { \ + type ret; \ + switch (memorder) { \ + case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ + case __ATOMIC_CONSUME: \ + case __ATOMIC_ACQUIRE: __simt_add_acquire_##bits(ptr, ret, -val); break; \ + case __ATOMIC_ACQ_REL: __simt_add_acq_rel_##bits(ptr, ret, -val); break; \ + case __ATOMIC_RELEASE: __simt_add_release_##bits(ptr, ret, -val); break; \ + case __ATOMIC_RELAXED: __simt_add_relaxed_##bits(ptr, ret, -val); break; \ + default: assert(0); \ + } \ + return ret; \ + } +DO__atomic_fetch_sub_simt_(4, 32) DO__atomic_fetch_sub_simt_(8, 64) + + template ::type = 0> + type __device__ + __atomic_fetch_sub_simt_(type *ptr, delta val, int memorder) { + type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); + type const desired = expected - val; + while (!__atomic_compare_exchange_simt_(ptr, &expected, &desired, true, + memorder, memorder)) + ; + return expected; +} + +#define DO__atomic_fetch_and_simt_(bytes, bits) \ + template ::type = 0> \ + type __device__ __atomic_fetch_and_simt_(type *ptr, type val, \ + int memorder) { \ + type ret; \ + switch (memorder) { \ + case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ + case __ATOMIC_CONSUME: \ + case __ATOMIC_ACQUIRE: __simt_and_acquire_##bits(ptr, ret, val); break; \ + case __ATOMIC_ACQ_REL: __simt_and_acq_rel_##bits(ptr, ret, val); break; \ + case __ATOMIC_RELEASE: __simt_and_release_##bits(ptr, ret, val); break; \ + case __ATOMIC_RELAXED: __simt_and_relaxed_##bits(ptr, ret, val); break; \ + default: assert(0); \ + } \ + return ret; \ + } +DO__atomic_fetch_and_simt_(4, 32) DO__atomic_fetch_and_simt_(8, 64) + + template ::type = 0> + type __device__ + __atomic_fetch_and_simt_(type *ptr, delta val, int memorder) { + type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); + type const desired = expected & val; + while (!__atomic_compare_exchange_simt_(ptr, &expected, &desired, true, + memorder, memorder)) + ; + return expected; +} + +#define DO__atomic_fetch_xor_simt_(bytes, bits) \ + template ::type = 0> \ + type __device__ __atomic_fetch_xor_simt_(type *ptr, type val, \ + int memorder) { \ + type ret; \ + switch (memorder) { \ + case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ + case __ATOMIC_CONSUME: \ + case __ATOMIC_ACQUIRE: __simt_xor_acquire_##bits(ptr, ret, val); break; \ + case __ATOMIC_ACQ_REL: __simt_xor_acq_rel_##bits(ptr, ret, val); break; \ + case __ATOMIC_RELEASE: __simt_xor_release_##bits(ptr, ret, val); break; \ + case __ATOMIC_RELAXED: __simt_xor_relaxed_##bits(ptr, ret, val); break; \ + default: assert(0); \ + } \ + return ret; \ + } +DO__atomic_fetch_xor_simt_(4, 32) DO__atomic_fetch_xor_simt_(8, 64) + + template ::type = 0> + type __device__ + __atomic_fetch_xor_simt_(type *ptr, delta val, int memorder) { + type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); + type const desired = expected ^ val; + while (!__atomic_compare_exchange_simt_(ptr, &expected, &desired, true, + memorder, memorder)) + ; + return expected; +} + +#define DO__atomic_fetch_or_simt_(bytes, bits) \ + template ::type = 0> \ + type __device__ __atomic_fetch_or_simt_(type *ptr, type val, int memorder) { \ + type ret; \ + switch (memorder) { \ + case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ + case __ATOMIC_CONSUME: \ + case __ATOMIC_ACQUIRE: __simt_or_acquire_##bits(ptr, ret, val); break; \ + case __ATOMIC_ACQ_REL: __simt_or_acq_rel_##bits(ptr, ret, val); break; \ + case __ATOMIC_RELEASE: __simt_or_release_##bits(ptr, ret, val); break; \ + case __ATOMIC_RELAXED: __simt_or_relaxed_##bits(ptr, ret, val); break; \ + default: assert(0); \ + } \ + return ret; \ + } +DO__atomic_fetch_or_simt_(4, 32) DO__atomic_fetch_or_simt_(8, 64) + + template ::type = 0> + type __device__ + __atomic_fetch_or_simt_(type *ptr, delta val, int memorder) { + type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); + type const desired = expected | val; + while (!__atomic_compare_exchange_simt_(ptr, &expected, &desired, true, + memorder, memorder)) + ; + return expected; +} + +template inline bool __device__ __atomic_test_and_set_simt_(type *ptr, int memorder) { - return __atomic_exchange_n_simt_((char*)ptr, (char)1, memorder) == 1; + return __atomic_exchange_n_simt_((char *)ptr, (char)1, memorder) == 1; } -template +template inline void __device__ __atomic_clear_simt_(type *ptr, int memorder) { - return __atomic_store_n_simt_((char*)ptr, (char)0, memorder); + return __atomic_store_n_simt_((char *)ptr, (char)0, memorder); } -inline constexpr __device__ bool __atomic_always_lock_free_simt_ (size_t size, void *) { - return size <= 8; +inline constexpr __device__ bool __atomic_always_lock_free_simt_(size_t size, + void *) { + return size <= 8; } -inline __device__ bool __atomic_is_lock_free_simt_(size_t size, void * ptr) { - return __atomic_always_lock_free_simt_(size, ptr); +inline __device__ bool __atomic_is_lock_free_simt_(size_t size, void *ptr) { + return __atomic_always_lock_free_simt_(size, ptr); } /* @@ -499,7 +794,7 @@ inline __device__ bool __atomic_is_lock_free_simt_(size_t size, void * ptr) { */ inline void __device__ __atomic_thread_fence_simt(int memorder) { - switch (memorder) { + switch (memorder) { case __ATOMIC_SEQ_CST: __simt_fence_sc_(); break; case __ATOMIC_CONSUME: case __ATOMIC_ACQUIRE: @@ -507,124 +802,184 @@ inline void __device__ __atomic_thread_fence_simt(int memorder) { case __ATOMIC_RELEASE: __simt_fence_(); break; case __ATOMIC_RELAXED: break; default: assert(0); - } + } } -inline void __device__ __atomic_signal_fence_simt(int memorder) { - __atomic_thread_fence_simt(memorder); +inline void __device__ __atomic_signal_fence_simt(int memorder) { + __atomic_thread_fence_simt(memorder); } /* non-volatile */ -template type __device__ __atomic_load_n_simt(const type *ptr, int memorder) { - return __atomic_load_n_simt_(const_cast(ptr), memorder); -} -template void __device__ __atomic_load_simt(const type *ptr, type *ret, int memorder) { - __atomic_load_simt_(const_cast(ptr), ret, memorder); -} -template void __device__ __atomic_store_n_simt(type *ptr, type val, int memorder) { - __atomic_store_n_simt_(const_cast(ptr), val, memorder); -} -template void __device__ __atomic_store_simt(type *ptr, type *val, int memorder) { - __atomic_store_simt_(const_cast(ptr), val, memorder); -} -template type __device__ __atomic_exchange_n_simt(type *ptr, type val, int memorder) { - return __atomic_exchange_n_simt_(const_cast(ptr), val, memorder); -} -template void __device__ __atomic_exchange_simt(type *ptr, type *val, type *ret, int memorder) { - __atomic_exchange_simt_(const_cast(ptr), val, ret, memorder); -} -template bool __device__ __atomic_compare_exchange_n_simt(type *ptr, type *expected, type desired, bool weak, int success_memorder, int failure_memorder) { - return __atomic_compare_exchange_n_simt_(const_cast(ptr), expected, desired, weak, success_memorder, failure_memorder); -} -template bool __device__ __atomic_compare_exchange_simt(type *ptr, type *expected, type *desired, bool weak, int success_memorder, int failure_memorder) { - return __atomic_compare_exchange_simt_(const_cast(ptr), expected, desired, weak, success_memorder, failure_memorder); -} -template type __device__ __atomic_fetch_add_simt(type *ptr, delta val, int memorder) { - return __atomic_fetch_add_simt_(const_cast(ptr), val, memorder); -} -template type __device__ __atomic_fetch_sub_simt(type *ptr, delta val, int memorder) { - return __atomic_fetch_sub_simt_(const_cast(ptr), val, memorder); -} -template type __device__ __atomic_fetch_and_simt(type *ptr, type val, int memorder) { - return __atomic_fetch_and_simt_(const_cast(ptr), val, memorder); -} -template type __device__ __atomic_fetch_xor_simt(type *ptr, type val, int memorder) { - return __atomic_fetch_xor_simt_(const_cast(ptr), val, memorder); -} -template type __device__ __atomic_fetch_or_simt(type *ptr, type val, int memorder) { - return __atomic_fetch_or_simt_(const_cast(ptr), val, memorder); -} -template bool __device__ __atomic_test_and_set_simt(void *ptr, int memorder) { - return __atomic_test_and_set_simt_(const_cast(ptr), memorder); -} -template void __device__ __atomic_clear_simt(void *ptr, int memorder) { - return __atomic_clear_simt_(const_cast(ptr), memorder); +template +type __device__ __atomic_load_n_simt(const type *ptr, int memorder) { + return __atomic_load_n_simt_(const_cast(ptr), memorder); +} +template +void __device__ __atomic_load_simt(const type *ptr, type *ret, int memorder) { + __atomic_load_simt_(const_cast(ptr), ret, memorder); +} +template +void __device__ __atomic_store_n_simt(type *ptr, type val, int memorder) { + __atomic_store_n_simt_(const_cast(ptr), val, memorder); +} +template +void __device__ __atomic_store_simt(type *ptr, type *val, int memorder) { + __atomic_store_simt_(const_cast(ptr), val, memorder); +} +template +type __device__ __atomic_exchange_n_simt(type *ptr, type val, int memorder) { + return __atomic_exchange_n_simt_(const_cast(ptr), val, memorder); +} +template +void __device__ __atomic_exchange_simt(type *ptr, type *val, type *ret, + int memorder) { + __atomic_exchange_simt_(const_cast(ptr), val, ret, memorder); +} +template +bool __device__ __atomic_compare_exchange_n_simt(type *ptr, type *expected, + type desired, bool weak, + int success_memorder, + int failure_memorder) { + return __atomic_compare_exchange_n_simt_(const_cast(ptr), expected, + desired, weak, success_memorder, + failure_memorder); +} +template +bool __device__ __atomic_compare_exchange_simt(type *ptr, type *expected, + type *desired, bool weak, + int success_memorder, + int failure_memorder) { + return __atomic_compare_exchange_simt_(const_cast(ptr), expected, + desired, weak, success_memorder, + failure_memorder); +} +template +type __device__ __atomic_fetch_add_simt(type *ptr, delta val, int memorder) { + return __atomic_fetch_add_simt_(const_cast(ptr), val, memorder); +} +template +type __device__ __atomic_fetch_sub_simt(type *ptr, delta val, int memorder) { + return __atomic_fetch_sub_simt_(const_cast(ptr), val, memorder); +} +template +type __device__ __atomic_fetch_and_simt(type *ptr, type val, int memorder) { + return __atomic_fetch_and_simt_(const_cast(ptr), val, memorder); +} +template +type __device__ __atomic_fetch_xor_simt(type *ptr, type val, int memorder) { + return __atomic_fetch_xor_simt_(const_cast(ptr), val, memorder); +} +template +type __device__ __atomic_fetch_or_simt(type *ptr, type val, int memorder) { + return __atomic_fetch_or_simt_(const_cast(ptr), val, memorder); +} +template +bool __device__ __atomic_test_and_set_simt(void *ptr, int memorder) { + return __atomic_test_and_set_simt_(const_cast(ptr), memorder); +} +template +void __device__ __atomic_clear_simt(void *ptr, int memorder) { + return __atomic_clear_simt_(const_cast(ptr), memorder); } inline bool __device__ __atomic_always_lock_free_simt(size_t size, void *ptr) { - return __atomic_always_lock_free_simt_(size, const_cast(ptr)); + return __atomic_always_lock_free_simt_(size, const_cast(ptr)); } inline bool __device__ __atomic_is_lock_free_simt(size_t size, void *ptr) { - return __atomic_is_lock_free_simt_(size, const_cast(ptr)); + return __atomic_is_lock_free_simt_(size, const_cast(ptr)); } /* - volatile + volatile */ -template type __device__ __atomic_load_n_simt(const volatile type *ptr, int memorder) { - return __atomic_load_n_simt_(const_cast(ptr), memorder); -} -template void __device__ __atomic_load_simt(const volatile type *ptr, type *ret, int memorder) { - __atomic_load_simt_(const_cast(ptr), ret, memorder); -} -template void __device__ __atomic_store_n_simt(volatile type *ptr, type val, int memorder) { - __atomic_store_n_simt_(const_cast(ptr), val, memorder); -} -template void __device__ __atomic_store_simt(volatile type *ptr, type *val, int memorder) { - __atomic_store_simt_(const_cast(ptr), val, memorder); -} -template type __device__ __atomic_exchange_n_simt(volatile type *ptr, type val, int memorder) { - return __atomic_exchange_n_simt_(const_cast(ptr), val, memorder); -} -template void __device__ __atomic_exchange_simt(volatile type *ptr, type *val, type *ret, int memorder) { - __atomic_exchange_simt_(const_cast(ptr), val, ret, memorder); -} -template bool __device__ __atomic_compare_exchange_n_simt(volatile type *ptr, type *expected, type desired, bool weak, int success_memorder, int failure_memorder) { - return __atomic_compare_exchange_n_simt_(const_cast(ptr), expected, desired, weak, success_memorder, failure_memorder); -} -template bool __device__ __atomic_compare_exchange_simt(volatile type *ptr, type *expected, type *desired, bool weak, int success_memorder, int failure_memorder) { - return __atomic_compare_exchange_simt_(const_cast(ptr), expected, desired, weak, success_memorder, failure_memorder); -} -template type __device__ __atomic_fetch_add_simt(volatile type *ptr, delta val, int memorder) { - return __atomic_fetch_add_simt_(const_cast(ptr), val, memorder); -} -template type __device__ __atomic_fetch_sub_simt(volatile type *ptr, delta val, int memorder) { - return __atomic_fetch_sub_simt_(const_cast(ptr), val, memorder); -} -template type __device__ __atomic_fetch_and_simt(volatile type *ptr, type val, int memorder) { - return __atomic_fetch_and_simt_(const_cast(ptr), val, memorder); -} -template type __device__ __atomic_fetch_xor_simt(volatile type *ptr, type val, int memorder) { - return __atomic_fetch_xor_simt_(const_cast(ptr), val, memorder); -} -template type __device__ __atomic_fetch_or_simt(volatile type *ptr, type val, int memorder) { - return __atomic_fetch_or_simt_(const_cast(ptr), val, memorder); -} -template bool __device__ __atomic_test_and_set_simt(volatile void *ptr, int memorder) { - return __atomic_test_and_set_simt_(const_cast(ptr), memorder); -} -template void __device__ __atomic_clear_simt(volatile void *ptr, int memorder) { - return __atomic_clear_simt_(const_cast(ptr), memorder); -} - - - -} // end namespace Impl -} // end namespace Kokkos - -#endif //_SIMT_DETAILS_CONFIG +template +type __device__ __atomic_load_n_simt(const volatile type *ptr, int memorder) { + return __atomic_load_n_simt_(const_cast(ptr), memorder); +} +template +void __device__ __atomic_load_simt(const volatile type *ptr, type *ret, + int memorder) { + __atomic_load_simt_(const_cast(ptr), ret, memorder); +} +template +void __device__ __atomic_store_n_simt(volatile type *ptr, type val, + int memorder) { + __atomic_store_n_simt_(const_cast(ptr), val, memorder); +} +template +void __device__ __atomic_store_simt(volatile type *ptr, type *val, + int memorder) { + __atomic_store_simt_(const_cast(ptr), val, memorder); +} +template +type __device__ __atomic_exchange_n_simt(volatile type *ptr, type val, + int memorder) { + return __atomic_exchange_n_simt_(const_cast(ptr), val, memorder); +} +template +void __device__ __atomic_exchange_simt(volatile type *ptr, type *val, type *ret, + int memorder) { + __atomic_exchange_simt_(const_cast(ptr), val, ret, memorder); +} +template +bool __device__ __atomic_compare_exchange_n_simt(volatile type *ptr, + type *expected, type desired, + bool weak, + int success_memorder, + int failure_memorder) { + return __atomic_compare_exchange_n_simt_(const_cast(ptr), expected, + desired, weak, success_memorder, + failure_memorder); +} +template +bool __device__ __atomic_compare_exchange_simt(volatile type *ptr, + type *expected, type *desired, + bool weak, int success_memorder, + int failure_memorder) { + return __atomic_compare_exchange_simt_(const_cast(ptr), expected, + desired, weak, success_memorder, + failure_memorder); +} +template +type __device__ __atomic_fetch_add_simt(volatile type *ptr, delta val, + int memorder) { + return __atomic_fetch_add_simt_(const_cast(ptr), val, memorder); +} +template +type __device__ __atomic_fetch_sub_simt(volatile type *ptr, delta val, + int memorder) { + return __atomic_fetch_sub_simt_(const_cast(ptr), val, memorder); +} +template +type __device__ __atomic_fetch_and_simt(volatile type *ptr, type val, + int memorder) { + return __atomic_fetch_and_simt_(const_cast(ptr), val, memorder); +} +template +type __device__ __atomic_fetch_xor_simt(volatile type *ptr, type val, + int memorder) { + return __atomic_fetch_xor_simt_(const_cast(ptr), val, memorder); +} +template +type __device__ __atomic_fetch_or_simt(volatile type *ptr, type val, + int memorder) { + return __atomic_fetch_or_simt_(const_cast(ptr), val, memorder); +} +template +bool __device__ __atomic_test_and_set_simt(volatile void *ptr, int memorder) { + return __atomic_test_and_set_simt_(const_cast(ptr), memorder); +} +template +void __device__ __atomic_clear_simt(volatile void *ptr, int memorder) { + return __atomic_clear_simt_(const_cast(ptr), memorder); +} + +} // end namespace Impl +} // end namespace Kokkos + +#endif //_SIMT_DETAILS_CONFIG #ifndef KOKKOS_SIMT_ATOMIC_BUILTIN_REPLACEMENTS_DEFINED /* @@ -653,5 +1008,5 @@ template void __device__ __atomic_clear_simt(volatile void *ptr, int #define KOKKOS_SIMT_ATOMIC_BUILTIN_REPLACEMENTS_DEFINED -#endif //__CUDA_ARCH__ && KOKKOS_ENABLE_CUDA_ASM_ATOMICS -#endif // KOKKOS_SIMT_ATOMIC_BUILTIN_REPLACEMENTS_DEFINED +#endif //__CUDA_ARCH__ && KOKKOS_ENABLE_CUDA_ASM_ATOMICS +#endif // KOKKOS_SIMT_ATOMIC_BUILTIN_REPLACEMENTS_DEFINED diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Atomic_Intrinsics_Restore_Builtins.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Atomic_Intrinsics_Restore_Builtins.hpp index bedb147227..d7cd1bab13 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Atomic_Intrinsics_Restore_Builtins.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Atomic_Intrinsics_Restore_Builtins.hpp @@ -2,10 +2,10 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 +// Kokkos v. 3.0 // Copyright (2019) Sandia Corporation // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -65,4 +65,4 @@ #undef KOKKOS_SIMT_ATOMIC_BUILTIN_REPLACEMENTS_DEFINED -#endif // KOKKOS_SIMT_ATOMIC_BUILTIN_REPLACEMENTS_DEFINED +#endif // KOKKOS_SIMT_ATOMIC_BUILTIN_REPLACEMENTS_DEFINED diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_BlockSize_Deduction.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_BlockSize_Deduction.hpp index 932bde2b37..34b681be15 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_BlockSize_Deduction.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_BlockSize_Deduction.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -47,377 +48,447 @@ #include #ifdef KOKKOS_ENABLE_CUDA -#include +#include #include -namespace Kokkos { namespace Impl { +namespace Kokkos { +namespace Impl { -template +template struct CudaGetMaxBlockSize; -template -int cuda_get_max_block_size(const typename DriverType::functor_type & f, const size_t vector_length, - const size_t shmem_extra_block, const size_t shmem_extra_thread) { - return CudaGetMaxBlockSize::get_block_size(f,vector_length, shmem_extra_block,shmem_extra_thread); +template +int cuda_get_max_block_size(const typename DriverType::functor_type& f, + const size_t vector_length, + const size_t shmem_extra_block, + const size_t shmem_extra_thread) { + return CudaGetMaxBlockSize::get_block_size( + f, vector_length, shmem_extra_block, shmem_extra_thread); } -template -int cuda_get_max_block_size(const CudaInternal* cuda_instance, const cudaFuncAttributes& attr, const FunctorType& f, const size_t vector_length, - const size_t shmem_block, const size_t shmem_thread) { - - const int min_blocks_per_sm = LaunchBounds::minBperSM == 0 ? - 1 : LaunchBounds::minBperSM ; - const int max_threads_per_block = LaunchBounds::maxTperB == 0 ? - cuda_instance->m_maxThreadsPerBlock : LaunchBounds::maxTperB ; - - const int regs_per_thread = attr.numRegs; - const int regs_per_sm = cuda_instance->m_regsPerSM; - const int shmem_per_sm = cuda_instance->m_shmemPerSM; +template +int cuda_get_max_block_size(const CudaInternal* cuda_instance, + const cudaFuncAttributes& attr, + const FunctorType& f, const size_t vector_length, + const size_t shmem_block, + const size_t shmem_thread) { + const int min_blocks_per_sm = + LaunchBounds::minBperSM == 0 ? 1 : LaunchBounds::minBperSM; + const int max_threads_per_block = LaunchBounds::maxTperB == 0 + ? cuda_instance->m_maxThreadsPerBlock + : LaunchBounds::maxTperB; + + const int regs_per_thread = attr.numRegs; + const int regs_per_sm = cuda_instance->m_regsPerSM; + const int shmem_per_sm = cuda_instance->m_shmemPerSM; const int max_shmem_per_block = cuda_instance->m_maxShmemPerBlock; - const int max_blocks_per_sm = cuda_instance->m_maxBlocksPerSM; - const int max_threads_per_sm = cuda_instance->m_maxThreadsPerSM; - - int block_size = std::min(attr.maxThreadsPerBlock,max_threads_per_block); - - int functor_shmem = FunctorTeamShmemSize< FunctorType >::value( f , block_size/vector_length ); - int total_shmem = shmem_block + shmem_thread*(block_size/vector_length) + functor_shmem + attr.sharedSizeBytes; - int max_blocks_regs = regs_per_sm/(regs_per_thread*block_size); - int max_blocks_shmem = (total_shmem0?shmem_per_sm/total_shmem:max_blocks_regs):0; - int blocks_per_sm = std::min(max_blocks_regs,max_blocks_shmem); + const int max_blocks_per_sm = cuda_instance->m_maxBlocksPerSM; + const int max_threads_per_sm = cuda_instance->m_maxThreadsPerSM; + + int block_size = std::min(attr.maxThreadsPerBlock, max_threads_per_block); + + int functor_shmem = + FunctorTeamShmemSize::value(f, block_size / vector_length); + int total_shmem = shmem_block + shmem_thread * (block_size / vector_length) + + functor_shmem + attr.sharedSizeBytes; + int max_blocks_regs = regs_per_sm / (regs_per_thread * block_size); + int max_blocks_shmem = + (total_shmem < max_shmem_per_block) + ? (total_shmem > 0 ? shmem_per_sm / total_shmem : max_blocks_regs) + : 0; + int blocks_per_sm = std::min(max_blocks_regs, max_blocks_shmem); int threads_per_sm = blocks_per_sm * block_size; - if(threads_per_sm > max_threads_per_sm) { - blocks_per_sm = max_threads_per_sm/block_size; + if (threads_per_sm > max_threads_per_sm) { + blocks_per_sm = max_threads_per_sm / block_size; threads_per_sm = blocks_per_sm * block_size; } - int opt_block_size = (blocks_per_sm>=min_blocks_per_sm) ? block_size : 0; + int opt_block_size = (blocks_per_sm >= min_blocks_per_sm) ? block_size : 0; int opt_threads_per_sm = threads_per_sm; - //printf("BlockSizeMax: %i Shmem: %i %i %i %i Regs: %i %i Blocks: %i %i Achieved: %i %i Opt: %i %i\n",block_size, + // printf("BlockSizeMax: %i Shmem: %i %i %i %i Regs: %i %i Blocks: %i %i + // Achieved: %i %i Opt: %i %i\n",block_size, // shmem_per_sm,max_shmem_per_block,functor_shmem,total_shmem, // regs_per_sm,regs_per_thread,max_blocks_shmem,max_blocks_regs,blocks_per_sm,threads_per_sm,opt_block_size,opt_threads_per_sm); - block_size-=32; - while ((blocks_per_sm==0) && (block_size>=32)) { - functor_shmem = FunctorTeamShmemSize< FunctorType >::value( f , block_size/vector_length ); - total_shmem = shmem_block + shmem_thread*(block_size/vector_length) + functor_shmem + attr.sharedSizeBytes; - max_blocks_regs = regs_per_sm/(regs_per_thread*block_size); - max_blocks_shmem = (total_shmem0?shmem_per_sm/total_shmem:max_blocks_regs):0; - blocks_per_sm = std::min(max_blocks_regs,max_blocks_shmem); + block_size -= 32; + while ((blocks_per_sm == 0) && (block_size >= 32)) { + functor_shmem = + FunctorTeamShmemSize::value(f, block_size / vector_length); + total_shmem = shmem_block + shmem_thread * (block_size / vector_length) + + functor_shmem + attr.sharedSizeBytes; + max_blocks_regs = regs_per_sm / (regs_per_thread * block_size); + max_blocks_shmem = + (total_shmem < max_shmem_per_block) + ? (total_shmem > 0 ? shmem_per_sm / total_shmem : max_blocks_regs) + : 0; + blocks_per_sm = std::min(max_blocks_regs, max_blocks_shmem); threads_per_sm = blocks_per_sm * block_size; - if(threads_per_sm > max_threads_per_sm) { - blocks_per_sm = max_threads_per_sm/block_size; + if (threads_per_sm > max_threads_per_sm) { + blocks_per_sm = max_threads_per_sm / block_size; threads_per_sm = blocks_per_sm * block_size; } - if((blocks_per_sm >= min_blocks_per_sm) && (blocks_per_sm <= max_blocks_per_sm)) { - if(threads_per_sm>=opt_threads_per_sm) { - opt_block_size = block_size; + if ((blocks_per_sm >= min_blocks_per_sm) && + (blocks_per_sm <= max_blocks_per_sm)) { + if (threads_per_sm >= opt_threads_per_sm) { + opt_block_size = block_size; opt_threads_per_sm = threads_per_sm; } } - //printf("BlockSizeMax: %i Shmem: %i %i %i %i Regs: %i %i Blocks: %i %i Achieved: %i %i Opt: %i %i\n",block_size, - // shmem_per_sm,max_shmem_per_block,functor_shmem,total_shmem, - // regs_per_sm,regs_per_thread,max_blocks_shmem,max_blocks_regs,blocks_per_sm,threads_per_sm,opt_block_size,opt_threads_per_sm); - block_size-=32; + // printf("BlockSizeMax: %i Shmem: %i %i %i %i Regs: %i %i Blocks: %i %i + // Achieved: %i %i Opt: %i %i\n",block_size, + // shmem_per_sm,max_shmem_per_block,functor_shmem,total_shmem, + // regs_per_sm,regs_per_thread,max_blocks_shmem,max_blocks_regs,blocks_per_sm,threads_per_sm,opt_block_size,opt_threads_per_sm); + block_size -= 32; } return opt_block_size; } - -template -struct CudaGetMaxBlockSize,true> { - static int get_block_size(const typename DriverType::functor_type & f, const size_t vector_length, - const size_t shmem_extra_block, const size_t shmem_extra_thread) { +template +struct CudaGetMaxBlockSize, true> { + static int get_block_size(const typename DriverType::functor_type& f, + const size_t vector_length, + const size_t shmem_extra_block, + const size_t shmem_extra_thread) { int numBlocks; - int blockSize=1024; - int sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + int blockSize = 1024; + int sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_constant_memory, - blockSize, + &numBlocks, cuda_parallel_launch_constant_memory, blockSize, sharedmem); - if(numBlocks>0) return blockSize; - while (blockSize>32 && numBlocks==0) { - blockSize/=2; - sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + if (numBlocks > 0) return blockSize; + while (blockSize > 32 && numBlocks == 0) { + blockSize /= 2; + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_constant_memory, - blockSize, - sharedmem); + &numBlocks, cuda_parallel_launch_constant_memory, + blockSize, sharedmem); } - int blockSizeUpperBound = blockSize*2; - while (blockSize0) { - blockSize+=32; - sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + int blockSizeUpperBound = blockSize * 2; + while (blockSize < blockSizeUpperBound && numBlocks > 0) { + blockSize += 32; + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_constant_memory, - blockSize, - sharedmem); + &numBlocks, cuda_parallel_launch_constant_memory, + blockSize, sharedmem); } return blockSize - 32; } }; -template -struct CudaGetMaxBlockSize,false> { - static int get_block_size(const typename DriverType::functor_type & f, const size_t vector_length, - const size_t shmem_extra_block, const size_t shmem_extra_thread) { +template +struct CudaGetMaxBlockSize, false> { + static int get_block_size(const typename DriverType::functor_type& f, + const size_t vector_length, + const size_t shmem_extra_block, + const size_t shmem_extra_thread) { int numBlocks; - unsigned int blockSize=1024; - unsigned int sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + unsigned int blockSize = 1024; + unsigned int sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_local_memory, - blockSize, + &numBlocks, cuda_parallel_launch_local_memory, blockSize, sharedmem); - if(numBlocks>0) return blockSize; - while (blockSize>32 && numBlocks==0) { - blockSize/=2; - sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + if (numBlocks > 0) return blockSize; + while (blockSize > 32 && numBlocks == 0) { + blockSize /= 2; + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_local_memory, - blockSize, + &numBlocks, cuda_parallel_launch_local_memory, blockSize, sharedmem); } - unsigned int blockSizeUpperBound = blockSize*2; - while (blockSize0) { - blockSize+=32; - sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + unsigned int blockSizeUpperBound = blockSize * 2; + while (blockSize < blockSizeUpperBound && numBlocks > 0) { + blockSize += 32; + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_local_memory, - blockSize, - sharedmem); + &numBlocks, cuda_parallel_launch_local_memory, blockSize, + sharedmem); } return blockSize - 32; } }; -template -struct CudaGetMaxBlockSize,true> { - static int get_block_size(const typename DriverType::functor_type & f, const size_t vector_length, - const size_t shmem_extra_block, const size_t shmem_extra_thread) { +template +struct CudaGetMaxBlockSize< + DriverType, Kokkos::LaunchBounds, + true> { + static int get_block_size(const typename DriverType::functor_type& f, + const size_t vector_length, + const size_t shmem_extra_block, + const size_t shmem_extra_thread) { int numBlocks = 0, oldNumBlocks = 0; - unsigned int blockSize=MaxThreadsPerBlock; - unsigned int sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + unsigned int blockSize = MaxThreadsPerBlock; + unsigned int sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( &numBlocks, - cuda_parallel_launch_constant_memory, - blockSize, - sharedmem); + cuda_parallel_launch_constant_memory, + blockSize, sharedmem); - if(static_cast(numBlocks)>=MinBlocksPerSM) return blockSize; + if (static_cast(numBlocks) >= MinBlocksPerSM) + return blockSize; - while (blockSize>32 && static_cast(numBlocks)::value( f , blockSize/vector_length ); + while (blockSize > 32 && + static_cast(numBlocks) < MinBlocksPerSM) { + blockSize /= 2; + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_constant_memory, - blockSize, - sharedmem); + &numBlocks, cuda_parallel_launch_constant_memory, + blockSize, sharedmem); } - unsigned int blockSizeUpperBound = (blockSize*2(numBlocks)>MinBlocksPerSM) { - blockSize+=32; - sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + unsigned int blockSizeUpperBound = + (blockSize * 2 < MaxThreadsPerBlock ? blockSize * 2 + : MaxThreadsPerBlock); + while (blockSize(numBlocks)> + MinBlocksPerSM) { + blockSize += 32; + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); oldNumBlocks = numBlocks; cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_constant_memory, - blockSize, - sharedmem); + &numBlocks, cuda_parallel_launch_constant_memory, + blockSize, sharedmem); } - if(static_cast(oldNumBlocks)>=MinBlocksPerSM) return blockSize - 32; + if (static_cast(oldNumBlocks) >= MinBlocksPerSM) + return blockSize - 32; return -1; } }; -template -struct CudaGetMaxBlockSize,false> { - static int get_block_size(const typename DriverType::functor_type & f, const size_t vector_length, - const size_t shmem_extra_block, const size_t shmem_extra_thread) { +template +struct CudaGetMaxBlockSize< + DriverType, Kokkos::LaunchBounds, + false> { + static int get_block_size(const typename DriverType::functor_type& f, + const size_t vector_length, + const size_t shmem_extra_block, + const size_t shmem_extra_thread) { int numBlocks = 0, oldNumBlocks = 0; - unsigned int blockSize=MaxThreadsPerBlock; - int sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + unsigned int blockSize = MaxThreadsPerBlock; + int sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( &numBlocks, - cuda_parallel_launch_local_memory, - blockSize, - sharedmem); - if(static_cast(numBlocks)>=MinBlocksPerSM) return blockSize; - - while (blockSize>32 && static_cast(numBlocks)::value( f , blockSize/vector_length ); + cuda_parallel_launch_local_memory, + blockSize, sharedmem); + if (static_cast(numBlocks) >= MinBlocksPerSM) + return blockSize; + + while (blockSize > 32 && + static_cast(numBlocks) < MinBlocksPerSM) { + blockSize /= 2; + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_local_memory, - blockSize, + &numBlocks, cuda_parallel_launch_local_memory, blockSize, sharedmem); } - unsigned int blockSizeUpperBound = (blockSize*2(numBlocks)>=MinBlocksPerSM) { - blockSize+=32; - sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + unsigned int blockSizeUpperBound = + (blockSize * 2 < MaxThreadsPerBlock ? blockSize * 2 + : MaxThreadsPerBlock); + while (blockSize < blockSizeUpperBound && + static_cast(numBlocks) >= MinBlocksPerSM) { + blockSize += 32; + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); oldNumBlocks = numBlocks; cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_local_memory, - blockSize, - sharedmem); + &numBlocks, cuda_parallel_launch_local_memory, blockSize, + sharedmem); } - if(static_cast(oldNumBlocks)>=MinBlocksPerSM) return blockSize - 32; + if (static_cast(oldNumBlocks) >= MinBlocksPerSM) + return blockSize - 32; return -1; } }; - -template +template struct CudaGetOptBlockSize; -template -int cuda_get_opt_block_size(const typename DriverType::functor_type & f, const size_t vector_length, - const size_t shmem_extra_block, const size_t shmem_extra_thread) { - return CudaGetOptBlockSize +int cuda_get_opt_block_size(const typename DriverType::functor_type& f, + const size_t vector_length, + const size_t shmem_extra_block, + const size_t shmem_extra_thread) { + return CudaGetOptBlockSize< + DriverType, LaunchBounds, + // LaunchBounds::launch_mechanism == Kokkos::Experimental::LaunchDefault ? + // (( CudaTraits::ConstantMemoryUseThreshold < + // sizeof(DriverType) )? // Kokkos::Experimental::CudaLaunchConstantMemory:Kokkos::Experimental::CudaLaunchLocalMemory): // LaunchBounds::launch_mechanism - (CudaTraits::ConstantMemoryUseThreshold < sizeof(DriverType)) - >::get_block_size(f,vector_length,shmem_extra_block,shmem_extra_thread); + (CudaTraits::ConstantMemoryUseThreshold < + sizeof(DriverType))>::get_block_size(f, vector_length, shmem_extra_block, + shmem_extra_thread); } -template -int cuda_get_opt_block_size(const CudaInternal* cuda_instance, const cudaFuncAttributes& attr, const FunctorType& f, const size_t vector_length, - const size_t shmem_block, const size_t shmem_thread) { - - const int min_blocks_per_sm = LaunchBounds::minBperSM == 0 ? - 1 : LaunchBounds::minBperSM ; - const int max_threads_per_block = LaunchBounds::maxTperB == 0 ? - cuda_instance->m_maxThreadsPerBlock : LaunchBounds::maxTperB ; - - const int regs_per_thread = attr.numRegs; - const int regs_per_sm = cuda_instance->m_regsPerSM; - const int shmem_per_sm = cuda_instance->m_shmemPerSM; +template +int cuda_get_opt_block_size(const CudaInternal* cuda_instance, + const cudaFuncAttributes& attr, + const FunctorType& f, const size_t vector_length, + const size_t shmem_block, + const size_t shmem_thread) { + const int min_blocks_per_sm = + LaunchBounds::minBperSM == 0 ? 1 : LaunchBounds::minBperSM; + const int max_threads_per_block = LaunchBounds::maxTperB == 0 + ? cuda_instance->m_maxThreadsPerBlock + : LaunchBounds::maxTperB; + + const int regs_per_thread = attr.numRegs; + const int regs_per_sm = cuda_instance->m_regsPerSM; + const int shmem_per_sm = cuda_instance->m_shmemPerSM; const int max_shmem_per_block = cuda_instance->m_maxShmemPerBlock; - const int max_blocks_per_sm = cuda_instance->m_maxBlocksPerSM; - const int max_threads_per_sm = cuda_instance->m_maxThreadsPerSM; - - int block_size = std::min(attr.maxThreadsPerBlock,max_threads_per_block); - - int functor_shmem = FunctorTeamShmemSize< FunctorType >::value( f , block_size/vector_length ); - int total_shmem = shmem_block + shmem_thread*(block_size/vector_length) + functor_shmem + attr.sharedSizeBytes; - int max_blocks_regs = regs_per_sm/(regs_per_thread*block_size); - int max_blocks_shmem = (total_shmem0?shmem_per_sm/total_shmem:max_blocks_regs):0; - int blocks_per_sm = std::min(max_blocks_regs,max_blocks_shmem); + const int max_blocks_per_sm = cuda_instance->m_maxBlocksPerSM; + const int max_threads_per_sm = cuda_instance->m_maxThreadsPerSM; + + int block_size = std::min(attr.maxThreadsPerBlock, max_threads_per_block); + + int functor_shmem = + FunctorTeamShmemSize::value(f, block_size / vector_length); + int total_shmem = shmem_block + shmem_thread * (block_size / vector_length) + + functor_shmem + attr.sharedSizeBytes; + int max_blocks_regs = regs_per_sm / (regs_per_thread * block_size); + int max_blocks_shmem = + (total_shmem < max_shmem_per_block) + ? (total_shmem > 0 ? shmem_per_sm / total_shmem : max_blocks_regs) + : 0; + int blocks_per_sm = std::min(max_blocks_regs, max_blocks_shmem); int threads_per_sm = blocks_per_sm * block_size; - if(threads_per_sm > max_threads_per_sm) { - blocks_per_sm = max_threads_per_sm/block_size; + if (threads_per_sm > max_threads_per_sm) { + blocks_per_sm = max_threads_per_sm / block_size; threads_per_sm = blocks_per_sm * block_size; } - int opt_block_size = (blocks_per_sm>=min_blocks_per_sm) ? block_size : 0; + int opt_block_size = (blocks_per_sm >= min_blocks_per_sm) ? block_size : 0; int opt_threads_per_sm = threads_per_sm; - block_size-=32; - while ((block_size>=32)) { - functor_shmem = FunctorTeamShmemSize< FunctorType >::value( f , block_size/vector_length ); - total_shmem = shmem_block + shmem_thread*(block_size/vector_length) + functor_shmem + attr.sharedSizeBytes; - max_blocks_regs = regs_per_sm/(regs_per_thread*block_size); - max_blocks_shmem = (total_shmem0?shmem_per_sm/total_shmem:max_blocks_regs):0; - blocks_per_sm = std::min(max_blocks_regs,max_blocks_shmem); + block_size -= 32; + while ((block_size >= 32)) { + functor_shmem = + FunctorTeamShmemSize::value(f, block_size / vector_length); + total_shmem = shmem_block + shmem_thread * (block_size / vector_length) + + functor_shmem + attr.sharedSizeBytes; + max_blocks_regs = regs_per_sm / (regs_per_thread * block_size); + max_blocks_shmem = + (total_shmem < max_shmem_per_block) + ? (total_shmem > 0 ? shmem_per_sm / total_shmem : max_blocks_regs) + : 0; + blocks_per_sm = std::min(max_blocks_regs, max_blocks_shmem); threads_per_sm = blocks_per_sm * block_size; - if(threads_per_sm > max_threads_per_sm) { - blocks_per_sm = max_threads_per_sm/block_size; + if (threads_per_sm > max_threads_per_sm) { + blocks_per_sm = max_threads_per_sm / block_size; threads_per_sm = blocks_per_sm * block_size; } - if((blocks_per_sm >= min_blocks_per_sm) && (blocks_per_sm <= max_blocks_per_sm)) { - if(threads_per_sm>=opt_threads_per_sm) { - opt_block_size = block_size; + if ((blocks_per_sm >= min_blocks_per_sm) && + (blocks_per_sm <= max_blocks_per_sm)) { + if (threads_per_sm >= opt_threads_per_sm) { + opt_block_size = block_size; opt_threads_per_sm = threads_per_sm; } } - block_size-=32; + block_size -= 32; } return opt_block_size; } -template -struct CudaGetOptBlockSize,true> { - static int get_block_size(const typename DriverType::functor_type & f, const size_t vector_length, - const size_t shmem_extra_block, const size_t shmem_extra_thread) { - int blockSize=16; +template +struct CudaGetOptBlockSize, true> { + static int get_block_size(const typename DriverType::functor_type& f, + const size_t vector_length, + const size_t shmem_extra_block, + const size_t shmem_extra_thread) { + int blockSize = 16; int numBlocks; int sharedmem; - int maxOccupancy=0; - int bestBlockSize=0; - - while(blockSize<1024) { - blockSize*=2; - - //calculate the occupancy with that optBlockSize and check whether its larger than the largest one found so far - sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + int maxOccupancy = 0; + int bestBlockSize = 0; + + while (blockSize < 1024) { + blockSize *= 2; + + // calculate the occupancy with that optBlockSize and check whether its + // larger than the largest one found so far + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_constant_memory, - blockSize, - sharedmem); - if(maxOccupancy < numBlocks*blockSize) { - maxOccupancy = numBlocks*blockSize; - bestBlockSize = blockSize; + &numBlocks, cuda_parallel_launch_constant_memory, + blockSize, sharedmem); + if (maxOccupancy < numBlocks * blockSize) { + maxOccupancy = numBlocks * blockSize; + bestBlockSize = blockSize; } } return bestBlockSize; } }; -template -struct CudaGetOptBlockSize,false> { - static int get_block_size(const typename DriverType::functor_type & f, const size_t vector_length, - const size_t shmem_extra_block, const size_t shmem_extra_thread) { - int blockSize=16; +template +struct CudaGetOptBlockSize, false> { + static int get_block_size(const typename DriverType::functor_type& f, + const size_t vector_length, + const size_t shmem_extra_block, + const size_t shmem_extra_thread) { + int blockSize = 16; int numBlocks; int sharedmem; - int maxOccupancy=0; - int bestBlockSize=0; + int maxOccupancy = 0; + int bestBlockSize = 0; - while(blockSize<1024) { - blockSize*=2; - sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + while (blockSize < 1024) { + blockSize *= 2; + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_local_memory, - blockSize, - sharedmem); + &numBlocks, cuda_parallel_launch_local_memory, blockSize, + sharedmem); - if(maxOccupancy < numBlocks*blockSize) { - maxOccupancy = numBlocks*blockSize; + if (maxOccupancy < numBlocks * blockSize) { + maxOccupancy = numBlocks * blockSize; bestBlockSize = blockSize; } } @@ -425,77 +496,96 @@ struct CudaGetOptBlockSize,false> { } }; -template -struct CudaGetOptBlockSize,true> { - static int get_block_size(const typename DriverType::functor_type & f, const size_t vector_length, - const size_t shmem_extra_block, const size_t shmem_extra_thread) { - int blockSize=16; +template +struct CudaGetOptBlockSize< + DriverType, Kokkos::LaunchBounds, + true> { + static int get_block_size(const typename DriverType::functor_type& f, + const size_t vector_length, + const size_t shmem_extra_block, + const size_t shmem_extra_thread) { + int blockSize = 16; int numBlocks; int sharedmem; - int maxOccupancy=0; - int bestBlockSize=0; - int max_threads_per_block = std::min(MaxThreadsPerBlock,cuda_internal_maximum_warp_count()*CudaTraits::WarpSize); - - while(blockSize < max_threads_per_block ) { - blockSize*=2; - - //calculate the occupancy with that optBlockSize and check whether its larger than the largest one found so far - sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + int maxOccupancy = 0; + int bestBlockSize = 0; + int max_threads_per_block = + std::min(MaxThreadsPerBlock, + cuda_internal_maximum_warp_count() * CudaTraits::WarpSize); + + while (blockSize < max_threads_per_block) { + blockSize *= 2; + + // calculate the occupancy with that optBlockSize and check whether its + // larger than the largest one found so far + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_constant_memory, - blockSize, - sharedmem); - if(numBlocks >= int(MinBlocksPerSM) && blockSize<=int(MaxThreadsPerBlock)) { - if(maxOccupancy < numBlocks*blockSize) { - maxOccupancy = numBlocks*blockSize; - bestBlockSize = blockSize; + &numBlocks, + cuda_parallel_launch_constant_memory, + blockSize, sharedmem); + if (numBlocks >= int(MinBlocksPerSM) && + blockSize <= int(MaxThreadsPerBlock)) { + if (maxOccupancy < numBlocks * blockSize) { + maxOccupancy = numBlocks * blockSize; + bestBlockSize = blockSize; } } } - if(maxOccupancy > 0) - return bestBlockSize; + if (maxOccupancy > 0) return bestBlockSize; return -1; } }; -template -struct CudaGetOptBlockSize,false> { - static int get_block_size(const typename DriverType::functor_type & f, const size_t vector_length, - const size_t shmem_extra_block, const size_t shmem_extra_thread) { - int blockSize=16; +template +struct CudaGetOptBlockSize< + DriverType, Kokkos::LaunchBounds, + false> { + static int get_block_size(const typename DriverType::functor_type& f, + const size_t vector_length, + const size_t shmem_extra_block, + const size_t shmem_extra_thread) { + int blockSize = 16; int numBlocks; int sharedmem; - int maxOccupancy=0; - int bestBlockSize=0; - int max_threads_per_block = std::min(MaxThreadsPerBlock,cuda_internal_maximum_warp_count()*CudaTraits::WarpSize); - - while(blockSize < max_threads_per_block ) { - blockSize*=2; - sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + int maxOccupancy = 0; + int bestBlockSize = 0; + int max_threads_per_block = + std::min(MaxThreadsPerBlock, + cuda_internal_maximum_warp_count() * CudaTraits::WarpSize); + + while (blockSize < max_threads_per_block) { + blockSize *= 2; + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_local_memory, - blockSize, - sharedmem); - if(numBlocks >= int(MinBlocksPerSM) && blockSize<=int(MaxThreadsPerBlock)) { - if(maxOccupancy < numBlocks*blockSize) { - maxOccupancy = numBlocks*blockSize; + &numBlocks, + cuda_parallel_launch_local_memory, + blockSize, sharedmem); + if (numBlocks >= int(MinBlocksPerSM) && + blockSize <= int(MaxThreadsPerBlock)) { + if (maxOccupancy < numBlocks * blockSize) { + maxOccupancy = numBlocks * blockSize; bestBlockSize = blockSize; } } } - if(maxOccupancy > 0) - return bestBlockSize; + if (maxOccupancy > 0) return bestBlockSize; return -1; } }; -}} // namespace Kokkos::Impl - -#endif // KOKKOS_ENABLE_CUDA -#endif /* #ifndef KOKKOS_CUDA_INTERNAL_HPP */ +} // namespace Impl +} // namespace Kokkos +#endif // KOKKOS_ENABLE_CUDA +#endif /* #ifndef KOKKOS_CUDA_INTERNAL_HPP */ diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Error.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Error.hpp index 55c7c782fe..3b674bbb30 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Error.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Error.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -47,22 +48,82 @@ #include #ifdef KOKKOS_ENABLE_CUDA -namespace Kokkos { namespace Impl { +#include + +#include + +namespace Kokkos { +namespace Impl { void cuda_device_synchronize(); -void cuda_internal_error_throw( cudaError e , const char * name, const char * file = NULL, const int line = 0 ); +void cuda_internal_error_throw(cudaError e, const char* name, + const char* file = NULL, const int line = 0); -inline void cuda_internal_safe_call( cudaError e , const char * name, const char * file = NULL, const int line = 0) -{ - if ( cudaSuccess != e ) { cuda_internal_error_throw( e , name, file, line ); } +inline void cuda_internal_safe_call(cudaError e, const char* name, + const char* file = NULL, + const int line = 0) { + if (cudaSuccess != e) { + cuda_internal_error_throw(e, name, file, line); + } } -#define CUDA_SAFE_CALL( call ) \ - Kokkos::Impl::cuda_internal_safe_call( call , #call, __FILE__, __LINE__ ) +#define CUDA_SAFE_CALL(call) \ + Kokkos::Impl::cuda_internal_safe_call(call, #call, __FILE__, __LINE__) + +} // namespace Impl + +namespace Experimental { + +class CudaRawMemoryAllocationFailure : public RawMemoryAllocationFailure { + private: + using base_t = RawMemoryAllocationFailure; + + cudaError_t m_error_code = cudaSuccess; + + static FailureMode get_failure_mode(cudaError_t error_code) { + switch (error_code) { + case cudaErrorMemoryAllocation: return FailureMode::OutOfMemoryError; + case cudaErrorInvalidValue: return FailureMode::InvalidAllocationSize; + // TODO handle cudaErrorNotSupported for cudaMallocManaged + default: return FailureMode::Unknown; + } + } + + public: + // using base_t::base_t; + // would trigger + // + // error: cannot determine the exception specification of the default + // constructor due to a circular dependency + // + // using NVCC 9.1 and gcc 7.4 + CudaRawMemoryAllocationFailure( + size_t arg_attempted_size, size_t arg_attempted_alignment, + FailureMode arg_failure_mode = FailureMode::OutOfMemoryError, + AllocationMechanism arg_mechanism = + AllocationMechanism::StdMalloc) noexcept + : base_t(arg_attempted_size, arg_attempted_alignment, arg_failure_mode, + arg_mechanism) {} + + CudaRawMemoryAllocationFailure(size_t arg_attempted_size, + cudaError_t arg_error_code, + AllocationMechanism arg_mechanism) noexcept + : base_t(arg_attempted_size, /* CudaSpace doesn't handle alignment? */ 1, + get_failure_mode(arg_error_code), arg_mechanism), + m_error_code(arg_error_code) {} + + void append_additional_error_information(std::ostream& o) const override { + if (m_error_code != cudaSuccess) { + o << " The Cuda allocation returned the error code \"\"" + << cudaGetErrorName(m_error_code) << "\"."; + } + } +}; -}} // namespace Kokkos::Impl +} // end namespace Experimental -#endif //KOKKOS_ENABLE_CUDA -#endif //KOKKOS_CUDA_ERROR_HPP +} // namespace Kokkos +#endif // KOKKOS_ENABLE_CUDA +#endif // KOKKOS_CUDA_ERROR_HPP diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Instance.cpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Instance.cpp index 0ca9e3c160..b3c7edf67c 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Instance.cpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Instance.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -66,10 +67,34 @@ #include #include +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION +namespace Kokkos { +namespace Impl { + +bool CudaInternal::kokkos_impl_cuda_use_serial_execution_v = false; + +void CudaInternal::cuda_set_serial_execution(bool val) { + CudaInternal::kokkos_impl_cuda_use_serial_execution_v = val; +} +bool CudaInternal::cuda_use_serial_execution() { + return CudaInternal::kokkos_impl_cuda_use_serial_execution_v; +} + +} // namespace Impl +} // namespace Kokkos + +void kokkos_impl_cuda_set_serial_execution(bool val) { + Kokkos::Impl::CudaInternal::cuda_set_serial_execution(val); +} +bool kokkos_impl_cuda_use_serial_execution() { + return Kokkos::Impl::CudaInternal::cuda_use_serial_execution(); +} +#endif + #ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE -__device__ __constant__ -unsigned long kokkos_impl_cuda_constant_memory_buffer[ Kokkos::Impl::CudaTraits::ConstantMemoryUsage / sizeof(unsigned long) ] ; +__device__ __constant__ unsigned long kokkos_impl_cuda_constant_memory_buffer + [Kokkos::Impl::CudaTraits::ConstantMemoryUsage / sizeof(unsigned long)]; #endif @@ -80,32 +105,28 @@ namespace Impl { namespace { -__global__ -void query_cuda_kernel_arch( int * d_arch ) -{ -#if defined( __CUDA_ARCH__ ) - *d_arch = __CUDA_ARCH__ ; +__global__ void query_cuda_kernel_arch(int *d_arch) { +#if defined(__CUDA_ARCH__) + *d_arch = __CUDA_ARCH__; #else - *d_arch = 0 ; + *d_arch = 0; #endif } /** Query what compute capability is actually launched to the device: */ -int cuda_kernel_arch() -{ - int * d_arch = 0 ; - cudaMalloc( (void **) & d_arch , sizeof(int) ); - query_cuda_kernel_arch<<<1,1>>>( d_arch ); - int arch = 0 ; - cudaMemcpy( & arch , d_arch , sizeof(int) , cudaMemcpyDefault ); - cudaFree( d_arch ); - return arch ; +int cuda_kernel_arch() { + int *d_arch = 0; + cudaMalloc((void **)&d_arch, sizeof(int)); + query_cuda_kernel_arch<<<1, 1>>>(d_arch); + int arch = 0; + cudaMemcpy(&arch, d_arch, sizeof(int), cudaMemcpyDefault); + cudaFree(d_arch); + return arch; } #ifdef KOKKOS_ENABLE_CUDA_UVM -bool cuda_launch_blocking() -{ - const char * env = getenv("CUDA_LAUNCH_BLOCKING"); +bool cuda_launch_blocking() { + const char *env = getenv("CUDA_LAUNCH_BLOCKING"); if (env == 0) return false; @@ -113,21 +134,19 @@ bool cuda_launch_blocking() } #endif -} +} // namespace -void cuda_device_synchronize() -{ - CUDA_SAFE_CALL( cudaDeviceSynchronize() ); -} +void cuda_device_synchronize() { CUDA_SAFE_CALL(cudaDeviceSynchronize()); } -void cuda_internal_error_throw( cudaError e , const char * name, const char * file, const int line ) -{ - std::ostringstream out ; - out << name << " error( " << cudaGetErrorName(e) << "): " << cudaGetErrorString(e); +void cuda_internal_error_throw(cudaError e, const char *name, const char *file, + const int line) { + std::ostringstream out; + out << name << " error( " << cudaGetErrorName(e) + << "): " << cudaGetErrorString(e); if (file) { out << " " << file << ":" << line; } - throw_runtime_exception( out.str() ); + throw_runtime_exception(out.str()); } //---------------------------------------------------------------------------- @@ -180,231 +199,220 @@ void cuda_internal_error_throw( cudaError e , const char * name, const char * fi // int maxThreadsPerMultiProcessor; // }; - namespace { - - class CudaInternalDevices { -public: + public: enum { MAXIMUM_DEVICE_COUNT = 64 }; - struct cudaDeviceProp m_cudaProp[ MAXIMUM_DEVICE_COUNT ] ; - int m_cudaDevCount ; + struct cudaDeviceProp m_cudaProp[MAXIMUM_DEVICE_COUNT]; + int m_cudaDevCount; CudaInternalDevices(); - static const CudaInternalDevices & singleton(); + static const CudaInternalDevices &singleton(); }; -CudaInternalDevices::CudaInternalDevices() -{ +CudaInternalDevices::CudaInternalDevices() { // See 'cudaSetDeviceFlags' for host-device thread interaction // Section 4.4.2.6 of the CUDA Toolkit Reference Manual - CUDA_SAFE_CALL (cudaGetDeviceCount( & m_cudaDevCount ) ); + CUDA_SAFE_CALL(cudaGetDeviceCount(&m_cudaDevCount)); - if(m_cudaDevCount > MAXIMUM_DEVICE_COUNT) { - Kokkos::abort("Sorry, you have more GPUs per node than we thought anybody would ever have. Please report this to github.com/kokkos/kokkos."); + if (m_cudaDevCount > MAXIMUM_DEVICE_COUNT) { + Kokkos::abort( + "Sorry, you have more GPUs per node than we thought anybody would ever " + "have. Please report this to github.com/kokkos/kokkos."); } - for ( int i = 0 ; i < m_cudaDevCount ; ++i ) { - CUDA_SAFE_CALL( cudaGetDeviceProperties( m_cudaProp + i , i ) ); + for (int i = 0; i < m_cudaDevCount; ++i) { + CUDA_SAFE_CALL(cudaGetDeviceProperties(m_cudaProp + i, i)); } } -const CudaInternalDevices & CudaInternalDevices::singleton() -{ - static CudaInternalDevices self ; return self ; -} - +const CudaInternalDevices &CudaInternalDevices::singleton() { + static CudaInternalDevices self; + return self; } +} // namespace int CudaInternal::was_initialized = 0; -int CudaInternal::was_finalized = 0; +int CudaInternal::was_finalized = 0; //---------------------------------------------------------------------------- +void CudaInternal::print_configuration(std::ostream &s) const { + const CudaInternalDevices &dev_info = CudaInternalDevices::singleton(); -void CudaInternal::print_configuration( std::ostream & s ) const -{ - const CudaInternalDevices & dev_info = CudaInternalDevices::singleton(); - -#if defined( KOKKOS_ENABLE_CUDA ) - s << "macro KOKKOS_ENABLE_CUDA : defined" << std::endl ; +#if defined(KOKKOS_ENABLE_CUDA) + s << "macro KOKKOS_ENABLE_CUDA : defined" << std::endl; #endif -#if defined( CUDA_VERSION ) - s << "macro CUDA_VERSION = " << CUDA_VERSION - << " = version " << CUDA_VERSION / 1000 - << "." << ( CUDA_VERSION % 1000 ) / 10 - << std::endl ; +#if defined(CUDA_VERSION) + s << "macro CUDA_VERSION = " << CUDA_VERSION << " = version " + << CUDA_VERSION / 1000 << "." << (CUDA_VERSION % 1000) / 10 << std::endl; #endif - for ( int i = 0 ; i < dev_info.m_cudaDevCount ; ++i ) { - s << "Kokkos::Cuda[ " << i << " ] " - << dev_info.m_cudaProp[i].name - << " capability " << dev_info.m_cudaProp[i].major << "." << dev_info.m_cudaProp[i].minor - << ", Total Global Memory: " << human_memory_size(dev_info.m_cudaProp[i].totalGlobalMem) - << ", Shared Memory per Block: " << human_memory_size(dev_info.m_cudaProp[i].sharedMemPerBlock); - if ( m_cudaDev == i ) s << " : Selected" ; - s << std::endl ; + for (int i = 0; i < dev_info.m_cudaDevCount; ++i) { + s << "Kokkos::Cuda[ " << i << " ] " << dev_info.m_cudaProp[i].name + << " capability " << dev_info.m_cudaProp[i].major << "." + << dev_info.m_cudaProp[i].minor << ", Total Global Memory: " + << human_memory_size(dev_info.m_cudaProp[i].totalGlobalMem) + << ", Shared Memory per Block: " + << human_memory_size(dev_info.m_cudaProp[i].sharedMemPerBlock); + if (m_cudaDev == i) s << " : Selected"; + s << std::endl; } } //---------------------------------------------------------------------------- -CudaInternal::~CudaInternal() -{ - if ( m_stream || - m_scratchSpace || - m_scratchFlags || - m_scratchUnified || - m_scratchConcurrentBitset ) { +CudaInternal::~CudaInternal() { + if (m_stream || m_scratchSpace || m_scratchFlags || m_scratchUnified || + m_scratchConcurrentBitset) { std::cerr << "Kokkos::Cuda ERROR: Failed to call Kokkos::Cuda::finalize()" - << std::endl ; + << std::endl; std::cerr.flush(); } - m_cudaDev = -1 ; - m_cudaArch = -1 ; - m_multiProcCount = 0 ; - m_maxWarpCount = 0 ; - m_maxBlock = 0 ; - m_maxSharedWords = 0 ; - m_maxConcurrency = 0 ; - m_scratchSpaceCount = 0 ; - m_scratchFlagsCount = 0 ; - m_scratchUnifiedCount = 0 ; - m_scratchUnifiedSupported = 0 ; - m_streamCount = 0 ; - m_scratchSpace = 0 ; - m_scratchFlags = 0 ; - m_scratchUnified = 0 ; - m_scratchConcurrentBitset = 0 ; - m_stream = 0 ; -} - -int CudaInternal::verify_is_initialized( const char * const label ) const -{ - if ( m_cudaDev < 0 ) { - std::cerr << "Kokkos::Cuda::" << label << " : ERROR device not initialized" << std::endl ; - } - return 0 <= m_cudaDev ; + m_cudaDev = -1; + m_cudaArch = -1; + m_multiProcCount = 0; + m_maxWarpCount = 0; + m_maxBlock = 0; + m_maxSharedWords = 0; + m_maxConcurrency = 0; + m_scratchSpaceCount = 0; + m_scratchFlagsCount = 0; + m_scratchUnifiedCount = 0; + m_scratchUnifiedSupported = 0; + m_streamCount = 0; + m_scratchSpace = 0; + m_scratchFlags = 0; + m_scratchUnified = 0; + m_scratchConcurrentBitset = 0; + m_stream = 0; } -CudaInternal & CudaInternal::singleton() -{ - static CudaInternal self ; - return self ; +int CudaInternal::verify_is_initialized(const char *const label) const { + if (m_cudaDev < 0) { + std::cerr << "Kokkos::Cuda::" << label << " : ERROR device not initialized" + << std::endl; + } + return 0 <= m_cudaDev; } -void CudaInternal::fence() const { - cudaStreamSynchronize(m_stream); + +CudaInternal &CudaInternal::singleton() { + static CudaInternal self; + return self; } +void CudaInternal::fence() const { cudaStreamSynchronize(m_stream); } -void CudaInternal::initialize( int cuda_device_id , cudaStream_t stream ) -{ - if ( was_finalized ) Kokkos::abort("Calling Cuda::initialize after Cuda::finalize is illegal\n"); +void CudaInternal::initialize(int cuda_device_id, cudaStream_t stream) { + if (was_finalized) + Kokkos::abort("Calling Cuda::initialize after Cuda::finalize is illegal\n"); was_initialized = 1; - if ( is_initialized() ) return; + if (is_initialized()) return; enum { WordSize = sizeof(size_type) }; #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - if ( ! HostSpace::execution_space::is_initialized() ) { + if (!HostSpace::execution_space::is_initialized()) { #else - if ( ! HostSpace::execution_space::impl_is_initialized() ) { + if (!HostSpace::execution_space::impl_is_initialized()) { #endif - const std::string msg("Cuda::initialize ERROR : HostSpace::execution_space is not initialized"); - throw_runtime_exception( msg ); + const std::string msg( + "Cuda::initialize ERROR : HostSpace::execution_space is not " + "initialized"); + throw_runtime_exception(msg); } - const CudaInternalDevices & dev_info = CudaInternalDevices::singleton(); + const CudaInternalDevices &dev_info = CudaInternalDevices::singleton(); - const bool ok_init = 0 == m_scratchSpace || 0 == m_scratchFlags ; + const bool ok_init = 0 == m_scratchSpace || 0 == m_scratchFlags; - const bool ok_id = 0 <= cuda_device_id && - cuda_device_id < dev_info.m_cudaDevCount ; + const bool ok_id = + 0 <= cuda_device_id && cuda_device_id < dev_info.m_cudaDevCount; // Need device capability 3.0 or better - const bool ok_dev = ok_id && - ( 3 <= dev_info.m_cudaProp[ cuda_device_id ].major && - 0 <= dev_info.m_cudaProp[ cuda_device_id ].minor ); - - if ( ok_init && ok_dev ) { + const bool ok_dev = + ok_id && (3 <= dev_info.m_cudaProp[cuda_device_id].major && + 0 <= dev_info.m_cudaProp[cuda_device_id].minor); - const struct cudaDeviceProp & cudaProp = - dev_info.m_cudaProp[ cuda_device_id ]; + if (ok_init && ok_dev) { + const struct cudaDeviceProp &cudaProp = dev_info.m_cudaProp[cuda_device_id]; - m_cudaDev = cuda_device_id ; + m_cudaDev = cuda_device_id; - CUDA_SAFE_CALL( cudaSetDevice( m_cudaDev ) ); + CUDA_SAFE_CALL(cudaSetDevice(m_cudaDev)); Kokkos::Impl::cuda_device_synchronize(); // Query what compute capability architecture a kernel executes: m_cudaArch = cuda_kernel_arch(); int compiled_major = m_cudaArch / 100; - int compiled_minor = ( m_cudaArch % 100 ) / 10; + int compiled_minor = (m_cudaArch % 100) / 10; - if ( compiled_major < 5 && cudaProp.major >= 5 ) { + if (compiled_major < 5 && cudaProp.major >= 5) { std::stringstream ss; - ss << "Kokkos::Cuda::initialize ERROR: running kernels compiled for compute capability " + ss << "Kokkos::Cuda::initialize ERROR: running kernels compiled for " + "compute capability " << compiled_major << "." << compiled_minor - << " (< 5.0) on device with compute capability " - << cudaProp.major << "." << cudaProp.minor - << " (>=5.0), this would give incorrect results!" - << std::endl ; + << " (< 5.0) on device with compute capability " << cudaProp.major + << "." << cudaProp.minor + << " (>=5.0), this would give incorrect results!" << std::endl; std::string msg = ss.str(); - Kokkos::abort( msg.c_str() ); + Kokkos::abort(msg.c_str()); } - if ( Kokkos::show_warnings() && (compiled_major != cudaProp.major || compiled_minor != cudaProp.minor) ) { - std::cerr << "Kokkos::Cuda::initialize WARNING: running kernels compiled for compute capability " + if (Kokkos::show_warnings() && (compiled_major != cudaProp.major || + compiled_minor != cudaProp.minor)) { + std::cerr << "Kokkos::Cuda::initialize WARNING: running kernels compiled " + "for compute capability " << compiled_major << "." << compiled_minor - << " on device with compute capability " - << cudaProp.major << "." << cudaProp.minor + << " on device with compute capability " << cudaProp.major + << "." << cudaProp.minor << " , this will likely reduce potential performance." - << std::endl ; + << std::endl; } // number of multiprocessors - m_multiProcCount = cudaProp.multiProcessorCount ; + m_multiProcCount = cudaProp.multiProcessorCount; //---------------------------------- // Maximum number of warps, // at most one warp per thread in a warp for reduction. - m_maxWarpCount = cudaProp.maxThreadsPerBlock / Impl::CudaTraits::WarpSize ; + m_maxWarpCount = cudaProp.maxThreadsPerBlock / Impl::CudaTraits::WarpSize; - if ( Impl::CudaTraits::WarpSize < m_maxWarpCount ) { - m_maxWarpCount = Impl::CudaTraits::WarpSize ; + if (Impl::CudaTraits::WarpSize < m_maxWarpCount) { + m_maxWarpCount = Impl::CudaTraits::WarpSize; } - m_maxSharedWords = cudaProp.sharedMemPerBlock / WordSize ; + m_maxSharedWords = cudaProp.sharedMemPerBlock / WordSize; //---------------------------------- // Maximum number of blocks: - m_maxBlock = cudaProp.maxGridSize[0] ; + m_maxBlock = cudaProp.maxGridSize[0]; - m_shmemPerSM = cudaProp.sharedMemPerMultiprocessor ; - m_maxShmemPerBlock = cudaProp.sharedMemPerBlock ; - m_regsPerSM = cudaProp.regsPerMultiprocessor ; - m_maxBlocksPerSM = m_cudaArch < 500 ? 16 : ( - m_cudaArch < 750 ? 32 : ( - m_cudaArch == 750 ? 16 : 32)); - m_maxThreadsPerSM = cudaProp.maxThreadsPerMultiProcessor ; - m_maxThreadsPerBlock = cudaProp.maxThreadsPerBlock ; + m_shmemPerSM = cudaProp.sharedMemPerMultiprocessor; + m_maxShmemPerBlock = cudaProp.sharedMemPerBlock; + m_regsPerSM = cudaProp.regsPerMultiprocessor; + m_maxBlocksPerSM = + m_cudaArch < 500 + ? 16 + : (m_cudaArch < 750 ? 32 : (m_cudaArch == 750 ? 16 : 32)); + m_maxThreadsPerSM = cudaProp.maxThreadsPerMultiProcessor; + m_maxThreadsPerBlock = cudaProp.maxThreadsPerBlock; //---------------------------------- - m_scratchUnifiedSupported = cudaProp.unifiedAddressing ; + m_scratchUnifiedSupported = cudaProp.unifiedAddressing; - if ( Kokkos::show_warnings() && ! m_scratchUnifiedSupported ) { - std::cerr << "Kokkos::Cuda device " - << cudaProp.name << " capability " + if (Kokkos::show_warnings() && !m_scratchUnifiedSupported) { + std::cerr << "Kokkos::Cuda device " << cudaProp.name << " capability " << cudaProp.major << "." << cudaProp.minor << " does not support unified virtual address space" - << std::endl ; + << std::endl; } //---------------------------------- @@ -413,345 +421,362 @@ void CudaInternal::initialize( int cuda_device_id , cudaStream_t stream ) // Allocate some initial space. This will grow as needed. { - const unsigned reduce_block_count = m_maxWarpCount * Impl::CudaTraits::WarpSize ; + const unsigned reduce_block_count = + m_maxWarpCount * Impl::CudaTraits::WarpSize; - (void) scratch_unified( 16 * sizeof(size_type) ); - (void) scratch_flags( reduce_block_count * 2 * sizeof(size_type) ); - (void) scratch_space( reduce_block_count * 16 * sizeof(size_type) ); + (void)scratch_unified(16 * sizeof(size_type)); + (void)scratch_flags(reduce_block_count * 2 * sizeof(size_type)); + (void)scratch_space(reduce_block_count * 16 * sizeof(size_type)); } //---------------------------------- // Concurrent bitset for obtaining unique tokens from within // an executing kernel. { - - m_maxConcurrency = - m_maxThreadsPerSM * cudaProp.multiProcessorCount ; + m_maxConcurrency = m_maxThreadsPerSM * cudaProp.multiProcessorCount; const int32_t buffer_bound = - Kokkos::Impl::concurrent_bitset::buffer_bound( m_maxConcurrency ); + Kokkos::Impl::concurrent_bitset::buffer_bound(m_maxConcurrency); // Allocate and initialize uint32_t[ buffer_bound ] - typedef Kokkos::Impl::SharedAllocationRecord< Kokkos::CudaSpace , void > Record ; - - Record * const r = Record::allocate( Kokkos::CudaSpace() - , "InternalScratchBitset" - , sizeof(uint32_t) * buffer_bound ); + typedef Kokkos::Impl::SharedAllocationRecord + Record; - Record::increment( r ); + Record *const r = + Record::allocate(Kokkos::CudaSpace(), "InternalScratchBitset", + sizeof(uint32_t) * buffer_bound); - m_scratchConcurrentBitset = reinterpret_cast( r->data() ); + Record::increment(r); - CUDA_SAFE_CALL( cudaMemset( m_scratchConcurrentBitset , 0 , sizeof(uint32_t) * buffer_bound ) ); + m_scratchConcurrentBitset = reinterpret_cast(r->data()); + CUDA_SAFE_CALL(cudaMemset(m_scratchConcurrentBitset, 0, + sizeof(uint32_t) * buffer_bound)); } //---------------------------------- - } - else { + } else { + std::ostringstream msg; + msg << "Kokkos::Cuda::initialize(" << cuda_device_id << ") FAILED"; - std::ostringstream msg ; - msg << "Kokkos::Cuda::initialize(" << cuda_device_id << ") FAILED" ; - - if ( ! ok_init ) { - msg << " : Already initialized" ; + if (!ok_init) { + msg << " : Already initialized"; } - if ( ! ok_id ) { + if (!ok_id) { msg << " : Device identifier out of range " - << "[0.." << dev_info.m_cudaDevCount << "]" ; - } - else if ( ! ok_dev ) { - msg << " : Device " ; - msg << dev_info.m_cudaProp[ cuda_device_id ].major ; - msg << "." ; - msg << dev_info.m_cudaProp[ cuda_device_id ].minor ; - msg << " has insufficient capability, required 3.0 or better" ; + << "[0.." << dev_info.m_cudaDevCount << "]"; + } else if (!ok_dev) { + msg << " : Device "; + msg << dev_info.m_cudaProp[cuda_device_id].major; + msg << "."; + msg << dev_info.m_cudaProp[cuda_device_id].minor; + msg << " has insufficient capability, required 3.0 or better"; } - Kokkos::Impl::throw_runtime_exception( msg.str() ); + Kokkos::Impl::throw_runtime_exception(msg.str()); } - #ifdef KOKKOS_ENABLE_CUDA_UVM - if( Kokkos::show_warnings() && !cuda_launch_blocking() ) { - std::cerr << "Kokkos::Cuda::initialize WARNING: Cuda is allocating into UVMSpace by default" << std::endl; - std::cerr << " without setting CUDA_LAUNCH_BLOCKING=1." << std::endl; - std::cerr << " The code must call Cuda().fence() after each kernel" << std::endl; - std::cerr << " or will likely crash when accessing data on the host." << std::endl; - } +#ifdef KOKKOS_ENABLE_CUDA_UVM + if (Kokkos::show_warnings() && !cuda_launch_blocking()) { + std::cerr << "Kokkos::Cuda::initialize WARNING: Cuda is allocating into " + "UVMSpace by default" + << std::endl; + std::cerr << " without setting " + "CUDA_LAUNCH_BLOCKING=1." + << std::endl; + std::cerr << " The code must call " + "Cuda().fence() after each kernel" + << std::endl; + std::cerr << " or will likely crash when " + "accessing data on the host." + << std::endl; + } - const char * env_force_device_alloc = getenv("CUDA_MANAGED_FORCE_DEVICE_ALLOC"); - bool force_device_alloc; - if (env_force_device_alloc == 0) force_device_alloc=false; - else force_device_alloc=atoi(env_force_device_alloc)!=0; - - const char * env_visible_devices = getenv("CUDA_VISIBLE_DEVICES"); - bool visible_devices_one=true; - if (env_visible_devices == 0) visible_devices_one=false; - - if( Kokkos::show_warnings() && (!visible_devices_one && !force_device_alloc) ) { - std::cerr << "Kokkos::Cuda::initialize WARNING: Cuda is allocating into UVMSpace by default" << std::endl; - std::cerr << " without setting CUDA_MANAGED_FORCE_DEVICE_ALLOC=1 or " << std::endl; - std::cerr << " setting CUDA_VISIBLE_DEVICES." << std::endl; - std::cerr << " This could on multi GPU systems lead to severe performance" << std::endl; - std::cerr << " penalties." << std::endl; - } - #endif + const char *env_force_device_alloc = + getenv("CUDA_MANAGED_FORCE_DEVICE_ALLOC"); + bool force_device_alloc; + if (env_force_device_alloc == 0) + force_device_alloc = false; + else + force_device_alloc = atoi(env_force_device_alloc) != 0; + + const char *env_visible_devices = getenv("CUDA_VISIBLE_DEVICES"); + bool visible_devices_one = true; + if (env_visible_devices == 0) visible_devices_one = false; + + if (Kokkos::show_warnings() && + (!visible_devices_one && !force_device_alloc)) { + std::cerr << "Kokkos::Cuda::initialize WARNING: Cuda is allocating into " + "UVMSpace by default" + << std::endl; + std::cerr << " without setting " + "CUDA_MANAGED_FORCE_DEVICE_ALLOC=1 or " + << std::endl; + std::cerr + << " setting CUDA_VISIBLE_DEVICES." + << std::endl; + std::cerr << " This could on multi GPU " + "systems lead to severe performance" + << std::endl; + std::cerr << " penalties." << std::endl; + } +#endif - #ifdef KOKKOS_ENABLE_PRE_CUDA_10_DEPRECATION_API +#ifdef KOKKOS_ENABLE_PRE_CUDA_10_DEPRECATION_API cudaThreadSetCacheConfig(cudaFuncCachePreferShared); - #else +#else cudaDeviceSetCacheConfig(cudaFuncCachePreferShared); - #endif +#endif // Init the array for used for arbitrarily sized atomics - if(stream == 0) - Impl::initialize_host_cuda_lock_arrays(); + if (stream == 0) Impl::initialize_host_cuda_lock_arrays(); m_stream = stream; } //---------------------------------------------------------------------------- -typedef Cuda::size_type ScratchGrain[ Impl::CudaTraits::WarpSize ] ; +typedef Cuda::size_type ScratchGrain[Impl::CudaTraits::WarpSize]; enum { sizeScratchGrain = sizeof(ScratchGrain) }; +Cuda::size_type *CudaInternal::scratch_flags(const Cuda::size_type size) const { + if (verify_is_initialized("scratch_flags") && + m_scratchFlagsCount * sizeScratchGrain < size) { + m_scratchFlagsCount = (size + sizeScratchGrain - 1) / sizeScratchGrain; -Cuda::size_type * -CudaInternal::scratch_flags( const Cuda::size_type size ) const -{ - if ( verify_is_initialized("scratch_flags") && m_scratchFlagsCount * sizeScratchGrain < size ) { - - - m_scratchFlagsCount = ( size + sizeScratchGrain - 1 ) / sizeScratchGrain ; - - typedef Kokkos::Impl::SharedAllocationRecord< Kokkos::CudaSpace , void > Record ; + typedef Kokkos::Impl::SharedAllocationRecord + Record; - if( m_scratchFlags ) - Record::decrement( Record::get_record( m_scratchFlags ) ); + if (m_scratchFlags) Record::decrement(Record::get_record(m_scratchFlags)); - Record * const r = Record::allocate( Kokkos::CudaSpace() - , "InternalScratchFlags" - , ( sizeof( ScratchGrain ) * m_scratchFlagsCount ) ); + Record *const r = + Record::allocate(Kokkos::CudaSpace(), "InternalScratchFlags", + (sizeof(ScratchGrain) * m_scratchFlagsCount)); - Record::increment( r ); + Record::increment(r); - m_scratchFlags = reinterpret_cast( r->data() ); + m_scratchFlags = reinterpret_cast(r->data()); - CUDA_SAFE_CALL( cudaMemset( m_scratchFlags , 0 , m_scratchFlagsCount * sizeScratchGrain ) ); + CUDA_SAFE_CALL( + cudaMemset(m_scratchFlags, 0, m_scratchFlagsCount * sizeScratchGrain)); } - return m_scratchFlags ; + return m_scratchFlags; } -Cuda::size_type * -CudaInternal::scratch_space( const Cuda::size_type size ) const -{ - if ( verify_is_initialized("scratch_space") && m_scratchSpaceCount * sizeScratchGrain < size ) { - - m_scratchSpaceCount = ( size + sizeScratchGrain - 1 ) / sizeScratchGrain ; +Cuda::size_type *CudaInternal::scratch_space(const Cuda::size_type size) const { + if (verify_is_initialized("scratch_space") && + m_scratchSpaceCount * sizeScratchGrain < size) { + m_scratchSpaceCount = (size + sizeScratchGrain - 1) / sizeScratchGrain; - typedef Kokkos::Impl::SharedAllocationRecord< Kokkos::CudaSpace , void > Record ; + typedef Kokkos::Impl::SharedAllocationRecord + Record; - if( m_scratchSpace ) - Record::decrement( Record::get_record( m_scratchSpace ) ); + if (m_scratchSpace) Record::decrement(Record::get_record(m_scratchSpace)); - Record * const r = Record::allocate( Kokkos::CudaSpace() - , "InternalScratchSpace" - , ( sizeof( ScratchGrain ) * m_scratchSpaceCount ) ); + Record *const r = + Record::allocate(Kokkos::CudaSpace(), "InternalScratchSpace", + (sizeof(ScratchGrain) * m_scratchSpaceCount)); - Record::increment( r ); + Record::increment(r); - m_scratchSpace = reinterpret_cast( r->data() ); + m_scratchSpace = reinterpret_cast(r->data()); } - return m_scratchSpace ; + return m_scratchSpace; } -Cuda::size_type * -CudaInternal::scratch_unified( const Cuda::size_type size ) const -{ - if ( verify_is_initialized("scratch_unified") && - m_scratchUnifiedSupported && m_scratchUnifiedCount * sizeScratchGrain < size ) { +Cuda::size_type *CudaInternal::scratch_unified( + const Cuda::size_type size) const { + if (verify_is_initialized("scratch_unified") && m_scratchUnifiedSupported && + m_scratchUnifiedCount * sizeScratchGrain < size) { + m_scratchUnifiedCount = (size + sizeScratchGrain - 1) / sizeScratchGrain; - m_scratchUnifiedCount = ( size + sizeScratchGrain - 1 ) / sizeScratchGrain ; + typedef Kokkos::Impl::SharedAllocationRecord + Record; - typedef Kokkos::Impl::SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void > Record ; + if (m_scratchUnified) + Record::decrement(Record::get_record(m_scratchUnified)); - if( m_scratchUnified ) - Record::decrement( Record::get_record( m_scratchUnified ) ); + Record *const r = Record::allocate( + Kokkos::CudaHostPinnedSpace(), "InternalScratchUnified", + (sizeof(ScratchGrain) * m_scratchUnifiedCount)); - Record * const r = Record::allocate( Kokkos::CudaHostPinnedSpace() - , "InternalScratchUnified" - , ( sizeof( ScratchGrain ) * m_scratchUnifiedCount ) ); + Record::increment(r); - Record::increment( r ); - - m_scratchUnified = reinterpret_cast( r->data() ); + m_scratchUnified = reinterpret_cast(r->data()); } - return m_scratchUnified ; + return m_scratchUnified; } -Cuda::size_type * -CudaInternal::scratch_functor( const Cuda::size_type size ) const -{ - if ( verify_is_initialized("scratch_functor") && - m_scratchFunctorSize < size ) { - - m_scratchFunctorSize = size ; +Cuda::size_type *CudaInternal::scratch_functor( + const Cuda::size_type size) const { + if (verify_is_initialized("scratch_functor") && m_scratchFunctorSize < size) { + m_scratchFunctorSize = size; - typedef Kokkos::Impl::SharedAllocationRecord< Kokkos::CudaSpace , void > Record ; + typedef Kokkos::Impl::SharedAllocationRecord + Record; - if( m_scratchFunctor ) - Record::decrement( Record::get_record( m_scratchFunctor ) ); + if (m_scratchFunctor) + Record::decrement(Record::get_record(m_scratchFunctor)); - Record * const r = Record::allocate( Kokkos::CudaSpace() - , "InternalScratchFunctor" - , m_scratchFunctorSize ); + Record *const r = Record::allocate( + Kokkos::CudaSpace(), "InternalScratchFunctor", m_scratchFunctorSize); - Record::increment( r ); + Record::increment(r); - m_scratchFunctor = reinterpret_cast( r->data() ); + m_scratchFunctor = reinterpret_cast(r->data()); } - return m_scratchFunctor ; + return m_scratchFunctor; } //---------------------------------------------------------------------------- -void CudaInternal::finalize() -{ +void CudaInternal::finalize() { was_finalized = 1; - if ( 0 != m_scratchSpace || 0 != m_scratchFlags ) { - + if (0 != m_scratchSpace || 0 != m_scratchFlags) { Impl::finalize_host_cuda_lock_arrays(); - if(m_stream!=0) cudaStreamDestroy(m_stream); - - typedef Kokkos::Impl::SharedAllocationRecord< CudaSpace > RecordCuda ; - typedef Kokkos::Impl::SharedAllocationRecord< CudaHostPinnedSpace > RecordHost ; - - RecordCuda::decrement( RecordCuda::get_record( m_scratchFlags ) ); - RecordCuda::decrement( RecordCuda::get_record( m_scratchSpace ) ); - RecordHost::decrement( RecordHost::get_record( m_scratchUnified ) ); - RecordCuda::decrement( RecordCuda::get_record( m_scratchConcurrentBitset ) ); - if(m_scratchFunctorSize>0) - RecordCuda::decrement( RecordCuda::get_record( m_scratchFunctor ) ); - - m_cudaDev = -1 ; - m_multiProcCount = 0 ; - m_maxWarpCount = 0 ; - m_maxBlock = 0 ; - m_maxSharedWords = 0 ; - m_scratchSpaceCount = 0 ; - m_scratchFlagsCount = 0 ; - m_scratchUnifiedCount = 0 ; - m_streamCount = 0 ; - m_scratchSpace = 0 ; - m_scratchFlags = 0 ; - m_scratchUnified = 0 ; - m_scratchConcurrentBitset = 0 ; - m_stream = 0 ; + if (m_stream != 0) cudaStreamDestroy(m_stream); + + typedef Kokkos::Impl::SharedAllocationRecord RecordCuda; + typedef Kokkos::Impl::SharedAllocationRecord + RecordHost; + + RecordCuda::decrement(RecordCuda::get_record(m_scratchFlags)); + RecordCuda::decrement(RecordCuda::get_record(m_scratchSpace)); + RecordHost::decrement(RecordHost::get_record(m_scratchUnified)); + RecordCuda::decrement(RecordCuda::get_record(m_scratchConcurrentBitset)); + if (m_scratchFunctorSize > 0) + RecordCuda::decrement(RecordCuda::get_record(m_scratchFunctor)); + + m_cudaDev = -1; + m_multiProcCount = 0; + m_maxWarpCount = 0; + m_maxBlock = 0; + m_maxSharedWords = 0; + m_scratchSpaceCount = 0; + m_scratchFlagsCount = 0; + m_scratchUnifiedCount = 0; + m_streamCount = 0; + m_scratchSpace = 0; + m_scratchFlags = 0; + m_scratchUnified = 0; + m_scratchConcurrentBitset = 0; + m_stream = 0; } } //---------------------------------------------------------------------------- -Cuda::size_type cuda_internal_multiprocessor_count() -{ return CudaInternal::singleton().m_multiProcCount ; } +Cuda::size_type cuda_internal_multiprocessor_count() { + return CudaInternal::singleton().m_multiProcCount; +} -CudaSpace::size_type cuda_internal_maximum_concurrent_block_count() -{ - #if defined(KOKKOS_ARCH_KEPLER) +CudaSpace::size_type cuda_internal_maximum_concurrent_block_count() { +#if defined(KOKKOS_ARCH_KEPLER) // Compute capability 3.0 through 3.7 enum : int { max_resident_blocks_per_multiprocessor = 16 }; - #else +#else // Compute capability 5.0 through 6.2 enum : int { max_resident_blocks_per_multiprocessor = 32 }; - #endif - return CudaInternal::singleton().m_multiProcCount - * max_resident_blocks_per_multiprocessor ; +#endif + return CudaInternal::singleton().m_multiProcCount * + max_resident_blocks_per_multiprocessor; }; -Cuda::size_type cuda_internal_maximum_warp_count() -{ return CudaInternal::singleton().m_maxWarpCount ; } - -Cuda::size_type cuda_internal_maximum_grid_count() -{ return CudaInternal::singleton().m_maxBlock ; } +Cuda::size_type cuda_internal_maximum_warp_count() { + return CudaInternal::singleton().m_maxWarpCount; +} -Cuda::size_type cuda_internal_maximum_shared_words() -{ return CudaInternal::singleton().m_maxSharedWords ; } +Cuda::size_type cuda_internal_maximum_grid_count() { + return CudaInternal::singleton().m_maxBlock; +} -Cuda::size_type * cuda_internal_scratch_space( const Cuda& instance, const Cuda::size_type size ) -{ return instance.impl_internal_space_instance()->scratch_space( size ); } +Cuda::size_type cuda_internal_maximum_shared_words() { + return CudaInternal::singleton().m_maxSharedWords; +} -Cuda::size_type * cuda_internal_scratch_flags( const Cuda& instance, const Cuda::size_type size ) -{ return instance.impl_internal_space_instance()->scratch_flags( size ); } +Cuda::size_type *cuda_internal_scratch_space(const Cuda &instance, + const Cuda::size_type size) { + return instance.impl_internal_space_instance()->scratch_space(size); +} -Cuda::size_type * cuda_internal_scratch_unified( const Cuda& instance, const Cuda::size_type size ) -{ return instance.impl_internal_space_instance()->scratch_unified( size ); } +Cuda::size_type *cuda_internal_scratch_flags(const Cuda &instance, + const Cuda::size_type size) { + return instance.impl_internal_space_instance()->scratch_flags(size); +} +Cuda::size_type *cuda_internal_scratch_unified(const Cuda &instance, + const Cuda::size_type size) { + return instance.impl_internal_space_instance()->scratch_unified(size); +} -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- namespace Kokkos { -Cuda::size_type Cuda::detect_device_count() -{ return Impl::CudaInternalDevices::singleton().m_cudaDevCount ; } +Cuda::size_type Cuda::detect_device_count() { + return Impl::CudaInternalDevices::singleton().m_cudaDevCount; +} -int Cuda::concurrency() -{ return Impl::CudaInternal::singleton().m_maxConcurrency ; } +int Cuda::concurrency() { + return Impl::CudaInternal::singleton().m_maxConcurrency; +} #ifdef KOKKOS_ENABLE_DEPRECATED_CODE int Cuda::is_initialized() #else int Cuda::impl_is_initialized() #endif -{ return Impl::CudaInternal::singleton().is_initialized(); } +{ + return Impl::CudaInternal::singleton().is_initialized(); +} #ifdef KOKKOS_ENABLE_DEPRECATED_CODE -void Cuda::initialize( const Cuda::SelectDevice config , size_t num_instances ) +void Cuda::initialize(const Cuda::SelectDevice config, size_t num_instances) #else -void Cuda::impl_initialize( const Cuda::SelectDevice config , size_t num_instances ) +void Cuda::impl_initialize(const Cuda::SelectDevice config, + size_t num_instances) #endif { - Impl::CudaInternal::singleton().initialize( config.cuda_device_id , 0 ); + Impl::CudaInternal::singleton().initialize(config.cuda_device_id, 0); - #if defined(KOKKOS_ENABLE_PROFILING) - Kokkos::Profiling::initialize(); - #endif +#if defined(KOKKOS_ENABLE_PROFILING) + Kokkos::Profiling::initialize(); +#endif } -std::vector -Cuda::detect_device_arch() -{ - const Impl::CudaInternalDevices & s = Impl::CudaInternalDevices::singleton(); +std::vector Cuda::detect_device_arch() { + const Impl::CudaInternalDevices &s = Impl::CudaInternalDevices::singleton(); - std::vector output( s.m_cudaDevCount ); + std::vector output(s.m_cudaDevCount); - for ( int i = 0 ; i < s.m_cudaDevCount ; ++i ) { - output[i] = s.m_cudaProp[i].major * 100 + s.m_cudaProp[i].minor ; + for (int i = 0; i < s.m_cudaDevCount; ++i) { + output[i] = s.m_cudaProp[i].major * 100 + s.m_cudaProp[i].minor; } - return output ; + return output; } -Cuda::size_type Cuda::device_arch() -{ - const int dev_id = Impl::CudaInternal::singleton().m_cudaDev ; +Cuda::size_type Cuda::device_arch() { + const int dev_id = Impl::CudaInternal::singleton().m_cudaDev; - int dev_arch = 0 ; + int dev_arch = 0; - if ( 0 <= dev_id ) { - const struct cudaDeviceProp & cudaProp = - Impl::CudaInternalDevices::singleton().m_cudaProp[ dev_id ] ; + if (0 <= dev_id) { + const struct cudaDeviceProp &cudaProp = + Impl::CudaInternalDevices::singleton().m_cudaProp[dev_id]; - dev_arch = cudaProp.major * 100 + cudaProp.minor ; + dev_arch = cudaProp.major * 100 + cudaProp.minor; } - return dev_arch ; + return dev_arch; } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE @@ -762,71 +787,62 @@ void Cuda::impl_finalize() { Impl::CudaInternal::singleton().finalize(); - #if defined(KOKKOS_ENABLE_PROFILING) - Kokkos::Profiling::finalize(); - #endif +#if defined(KOKKOS_ENABLE_PROFILING) + Kokkos::Profiling::finalize(); +#endif } -Cuda::Cuda() - : m_space_instance( &Impl::CudaInternal::singleton() ) -{ - Impl::CudaInternal::singleton().verify_is_initialized( "Cuda instance constructor" ); +Cuda::Cuda() : m_space_instance(&Impl::CudaInternal::singleton()) { + Impl::CudaInternal::singleton().verify_is_initialized( + "Cuda instance constructor"); } -Cuda::Cuda(cudaStream_t stream) - : m_space_instance(new Impl::CudaInternal) -{ - Impl::CudaInternal::singleton().verify_is_initialized( "Cuda instance constructor" ); - m_space_instance->initialize(Impl::CudaInternal::singleton().m_cudaDev,stream); +Cuda::Cuda(cudaStream_t stream) : m_space_instance(new Impl::CudaInternal) { + Impl::CudaInternal::singleton().verify_is_initialized( + "Cuda instance constructor"); + m_space_instance->initialize(Impl::CudaInternal::singleton().m_cudaDev, + stream); } -void Cuda::print_configuration( std::ostream & s , const bool ) -{ Impl::CudaInternal::singleton().print_configuration( s ); } +void Cuda::print_configuration(std::ostream &s, const bool) { + Impl::CudaInternal::singleton().print_configuration(s); +} #ifdef KOKKOS_ENABLE_DEPRECATED_CODE -bool Cuda::sleep() { return false ; } +bool Cuda::sleep() { return false; } -bool Cuda::wake() { return true ; } +bool Cuda::wake() { return true; } #endif -void Cuda::impl_static_fence() -{ - Kokkos::Impl::cuda_device_synchronize(); -} +void Cuda::impl_static_fence() { Kokkos::Impl::cuda_device_synchronize(); } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE -void Cuda::fence() { - impl_static_fence(); -} +void Cuda::fence() { impl_static_fence(); } #else -void Cuda::fence() const { - m_space_instance->fence(); -} +void Cuda::fence() const { m_space_instance->fence(); } #endif -const char* Cuda::name() { return "Cuda"; } +const char *Cuda::name() { return "Cuda"; } -cudaStream_t Cuda::cuda_stream() const { return m_space_instance->m_stream ; } -int Cuda::cuda_device() const { return m_space_instance->m_cudaDev ; } +cudaStream_t Cuda::cuda_stream() const { return m_space_instance->m_stream; } +int Cuda::cuda_device() const { return m_space_instance->m_cudaDev; } - -} // namespace Kokkos +} // namespace Kokkos namespace Kokkos { namespace Experimental { -UniqueToken< Kokkos::Cuda , Kokkos::Experimental::UniqueTokenScope::Global >:: -UniqueToken( Kokkos::Cuda const & ) - : m_buffer( Kokkos::Impl::CudaInternal::singleton().m_scratchConcurrentBitset ) - , m_count( Kokkos::Impl::CudaInternal::singleton().m_maxConcurrency ) - {} +UniqueToken:: + UniqueToken(Kokkos::Cuda const &) + : m_buffer( + Kokkos::Impl::CudaInternal::singleton().m_scratchConcurrentBitset), + m_count(Kokkos::Impl::CudaInternal::singleton().m_maxConcurrency) {} -} // namespace Experimental -} // namespace Kokkos +} // namespace Experimental +} // namespace Kokkos #else void KOKKOS_CORE_SRC_CUDA_IMPL_PREVENT_LINK_ERROR() {} -#endif // KOKKOS_ENABLE_CUDA - +#endif // KOKKOS_ENABLE_CUDA diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Instance.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Instance.hpp index f9e333fcf0..9d2c939af8 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Instance.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Instance.hpp @@ -3,39 +3,48 @@ //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- +// These functions fulfill the purpose of allowing to work around +// a suspected system software issue, or to check for race conditions. +// They are not currently a fully officially supported capability. +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION +extern "C" void kokkos_impl_cuda_set_serial_execution(bool); +extern "C" bool kokkos_impl_cuda_use_serial_execution(); +#endif namespace Kokkos { namespace Impl { struct CudaTraits { - enum { WarpSize = 32 /* 0x0020 */ }; - enum { WarpIndexMask = 0x001f /* Mask for warpindex */ }; - enum { WarpIndexShift = 5 /* WarpSize == 1 << WarpShift */ }; + enum { WarpSize = 32 /* 0x0020 */ }; + enum { WarpIndexMask = 0x001f /* Mask for warpindex */ }; + enum { WarpIndexShift = 5 /* WarpSize == 1 << WarpShift */ }; - enum { ConstantMemoryUsage = 0x008000 /* 32k bytes */ }; - enum { ConstantMemoryCache = 0x002000 /* 8k bytes */ }; - enum { KernelArgumentLimit = 0x001000 /* 4k bytes */ }; + enum { ConstantMemoryUsage = 0x008000 /* 32k bytes */ }; + enum { ConstantMemoryCache = 0x002000 /* 8k bytes */ }; + enum { KernelArgumentLimit = 0x001000 /* 4k bytes */ }; typedef unsigned long - ConstantGlobalBufferType[ ConstantMemoryUsage / sizeof(unsigned long) ]; + ConstantGlobalBufferType[ConstantMemoryUsage / sizeof(unsigned long)]; -#if defined(KOKKOS_ARCH_VOLTA) || \ - defined(KOKKOS_ARCH_PASCAL) - enum { ConstantMemoryUseThreshold = 0x000200 /* 0 bytes -> always use constant (or global)*/ }; +#if defined(KOKKOS_ARCH_VOLTA) || defined(KOKKOS_ARCH_PASCAL) + enum { + ConstantMemoryUseThreshold = + 0x000200 /* 0 bytes -> always use constant (or global)*/ + }; #else enum { ConstantMemoryUseThreshold = 0x000200 /* 512 bytes */ }; #endif - KOKKOS_INLINE_FUNCTION static - CudaSpace::size_type warp_count( CudaSpace::size_type i ) - { return ( i + WarpIndexMask ) >> WarpIndexShift ; } + KOKKOS_INLINE_FUNCTION static CudaSpace::size_type warp_count( + CudaSpace::size_type i) { + return (i + WarpIndexMask) >> WarpIndexShift; + } - KOKKOS_INLINE_FUNCTION static - CudaSpace::size_type warp_align( CudaSpace::size_type i ) - { - enum { Mask = ~CudaSpace::size_type( WarpIndexMask ) }; - return ( i + WarpIndexMask ) & Mask ; - } + KOKKOS_INLINE_FUNCTION static CudaSpace::size_type warp_align( + CudaSpace::size_type i) { + enum { Mask = ~CudaSpace::size_type(WarpIndexMask) }; + return (i + WarpIndexMask) & Mask; + } }; //---------------------------------------------------------------------------- @@ -47,110 +56,118 @@ CudaSpace::size_type cuda_internal_maximum_shared_words(); CudaSpace::size_type cuda_internal_maximum_concurrent_block_count(); -CudaSpace::size_type * cuda_internal_scratch_flags( const Cuda&, const CudaSpace::size_type size ); -CudaSpace::size_type * cuda_internal_scratch_space( const Cuda&, const CudaSpace::size_type size ); -CudaSpace::size_type * cuda_internal_scratch_unified( const Cuda&, const CudaSpace::size_type size ); +CudaSpace::size_type* cuda_internal_scratch_flags( + const Cuda&, const CudaSpace::size_type size); +CudaSpace::size_type* cuda_internal_scratch_space( + const Cuda&, const CudaSpace::size_type size); +CudaSpace::size_type* cuda_internal_scratch_unified( + const Cuda&, const CudaSpace::size_type size); -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- namespace Kokkos { namespace Impl { class CudaInternal { -private: - - CudaInternal( const CudaInternal & ); - CudaInternal & operator = ( const CudaInternal & ); - - -public: + private: + CudaInternal(const CudaInternal&); + CudaInternal& operator=(const CudaInternal&); +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + static bool kokkos_impl_cuda_use_serial_execution_v; +#endif - typedef Cuda::size_type size_type ; + public: + typedef Cuda::size_type size_type; - int m_cudaDev ; + int m_cudaDev; // Device Properties - int m_cudaArch ; - unsigned m_multiProcCount ; - unsigned m_maxWarpCount ; - unsigned m_maxBlock ; - unsigned m_maxSharedWords ; - uint32_t m_maxConcurrency ; - int m_shmemPerSM ; - int m_maxShmemPerBlock ; - int m_regsPerSM ; - int m_maxBlocksPerSM ; - int m_maxThreadsPerSM ; - int m_maxThreadsPerBlock ; - - mutable size_type m_scratchSpaceCount ; - mutable size_type m_scratchFlagsCount ; - mutable size_type m_scratchUnifiedCount ; - mutable size_type m_scratchFunctorSize ; - size_type m_scratchUnifiedSupported ; - size_type m_streamCount ; - mutable size_type * m_scratchSpace ; - mutable size_type * m_scratchFlags ; - mutable size_type * m_scratchUnified ; - mutable size_type * m_scratchFunctor ; - uint32_t * m_scratchConcurrentBitset ; - cudaStream_t m_stream ; + int m_cudaArch; + unsigned m_multiProcCount; + unsigned m_maxWarpCount; + unsigned m_maxBlock; + unsigned m_maxSharedWords; + uint32_t m_maxConcurrency; + int m_shmemPerSM; + int m_maxShmemPerBlock; + int m_regsPerSM; + int m_maxBlocksPerSM; + int m_maxThreadsPerSM; + int m_maxThreadsPerBlock; + + mutable size_type m_scratchSpaceCount; + mutable size_type m_scratchFlagsCount; + mutable size_type m_scratchUnifiedCount; + mutable size_type m_scratchFunctorSize; + size_type m_scratchUnifiedSupported; + size_type m_streamCount; + mutable size_type* m_scratchSpace; + mutable size_type* m_scratchFlags; + mutable size_type* m_scratchUnified; + mutable size_type* m_scratchFunctor; + uint32_t* m_scratchConcurrentBitset; + cudaStream_t m_stream; static int was_initialized; static int was_finalized; - static CudaInternal & singleton(); + static CudaInternal& singleton(); - int verify_is_initialized( const char * const label ) const ; + int verify_is_initialized(const char* const label) const; - int is_initialized() const - { return 0 != m_scratchSpace && 0 != m_scratchFlags ; } + int is_initialized() const { + return 0 != m_scratchSpace && 0 != m_scratchFlags; + } - void initialize( int cuda_device_id , cudaStream_t stream = 0 ); + void initialize(int cuda_device_id, cudaStream_t stream = 0); void finalize(); - void print_configuration( std::ostream & ) const ; + void print_configuration(std::ostream&) const; + +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + static bool cuda_use_serial_execution(); + static void cuda_set_serial_execution(bool); +#endif - void fence() const ; + void fence() const; ~CudaInternal(); CudaInternal() - : m_cudaDev( -1 ) - , m_cudaArch( -1 ) - , m_multiProcCount( 0 ) - , m_maxWarpCount( 0 ) - , m_maxBlock( 0 ) - , m_maxSharedWords( 0 ) - , m_maxConcurrency( 0 ) - , m_shmemPerSM( 0 ) - , m_maxShmemPerBlock( 0 ) - , m_regsPerSM( 0 ) - , m_maxBlocksPerSM( 0 ) - , m_maxThreadsPerSM( 0 ) - , m_maxThreadsPerBlock( 0 ) - , m_scratchSpaceCount( 0 ) - , m_scratchFlagsCount( 0 ) - , m_scratchUnifiedCount( 0 ) - , m_scratchFunctorSize( 0 ) - , m_scratchUnifiedSupported( 0 ) - , m_streamCount( 0 ) - , m_scratchSpace( 0 ) - , m_scratchFlags( 0 ) - , m_scratchUnified( 0 ) - , m_scratchFunctor( 0 ) - , m_scratchConcurrentBitset( 0 ) - , m_stream( 0 ) - {} - - size_type * scratch_space( const size_type size ) const ; - size_type * scratch_flags( const size_type size ) const ; - size_type * scratch_unified( const size_type size ) const ; - size_type * scratch_functor( const size_type size ) const ; + : m_cudaDev(-1), + m_cudaArch(-1), + m_multiProcCount(0), + m_maxWarpCount(0), + m_maxBlock(0), + m_maxSharedWords(0), + m_maxConcurrency(0), + m_shmemPerSM(0), + m_maxShmemPerBlock(0), + m_regsPerSM(0), + m_maxBlocksPerSM(0), + m_maxThreadsPerSM(0), + m_maxThreadsPerBlock(0), + m_scratchSpaceCount(0), + m_scratchFlagsCount(0), + m_scratchUnifiedCount(0), + m_scratchFunctorSize(0), + m_scratchUnifiedSupported(0), + m_streamCount(0), + m_scratchSpace(0), + m_scratchFlags(0), + m_scratchUnified(0), + m_scratchFunctor(0), + m_scratchConcurrentBitset(0), + m_stream(0) {} + + size_type* scratch_space(const size_type size) const; + size_type* scratch_flags(const size_type size) const; + size_type* scratch_unified(const size_type size) const; + size_type* scratch_functor(const size_type size) const; }; -} // Namespace Impl -} // Namespace Kokkos +} // Namespace Impl +} // Namespace Kokkos #endif diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_KernelLaunch.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_KernelLaunch.hpp index 2ec868c1f1..590fa7a784 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_KernelLaunch.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_KernelLaunch.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -59,32 +60,32 @@ //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- -#if defined( __CUDACC__ ) +#if defined(__CUDACC__) /** \brief Access to constant memory on the device */ #ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE -__device__ __constant__ -extern unsigned long kokkos_impl_cuda_constant_memory_buffer[] ; +__device__ __constant__ extern unsigned long + kokkos_impl_cuda_constant_memory_buffer[]; #else -__device__ __constant__ -unsigned long kokkos_impl_cuda_constant_memory_buffer[ Kokkos::Impl::CudaTraits::ConstantMemoryUsage / sizeof(unsigned long) ] ; +__device__ __constant__ unsigned long kokkos_impl_cuda_constant_memory_buffer + [Kokkos::Impl::CudaTraits::ConstantMemoryUsage / sizeof(unsigned long)]; #endif namespace Kokkos { namespace Impl { - void* cuda_resize_scratch_space(std::int64_t bytes, bool force_shrink = false); -} +void* cuda_resize_scratch_space(std::int64_t bytes, bool force_shrink = false); } +} // namespace Kokkos -template< typename T > -inline -__device__ -T * kokkos_impl_cuda_shared_memory() -{ extern __shared__ Kokkos::CudaSpace::size_type sh[]; return (T*) sh ; } +template +inline __device__ T* kokkos_impl_cuda_shared_memory() { + extern __shared__ Kokkos::CudaSpace::size_type sh[]; + return (T*)sh; +} namespace Kokkos { namespace Impl { @@ -100,105 +101,111 @@ namespace Impl { // For 2.0 capability: 48 KB L1 and 16 KB shared //---------------------------------------------------------------------------- -template< class DriverType> -__global__ -static void cuda_parallel_launch_constant_memory() -{ - const DriverType & driver = - *((const DriverType *) kokkos_impl_cuda_constant_memory_buffer ); +template +__global__ static void cuda_parallel_launch_constant_memory() { + const DriverType& driver = + *((const DriverType*)kokkos_impl_cuda_constant_memory_buffer); driver(); } -template< class DriverType, unsigned int maxTperB, unsigned int minBperSM > -__global__ -__launch_bounds__(maxTperB, minBperSM) -static void cuda_parallel_launch_constant_memory() -{ - const DriverType & driver = - *((const DriverType *) kokkos_impl_cuda_constant_memory_buffer ); +template +__global__ __launch_bounds__( + maxTperB, minBperSM) static void cuda_parallel_launch_constant_memory() { + const DriverType& driver = + *((const DriverType*)kokkos_impl_cuda_constant_memory_buffer); driver(); } -template< class DriverType> -__global__ -static void cuda_parallel_launch_local_memory( const DriverType driver ) -{ +template +__global__ static void cuda_parallel_launch_local_memory( + const DriverType driver) { driver(); } -template< class DriverType, unsigned int maxTperB, unsigned int minBperSM > -__global__ -__launch_bounds__(maxTperB, minBperSM) -static void cuda_parallel_launch_local_memory( const DriverType driver ) -{ +template +__global__ __launch_bounds__( + maxTperB, + minBperSM) static void cuda_parallel_launch_local_memory(const DriverType + driver) { driver(); } -template< class DriverType> -__global__ -static void cuda_parallel_launch_global_memory( const DriverType* driver ) -{ +template +__global__ static void cuda_parallel_launch_global_memory( + const DriverType* driver) { driver->operator()(); } -template< class DriverType, unsigned int maxTperB, unsigned int minBperSM > -__global__ -__launch_bounds__(maxTperB, minBperSM) -static void cuda_parallel_launch_global_memory( const DriverType* driver ) -{ +template +__global__ __launch_bounds__( + maxTperB, + minBperSM) static void cuda_parallel_launch_global_memory(const DriverType* + driver) { driver->operator()(); } -template< class DriverType> -__global__ -static void cuda_parallel_launch_constant_or_global_memory( const DriverType* driver_ptr ) -{ - const DriverType & driver = driver_ptr!=NULL ? *driver_ptr : - *((const DriverType *) kokkos_impl_cuda_constant_memory_buffer ); +template +__global__ static void cuda_parallel_launch_constant_or_global_memory( + const DriverType* driver_ptr) { + const DriverType& driver = + driver_ptr != NULL + ? *driver_ptr + : *((const DriverType*)kokkos_impl_cuda_constant_memory_buffer); driver(); } -template< class DriverType, unsigned int maxTperB, unsigned int minBperSM > +template __global__ -__launch_bounds__(maxTperB, minBperSM) -static void cuda_parallel_launch_constant_or_global_memory( const DriverType* driver_ptr ) -{ - const DriverType & driver = driver_ptr!=NULL ? *driver_ptr : - *((const DriverType *) kokkos_impl_cuda_constant_memory_buffer ); +__launch_bounds__(maxTperB, minBperSM) static void cuda_parallel_launch_constant_or_global_memory( + const DriverType* driver_ptr) { + const DriverType& driver = + driver_ptr != NULL + ? *driver_ptr + : *((const DriverType*)kokkos_impl_cuda_constant_memory_buffer); driver(); } -template< class DriverType > +template struct DeduceCudaLaunchMechanism { - constexpr static const Kokkos::Experimental::WorkItemProperty::HintLightWeight_t light_weight = Kokkos::Experimental::WorkItemProperty::HintLightWeight; - constexpr static const Kokkos::Experimental::WorkItemProperty::HintHeavyWeight_t heavy_weight = Kokkos::Experimental::WorkItemProperty::HintHeavyWeight ; - constexpr static const typename DriverType::Policy::work_item_property property = typename DriverType::Policy::work_item_property(); - - static constexpr const Experimental::CudaLaunchMechanism valid_launch_mechanism = - // BuildValidMask - (sizeof(DriverType) - , Experimental::CudaLaunchMechanism LaunchMechanism = - DeduceCudaLaunchMechanism::launch_mechanism > -struct CudaParallelLaunch ; - -template < class DriverType - , unsigned int MaxThreadsPerBlock - , unsigned int MinBlocksPerSM> -struct CudaParallelLaunch< DriverType - , Kokkos::LaunchBounds< MaxThreadsPerBlock - , MinBlocksPerSM > - , Experimental::CudaLaunchMechanism::ConstantMemory> -{ - static_assert(sizeof(DriverType), + Experimental::CudaLaunchMechanism LaunchMechanism = + DeduceCudaLaunchMechanism::launch_mechanism> +struct CudaParallelLaunch; + +template +struct CudaParallelLaunch< + DriverType, Kokkos::LaunchBounds, + Experimental::CudaLaunchMechanism::ConstantMemory> { + static_assert(sizeof(DriverType) < CudaTraits::ConstantMemoryUsage, + "Kokkos Error: Requested CudaLaunchConstantMemory with a " + "Functor larger than 32kB."); + inline CudaParallelLaunch(const DriverType& driver, const dim3& grid, + const dim3& block, const int shmem, + const CudaInternal* cuda_instance, + const bool prefer_shmem) { + if ((grid.x != 0) && ((block.x * block.y * block.z) != 0)) { // Fence before changing settings and copying closure Kokkos::Cuda().fence(); - if ( cuda_instance->m_maxShmemPerBlock < shmem ) { - Kokkos::Impl::throw_runtime_exception( std::string("CudaParallelLaunch FAILED: shared memory request is too large") ); + if (cuda_instance->m_maxShmemPerBlock < shmem) { + Kokkos::Impl::throw_runtime_exception(std::string( + "CudaParallelLaunch FAILED: shared memory request is too large")); } - #ifndef KOKKOS_ARCH_KEPLER +#ifndef KOKKOS_ARCH_KEPLER // On Kepler the L1 has no benefit since it doesn't cache reads else { - CUDA_SAFE_CALL( - cudaFuncSetCacheConfig - ( cuda_parallel_launch_constant_memory - < DriverType, MaxThreadsPerBlock, MinBlocksPerSM > - , ( prefer_shmem ? cudaFuncCachePreferShared : cudaFuncCachePreferL1 ) - ) ); + CUDA_SAFE_CALL(cudaFuncSetCacheConfig( + cuda_parallel_launch_constant_memory, + (prefer_shmem ? cudaFuncCachePreferShared + : cudaFuncCachePreferL1))); } - #endif +#endif // Copy functor to constant memory on the device - cudaMemcpyToSymbolAsync( - kokkos_impl_cuda_constant_memory_buffer, &driver, sizeof(DriverType), 0, cudaMemcpyHostToDevice, cudaStream_t(cuda_instance->m_stream)); + cudaMemcpyToSymbolAsync(kokkos_impl_cuda_constant_memory_buffer, &driver, + sizeof(DriverType), 0, cudaMemcpyHostToDevice, + cudaStream_t(cuda_instance->m_stream)); KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE(); // Invoke the driver function on the device - cuda_parallel_launch_constant_memory - < DriverType, MaxThreadsPerBlock, MinBlocksPerSM > - <<< grid , block , shmem , cuda_instance->m_stream >>>(); + cuda_parallel_launch_constant_memory + <<m_stream>>>(); -#if defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK ) - CUDA_SAFE_CALL( cudaGetLastError() ); +#if defined(KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK) + CUDA_SAFE_CALL(cudaGetLastError()); Kokkos::Cuda().fence(); #endif } @@ -283,57 +283,55 @@ struct CudaParallelLaunch< DriverType static cudaFuncAttributes get_cuda_func_attributes() { cudaFuncAttributes attr; - cudaFuncGetAttributes(&attr,cuda_parallel_launch_constant_memory - < DriverType, MaxThreadsPerBlock, MinBlocksPerSM >); + CUDA_SAFE_CALL(cudaFuncGetAttributes( + &attr, + cuda_parallel_launch_constant_memory)); return attr; } }; -template < class DriverType> -struct CudaParallelLaunch< DriverType - , Kokkos::LaunchBounds<0,0> - , Experimental::CudaLaunchMechanism::ConstantMemory > -{ - static_assert(sizeof(DriverType) +struct CudaParallelLaunch, + Experimental::CudaLaunchMechanism::ConstantMemory> { + static_assert(sizeof(DriverType) < CudaTraits::ConstantMemoryUsage, + "Kokkos Error: Requested CudaLaunchConstantMemory with a " + "Functor larger than 32kB."); + inline CudaParallelLaunch(const DriverType& driver, const dim3& grid, + const dim3& block, const int shmem, + const CudaInternal* cuda_instance, + const bool prefer_shmem) { + if ((grid.x != 0) && ((block.x * block.y * block.z) != 0)) { // Fence before changing settings and copying closure Kokkos::Cuda().fence(); - if ( cuda_instance->m_maxShmemPerBlock < shmem ) { - Kokkos::Impl::throw_runtime_exception( std::string("CudaParallelLaunch FAILED: shared memory request is too large") ); + if (cuda_instance->m_maxShmemPerBlock < shmem) { + Kokkos::Impl::throw_runtime_exception(std::string( + "CudaParallelLaunch FAILED: shared memory request is too large")); } - #ifndef KOKKOS_ARCH_KEPLER +#ifndef KOKKOS_ARCH_KEPLER // On Kepler the L1 has no benefit since it doesn't cache reads else { - CUDA_SAFE_CALL( - cudaFuncSetCacheConfig - ( cuda_parallel_launch_constant_memory< DriverType > - , ( prefer_shmem ? cudaFuncCachePreferShared : cudaFuncCachePreferL1 ) - ) ); + CUDA_SAFE_CALL(cudaFuncSetCacheConfig( + cuda_parallel_launch_constant_memory, + (prefer_shmem ? cudaFuncCachePreferShared + : cudaFuncCachePreferL1))); } - #endif +#endif // Copy functor to constant memory on the device - cudaMemcpyToSymbolAsync( - kokkos_impl_cuda_constant_memory_buffer, &driver, sizeof(DriverType), 0, cudaMemcpyHostToDevice, cudaStream_t(cuda_instance->m_stream)); + cudaMemcpyToSymbolAsync(kokkos_impl_cuda_constant_memory_buffer, &driver, + sizeof(DriverType), 0, cudaMemcpyHostToDevice, + cudaStream_t(cuda_instance->m_stream)); KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE(); // Invoke the driver function on the device - cuda_parallel_launch_constant_memory< DriverType > - <<< grid , block , shmem , cuda_instance->m_stream >>>(); + cuda_parallel_launch_constant_memory + <<m_stream>>>(); -#if defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK ) - CUDA_SAFE_CALL( cudaGetLastError() ); +#if defined(KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK) + CUDA_SAFE_CALL(cudaGetLastError()); Kokkos::Cuda().fence(); #endif } @@ -341,55 +339,49 @@ struct CudaParallelLaunch< DriverType static cudaFuncAttributes get_cuda_func_attributes() { cudaFuncAttributes attr; - cudaFuncGetAttributes(&attr,cuda_parallel_launch_constant_memory - < DriverType >); + CUDA_SAFE_CALL(cudaFuncGetAttributes( + &attr, cuda_parallel_launch_constant_memory)); return attr; } }; -template < class DriverType - , unsigned int MaxThreadsPerBlock - , unsigned int MinBlocksPerSM > -struct CudaParallelLaunch< DriverType - , Kokkos::LaunchBounds< MaxThreadsPerBlock - , MinBlocksPerSM > - , Experimental::CudaLaunchMechanism::LocalMemory > -{ - static_assert(sizeof(DriverType)m_maxShmemPerBlock < shmem ) { - Kokkos::Impl::throw_runtime_exception( std::string("CudaParallelLaunch FAILED: shared memory request is too large") ); +template +struct CudaParallelLaunch< + DriverType, Kokkos::LaunchBounds, + Experimental::CudaLaunchMechanism::LocalMemory> { + static_assert(sizeof(DriverType) < CudaTraits::KernelArgumentLimit, + "Kokkos Error: Requested CudaLaunchLocalMemory with a Functor " + "larger than 4096 bytes."); + inline CudaParallelLaunch(const DriverType& driver, const dim3& grid, + const dim3& block, const int shmem, + const CudaInternal* cuda_instance, + const bool prefer_shmem) { + if ((grid.x != 0) && ((block.x * block.y * block.z) != 0)) { + if (cuda_instance->m_maxShmemPerBlock < shmem) { + Kokkos::Impl::throw_runtime_exception(std::string( + "CudaParallelLaunch FAILED: shared memory request is too large")); } - #ifndef KOKKOS_ARCH_KEPLER +#ifndef KOKKOS_ARCH_KEPLER // On Kepler the L1 has no benefit since it doesn't cache reads else { - CUDA_SAFE_CALL( - cudaFuncSetCacheConfig - ( cuda_parallel_launch_local_memory - < DriverType, MaxThreadsPerBlock, MinBlocksPerSM > - , ( prefer_shmem ? cudaFuncCachePreferShared : cudaFuncCachePreferL1 ) - ) ); + CUDA_SAFE_CALL(cudaFuncSetCacheConfig( + cuda_parallel_launch_local_memory, + (prefer_shmem ? cudaFuncCachePreferShared + : cudaFuncCachePreferL1))); } - #endif +#endif KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE(); // Invoke the driver function on the device - cuda_parallel_launch_local_memory - < DriverType, MaxThreadsPerBlock, MinBlocksPerSM > - <<< grid , block , shmem , cuda_instance->m_stream >>>( driver ); + cuda_parallel_launch_local_memory + <<m_stream>>>(driver); -#if defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK ) - CUDA_SAFE_CALL( cudaGetLastError() ); +#if defined(KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK) + CUDA_SAFE_CALL(cudaGetLastError()); Kokkos::Cuda().fence(); #endif } @@ -397,50 +389,46 @@ struct CudaParallelLaunch< DriverType static cudaFuncAttributes get_cuda_func_attributes() { cudaFuncAttributes attr; - cudaFuncGetAttributes(&attr,cuda_parallel_launch_local_memory - < DriverType, MaxThreadsPerBlock, MinBlocksPerSM >); + CUDA_SAFE_CALL(cudaFuncGetAttributes( + &attr, cuda_parallel_launch_local_memory)); return attr; } }; -template < class DriverType> -struct CudaParallelLaunch< DriverType - , Kokkos::LaunchBounds<0,0> - , Experimental::CudaLaunchMechanism::LocalMemory > -{ - static_assert(sizeof(DriverType)m_maxShmemPerBlock < shmem ) { - Kokkos::Impl::throw_runtime_exception( std::string("CudaParallelLaunch FAILED: shared memory request is too large") ); +template +struct CudaParallelLaunch, + Experimental::CudaLaunchMechanism::LocalMemory> { + static_assert(sizeof(DriverType) < CudaTraits::KernelArgumentLimit, + "Kokkos Error: Requested CudaLaunchLocalMemory with a Functor " + "larger than 4096 bytes."); + inline CudaParallelLaunch(const DriverType& driver, const dim3& grid, + const dim3& block, const int shmem, + const CudaInternal* cuda_instance, + const bool prefer_shmem) { + if ((grid.x != 0) && ((block.x * block.y * block.z) != 0)) { + if (cuda_instance->m_maxShmemPerBlock < shmem) { + Kokkos::Impl::throw_runtime_exception(std::string( + "CudaParallelLaunch FAILED: shared memory request is too large")); } - #ifndef KOKKOS_ARCH_KEPLER +#ifndef KOKKOS_ARCH_KEPLER // On Kepler the L1 has no benefit since it doesn't cache reads else { - CUDA_SAFE_CALL( - cudaFuncSetCacheConfig - ( cuda_parallel_launch_local_memory< DriverType > - , ( prefer_shmem ? cudaFuncCachePreferShared : cudaFuncCachePreferL1 ) - ) ); + CUDA_SAFE_CALL(cudaFuncSetCacheConfig( + cuda_parallel_launch_local_memory, + (prefer_shmem ? cudaFuncCachePreferShared + : cudaFuncCachePreferL1))); } - #endif +#endif KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE(); // Invoke the driver function on the device - cuda_parallel_launch_local_memory< DriverType > - <<< grid , block , shmem , cuda_instance->m_stream >>>( driver ); + cuda_parallel_launch_local_memory + <<m_stream>>>(driver); -#if defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK ) - CUDA_SAFE_CALL( cudaGetLastError() ); +#if defined(KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK) + CUDA_SAFE_CALL(cudaGetLastError()); Kokkos::Cuda().fence(); #endif } @@ -448,111 +436,101 @@ struct CudaParallelLaunch< DriverType static cudaFuncAttributes get_cuda_func_attributes() { cudaFuncAttributes attr; - cudaFuncGetAttributes(&attr,cuda_parallel_launch_local_memory - < DriverType >); + CUDA_SAFE_CALL(cudaFuncGetAttributes( + &attr, cuda_parallel_launch_local_memory)); return attr; } }; -template < class DriverType - , unsigned int MaxThreadsPerBlock - , unsigned int MinBlocksPerSM> -struct CudaParallelLaunch< DriverType - , Kokkos::LaunchBounds< MaxThreadsPerBlock - , MinBlocksPerSM> - , Experimental::CudaLaunchMechanism::GlobalMemory > -{ - inline - CudaParallelLaunch( const DriverType & driver - , const dim3 & grid - , const dim3 & block - , const int shmem - , CudaInternal* cuda_instance - , const bool prefer_shmem ) - { - if ( (grid.x != 0) && ( ( block.x * block.y * block.z ) != 0 ) ) { - - if ( cuda_instance->m_maxShmemPerBlock < shmem ) { - Kokkos::Impl::throw_runtime_exception( std::string("CudaParallelLaunch FAILED: shared memory request is too large") ); +template +struct CudaParallelLaunch< + DriverType, Kokkos::LaunchBounds, + Experimental::CudaLaunchMechanism::GlobalMemory> { + inline CudaParallelLaunch(const DriverType& driver, const dim3& grid, + const dim3& block, const int shmem, + CudaInternal* cuda_instance, + const bool prefer_shmem) { + if ((grid.x != 0) && ((block.x * block.y * block.z) != 0)) { + if (cuda_instance->m_maxShmemPerBlock < shmem) { + Kokkos::Impl::throw_runtime_exception(std::string( + "CudaParallelLaunch FAILED: shared memory request is too large")); } - #ifndef KOKKOS_ARCH_KEPLER +#ifndef KOKKOS_ARCH_KEPLER // On Kepler the L1 has no benefit since it doesn't cache reads else { - CUDA_SAFE_CALL( - cudaFuncSetCacheConfig - ( cuda_parallel_launch_global_memory - < DriverType, MaxThreadsPerBlock, MinBlocksPerSM > - , ( prefer_shmem ? cudaFuncCachePreferShared : cudaFuncCachePreferL1 ) - ) ); + CUDA_SAFE_CALL(cudaFuncSetCacheConfig( + cuda_parallel_launch_global_memory, + (prefer_shmem ? cudaFuncCachePreferShared + : cudaFuncCachePreferL1))); } - #endif +#endif KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE(); DriverType* driver_ptr = NULL; - driver_ptr = reinterpret_cast(cuda_instance->scratch_functor(sizeof(DriverType))); - cudaMemcpyAsync(driver_ptr,&driver, sizeof(DriverType), cudaMemcpyDefault, cuda_instance->m_stream); + driver_ptr = reinterpret_cast( + cuda_instance->scratch_functor(sizeof(DriverType))); + cudaMemcpyAsync(driver_ptr, &driver, sizeof(DriverType), + cudaMemcpyDefault, cuda_instance->m_stream); // Invoke the driver function on the device - cuda_parallel_launch_global_memory - < DriverType, MaxThreadsPerBlock, MinBlocksPerSM > - <<< grid , block , shmem , cuda_instance->m_stream >>>( driver_ptr ); + cuda_parallel_launch_global_memory + <<m_stream>>>(driver_ptr); -#if defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK ) - CUDA_SAFE_CALL( cudaGetLastError() ); +#if defined(KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK) + CUDA_SAFE_CALL(cudaGetLastError()); Kokkos::Cuda().fence(); #endif } } static cudaFuncAttributes get_cuda_func_attributes() { cudaFuncAttributes attr; - cudaFuncGetAttributes(&attr,cuda_parallel_launch_global_memory - < DriverType, MaxThreadsPerBlock, MinBlocksPerSM >); + CUDA_SAFE_CALL(cudaFuncGetAttributes( + &attr, + cuda_parallel_launch_global_memory)); return attr; } - }; -template < class DriverType> -struct CudaParallelLaunch< DriverType - , Kokkos::LaunchBounds<0,0> - , Experimental::CudaLaunchMechanism::GlobalMemory > -{ - inline - CudaParallelLaunch( const DriverType & driver - , const dim3 & grid - , const dim3 & block - , const int shmem - , CudaInternal* cuda_instance - , const bool prefer_shmem) - { - if ( (grid.x != 0) && ( ( block.x * block.y * block.z ) != 0 ) ) { - - if ( cuda_instance->m_maxShmemPerBlock < shmem ) { - Kokkos::Impl::throw_runtime_exception( std::string("CudaParallelLaunch FAILED: shared memory request is too large") ); +template +struct CudaParallelLaunch, + Experimental::CudaLaunchMechanism::GlobalMemory> { + inline CudaParallelLaunch(const DriverType& driver, const dim3& grid, + const dim3& block, const int shmem, + CudaInternal* cuda_instance, + const bool prefer_shmem) { + if ((grid.x != 0) && ((block.x * block.y * block.z) != 0)) { + if (cuda_instance->m_maxShmemPerBlock < shmem) { + Kokkos::Impl::throw_runtime_exception(std::string( + "CudaParallelLaunch FAILED: shared memory request is too large")); } - #ifndef KOKKOS_ARCH_KEPLER +#ifndef KOKKOS_ARCH_KEPLER // On Kepler the L1 has no benefit since it doesn't cache reads else { - CUDA_SAFE_CALL( - cudaFuncSetCacheConfig - ( cuda_parallel_launch_global_memory< DriverType > - , ( prefer_shmem ? cudaFuncCachePreferShared : cudaFuncCachePreferL1 ) - ) ); + CUDA_SAFE_CALL(cudaFuncSetCacheConfig( + cuda_parallel_launch_global_memory, + (prefer_shmem ? cudaFuncCachePreferShared + : cudaFuncCachePreferL1))); } - #endif +#endif KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE(); DriverType* driver_ptr = NULL; - driver_ptr = reinterpret_cast(cuda_instance->scratch_functor(sizeof(DriverType))); - cudaMemcpyAsync(driver_ptr,&driver, sizeof(DriverType), cudaMemcpyDefault, cuda_instance->m_stream); + driver_ptr = reinterpret_cast( + cuda_instance->scratch_functor(sizeof(DriverType))); + cudaMemcpyAsync(driver_ptr, &driver, sizeof(DriverType), + cudaMemcpyDefault, cuda_instance->m_stream); - cuda_parallel_launch_global_memory< DriverType > - <<< grid , block , shmem , cuda_instance->m_stream >>>( driver_ptr ); + cuda_parallel_launch_global_memory + <<m_stream>>>(driver_ptr); -#if defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK ) - CUDA_SAFE_CALL( cudaGetLastError() ); +#if defined(KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK) + CUDA_SAFE_CALL(cudaGetLastError()); Kokkos::Cuda().fence(); #endif } @@ -560,15 +538,15 @@ struct CudaParallelLaunch< DriverType static cudaFuncAttributes get_cuda_func_attributes() { cudaFuncAttributes attr; - cudaFuncGetAttributes(&attr,cuda_parallel_launch_global_memory - < DriverType >); + CUDA_SAFE_CALL(cudaFuncGetAttributes( + &attr, cuda_parallel_launch_global_memory)); return attr; } }; //---------------------------------------------------------------------------- -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -576,4 +554,3 @@ struct CudaParallelLaunch< DriverType #endif /* defined( __CUDACC__ ) */ #endif /* defined( KOKKOS_ENABLE_CUDA ) */ #endif /* #ifndef KOKKOS_CUDAEXEC_HPP */ - diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.cpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.cpp index f1828ea2de..07dadb3c16 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.cpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -52,10 +53,10 @@ #ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE namespace Kokkos { namespace Impl { -__device__ __constant__ -CudaLockArrays g_device_cuda_lock_arrays = { nullptr, nullptr, 0 }; -} +__device__ __constant__ CudaLockArrays g_device_cuda_lock_arrays = {nullptr, + nullptr, 0}; } +} // namespace Kokkos #endif namespace Kokkos { @@ -63,36 +64,38 @@ namespace Kokkos { namespace { __global__ void init_lock_array_kernel_atomic() { - unsigned i = blockIdx.x*blockDim.x + threadIdx.x; - if(i>>(); - init_lock_array_kernel_threadid<<<(Kokkos::Cuda::concurrency()+255)/256,256>>>(Kokkos::Cuda::concurrency()); + init_lock_array_kernel_atomic<<<(CUDA_SPACE_ATOMIC_MASK + 1 + 255) / 256, + 256>>>(); + init_lock_array_kernel_threadid<<<(Kokkos::Cuda::concurrency() + 255) / 256, + 256>>>(Kokkos::Cuda::concurrency()); CUDA_SAFE_CALL(cudaDeviceSynchronize()); } @@ -102,15 +105,15 @@ void finalize_host_cuda_lock_arrays() { g_host_cuda_lock_arrays.atomic = nullptr; cudaFree(g_host_cuda_lock_arrays.scratch); g_host_cuda_lock_arrays.scratch = nullptr; - g_host_cuda_lock_arrays.n = 0; + g_host_cuda_lock_arrays.n = 0; #ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE KOKKOS_COPY_CUDA_LOCK_ARRAYS_TO_DEVICE(); #endif } -} // namespace Impl +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos #else diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.hpp index cfc46f0461..84a9c3821e 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -63,7 +64,7 @@ struct CudaLockArrays { /// \brief This global variable in Host space is the central definition /// of these arrays. -extern Kokkos::Impl::CudaLockArrays g_host_cuda_lock_arrays ; +extern Kokkos::Impl::CudaLockArrays g_host_cuda_lock_arrays; /// \brief After this call, the g_host_cuda_lock_arrays variable has /// valid, initialized arrays. @@ -77,10 +78,10 @@ void initialize_host_cuda_lock_arrays(); /// This call is idempotent. void finalize_host_cuda_lock_arrays(); -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos -#if defined( __CUDACC__ ) +#if defined(__CUDACC__) namespace Kokkos { namespace Impl { @@ -106,73 +107,70 @@ namespace Impl { /// That is the purpose of the KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE macro. __device__ #ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE -__constant__ -extern + __constant__ extern #endif -Kokkos::Impl::CudaLockArrays g_device_cuda_lock_arrays ; + Kokkos::Impl::CudaLockArrays g_device_cuda_lock_arrays; #define CUDA_SPACE_ATOMIC_MASK 0x1FFFF -/// \brief Acquire a lock for the address +/// \brief Aquire a lock for the address /// -/// This function tries to acquire the lock for the hash value derived -/// from the provided ptr. If the lock is successfully acquired the +/// This function tries to aquire the lock for the hash value derived +/// from the provided ptr. If the lock is successfully aquired the /// function returns true. Otherwise it returns false. -__device__ inline -bool lock_address_cuda_space(void* ptr) { +__device__ inline bool lock_address_cuda_space(void* ptr) { size_t offset = size_t(ptr); - offset = offset >> 2; - offset = offset & CUDA_SPACE_ATOMIC_MASK; - return (0 == atomicCAS(&Kokkos::Impl::g_device_cuda_lock_arrays.atomic[offset],0,1)); + offset = offset >> 2; + offset = offset & CUDA_SPACE_ATOMIC_MASK; + return ( + 0 == + atomicCAS(&Kokkos::Impl::g_device_cuda_lock_arrays.atomic[offset], 0, 1)); } /// \brief Release lock for the address /// /// This function releases the lock for the hash value derived /// from the provided ptr. This function should only be called -/// after previously successfully acquiring a lock with +/// after previously successfully aquiring a lock with /// lock_address. -__device__ inline -void unlock_address_cuda_space(void* ptr) { +__device__ inline void unlock_address_cuda_space(void* ptr) { size_t offset = size_t(ptr); - offset = offset >> 2; - offset = offset & CUDA_SPACE_ATOMIC_MASK; - atomicExch( &Kokkos::Impl::g_device_cuda_lock_arrays.atomic[ offset ], 0); + offset = offset >> 2; + offset = offset & CUDA_SPACE_ATOMIC_MASK; + atomicExch(&Kokkos::Impl::g_device_cuda_lock_arrays.atomic[offset], 0); } -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos // Make lock_array_copied an explicit translation unit scope thingy namespace Kokkos { namespace Impl { namespace { - static int lock_array_copied = 0; - inline int eliminate_warning_for_lock_array() { - return lock_array_copied; - } -} -} -} +static int lock_array_copied = 0; +inline int eliminate_warning_for_lock_array() { return lock_array_copied; } +} // namespace +} // namespace Impl +} // namespace Kokkos /* Dan Ibanez: it is critical that this code be a macro, so that it will capture the right address for Kokkos::Impl::g_device_cuda_lock_arrays! putting this in an inline function will NOT do the right thing! */ -#define KOKKOS_COPY_CUDA_LOCK_ARRAYS_TO_DEVICE() \ -{ \ - if(::Kokkos::Impl::lock_array_copied == 0) { \ - CUDA_SAFE_CALL(cudaMemcpyToSymbol( \ - Kokkos::Impl::g_device_cuda_lock_arrays , \ - & Kokkos::Impl::g_host_cuda_lock_arrays , \ - sizeof(Kokkos::Impl::CudaLockArrays) ) ); \ - } \ - lock_array_copied = 1; \ - \ -} +#define KOKKOS_COPY_CUDA_LOCK_ARRAYS_TO_DEVICE() \ + { \ + if (::Kokkos::Impl::lock_array_copied == 0) { \ + CUDA_SAFE_CALL( \ + cudaMemcpyToSymbol(Kokkos::Impl::g_device_cuda_lock_arrays, \ + &Kokkos::Impl::g_host_cuda_lock_arrays, \ + sizeof(Kokkos::Impl::CudaLockArrays))); \ + } \ + lock_array_copied = 1; \ + } #ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE #define KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE() #else -#define KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE() KOKKOS_COPY_CUDA_LOCK_ARRAYS_TO_DEVICE() +#define KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE() \ + KOKKOS_COPY_CUDA_LOCK_ARRAYS_TO_DEVICE() #endif #endif /* defined( __CUDACC__ ) */ diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Parallel.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Parallel.hpp index 860d94d6c7..4c5fe4b7f1 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Parallel.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Parallel.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,7 +46,7 @@ #define KOKKOS_CUDA_PARALLEL_HPP #include -#if defined( __CUDACC__ ) && defined( KOKKOS_ENABLE_CUDA ) +#if defined(__CUDACC__) && defined(KOKKOS_ENABLE_CUDA) #include #include @@ -78,202 +79,223 @@ extern bool show_warnings() noexcept; namespace Impl { -template< class ... Properties > -class TeamPolicyInternal< Kokkos::Cuda , Properties ... >: public PolicyTraits -{ -public: - +template +class TeamPolicyInternal + : public PolicyTraits { + public: //! Tag this class as a kokkos execution policy - typedef TeamPolicyInternal execution_policy ; + typedef TeamPolicyInternal execution_policy; - typedef PolicyTraits traits; + typedef PolicyTraits traits; - template< class ExecSpace, class ... OtherProperties > + template friend class TeamPolicyInternal; -private: - + private: enum { MAX_WARP = 8 }; typename traits::execution_space m_space; - int m_league_size ; - int m_team_size ; - int m_vector_length ; - int m_team_scratch_size[2] ; - int m_thread_scratch_size[2] ; + int m_league_size; + int m_team_size; + int m_vector_length; + int m_team_scratch_size[2]; + int m_thread_scratch_size[2]; int m_chunk_size; -public: - + public: //! Execution space of this execution policy - typedef Kokkos::Cuda execution_space ; - - template - TeamPolicyInternal( const TeamPolicyInternal& p ) { - m_league_size = p.m_league_size; - m_team_size = p.m_team_size; - m_vector_length = p.m_vector_length; - m_team_scratch_size[0] = p.m_team_scratch_size[0]; - m_team_scratch_size[1] = p.m_team_scratch_size[1]; + typedef Kokkos::Cuda execution_space; + + template + TeamPolicyInternal(const TeamPolicyInternal& p) { + m_league_size = p.m_league_size; + m_team_size = p.m_team_size; + m_vector_length = p.m_vector_length; + m_team_scratch_size[0] = p.m_team_scratch_size[0]; + m_team_scratch_size[1] = p.m_team_scratch_size[1]; m_thread_scratch_size[0] = p.m_thread_scratch_size[0]; m_thread_scratch_size[1] = p.m_thread_scratch_size[1]; - m_chunk_size = p.m_chunk_size; - m_space = p.m_space; + m_chunk_size = p.m_chunk_size; + m_space = p.m_space; } - TeamPolicyInternal& operator = (const TeamPolicyInternal& p) { - m_league_size = p.m_league_size; - m_team_size = p.m_team_size; - m_vector_length = p.m_vector_length; - m_team_scratch_size[0] = p.m_team_scratch_size[0]; - m_team_scratch_size[1] = p.m_team_scratch_size[1]; + TeamPolicyInternal& operator=(const TeamPolicyInternal& p) { + m_league_size = p.m_league_size; + m_team_size = p.m_team_size; + m_vector_length = p.m_vector_length; + m_team_scratch_size[0] = p.m_team_scratch_size[0]; + m_team_scratch_size[1] = p.m_team_scratch_size[1]; m_thread_scratch_size[0] = p.m_thread_scratch_size[0]; m_thread_scratch_size[1] = p.m_thread_scratch_size[1]; - m_chunk_size = p.m_chunk_size; - m_space = p.m_space; + m_chunk_size = p.m_chunk_size; + m_space = p.m_space; return *this; } //---------------------------------------- #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - template< class FunctorType > - static inline - int team_size_max( const FunctorType & functor ) - { - int n = MAX_WARP * Impl::CudaTraits::WarpSize ; - - for ( ; n ; n >>= 1 ) { - const int shmem_size = - /* for global reduce */ Impl::cuda_single_inter_block_reduce_scan_shmem( functor , n ) - /* for team reduce */ + ( n + 2 ) * sizeof(double) - /* for team shared */ + Impl::FunctorTeamShmemSize< FunctorType >::value( functor , n ); - - if ( shmem_size < typename traits::execution_space().impl_internal_space_instance()->m_maxShmemPerBlock ) break ; - } - - return n ; - } + template + static inline int team_size_max(const FunctorType& functor) { + int n = MAX_WARP * Impl::CudaTraits::WarpSize; + + for (; n; n >>= 1) { + const int shmem_size = + /* for global reduce */ Impl:: + cuda_single_inter_block_reduce_scan_shmem< + false, FunctorType, typename traits::work_tag>(functor, n) + /* for team reduce */ + + (n + 2) * sizeof(double) + /* for team shared */ + + Impl::FunctorTeamShmemSize::value(functor, n); + + if (shmem_size < typename traits::execution_space() + .impl_internal_space_instance() + ->m_maxShmemPerBlock) + break; + } + + return n; + } #endif - template - int team_size_max( const FunctorType& f, const ParallelForTag& ) const { - typedef Impl::ParallelFor< FunctorType , TeamPolicy > closure_type; - cudaFuncAttributes attr = CudaParallelLaunch< closure_type, typename traits::launch_bounds >:: - get_cuda_func_attributes(); - int block_size = Kokkos::Impl::cuda_get_max_block_size< FunctorType, typename traits::launch_bounds >( - space().impl_internal_space_instance(),attr,f ,(size_t) vector_length(), - (size_t) team_scratch_size(0) + 2*sizeof(double), (size_t) thread_scratch_size(0) + sizeof(double) ); - return block_size/vector_length(); - } - - template - int team_size_max( const FunctorType& f, const ParallelReduceTag& ) const { - typedef Impl::FunctorAnalysis functor_analysis_type; - typedef typename Impl::ParallelReduceReturnValue::reducer_type reducer_type; - typedef Impl::ParallelReduce< FunctorType , TeamPolicy, reducer_type > closure_type; - typedef Impl::FunctorValueTraits< FunctorType , typename traits::work_tag > functor_value_traits; - - cudaFuncAttributes attr = CudaParallelLaunch< closure_type, typename traits::launch_bounds >:: - get_cuda_func_attributes(); - int block_size = Kokkos::Impl::cuda_get_max_block_size< FunctorType, typename traits::launch_bounds >( - space().impl_internal_space_instance(),attr,f ,(size_t) vector_length(), - (size_t) team_scratch_size(0) + 2*sizeof(double), (size_t) thread_scratch_size(0) + sizeof(double) + - ((functor_value_traits::StaticValueSize!=0)?0:functor_value_traits::value_size( f ))); + template + int team_size_max(const FunctorType& f, const ParallelForTag&) const { + typedef Impl::ParallelFor> + closure_type; + cudaFuncAttributes attr = + CudaParallelLaunch:: + get_cuda_func_attributes(); + int block_size = + Kokkos::Impl::cuda_get_max_block_size( + space().impl_internal_space_instance(), attr, f, + (size_t)vector_length(), + (size_t)team_scratch_size(0) + 2 * sizeof(double), + (size_t)thread_scratch_size(0) + sizeof(double)); + return block_size / vector_length(); + } - // Currently we require Power-of-2 team size for reductions. - int p2 = 1; - while(p2<=block_size) p2*=2; - p2/=2; - return p2/vector_length(); + template + inline int team_size_max(const FunctorType& f, + const ParallelReduceTag&) const { + typedef Impl::FunctorAnalysis + functor_analysis_type; + typedef typename Impl::ParallelReduceReturnValue< + void, typename functor_analysis_type::value_type, + FunctorType>::reducer_type reducer_type; + typedef Impl::ParallelReduce, + reducer_type> + closure_type; + return internal_team_size_max(f); + } + + template + inline int team_size_max(const FunctorType& f, const ReducerType& r, + const ParallelReduceTag&) const { + using closure_type = + Impl::ParallelReduce, + ReducerType>; + return internal_team_size_max(f); } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - template< class FunctorType > - static int team_size_recommended( const FunctorType & functor ) - { return team_size_max( functor ); } + template + static int team_size_recommended(const FunctorType& functor) { + return team_size_max(functor); + } - template< class FunctorType > - static int team_size_recommended( const FunctorType & functor , const int vector_length) - { - int max = team_size_max( functor )/vector_length; - if(max<1) max = 1; - return max; - } + template + static int team_size_recommended(const FunctorType& functor, + const int vector_length) { + int max = team_size_max(functor) / vector_length; + if (max < 1) max = 1; + return max; + } #endif - template - int team_size_recommended( const FunctorType& f, const ParallelForTag& ) const { - typedef Impl::ParallelFor< FunctorType , TeamPolicy > closure_type; - cudaFuncAttributes attr = CudaParallelLaunch< closure_type, typename traits::launch_bounds >:: - get_cuda_func_attributes(); - const int block_size = Kokkos::Impl::cuda_get_opt_block_size< FunctorType, typename traits::launch_bounds>( - space().impl_internal_space_instance(), - attr, f , (size_t) vector_length(), - (size_t) team_scratch_size(0) + 2*sizeof(double), (size_t) thread_scratch_size(0) + sizeof(double)); - return block_size/vector_length(); - } - - template - int team_size_recommended( const FunctorType& f, const ParallelReduceTag& ) const { - typedef Impl::FunctorAnalysis functor_analysis_type; - typedef typename Impl::ParallelReduceReturnValue::reducer_type reducer_type; - typedef Impl::ParallelReduce< FunctorType , TeamPolicy, reducer_type > closure_type; - typedef Impl::FunctorValueTraits< FunctorType , typename traits::work_tag > functor_value_traits; - - cudaFuncAttributes attr = CudaParallelLaunch< closure_type, typename traits::launch_bounds >:: - get_cuda_func_attributes(); - const int block_size = Kokkos::Impl::cuda_get_opt_block_size< FunctorType, typename traits::launch_bounds>( - space().impl_internal_space_instance(), - attr, f , (size_t) vector_length(), - (size_t) team_scratch_size(0) + 2*sizeof(double), (size_t) thread_scratch_size(0) + sizeof(double) + - ((functor_value_traits::StaticValueSize!=0)?0:functor_value_traits::value_size( f ))); - // Currently we require Power-of-2 team size for reductions. - int p2 = 1; - while(p2<=block_size) p2*=2; - p2/=2; - return p2/vector_length(); + template + int team_size_recommended(const FunctorType& f, const ParallelForTag&) const { + typedef Impl::ParallelFor> + closure_type; + cudaFuncAttributes attr = + CudaParallelLaunch:: + get_cuda_func_attributes(); + const int block_size = + Kokkos::Impl::cuda_get_opt_block_size( + space().impl_internal_space_instance(), attr, f, + (size_t)vector_length(), + (size_t)team_scratch_size(0) + 2 * sizeof(double), + (size_t)thread_scratch_size(0) + sizeof(double)); + return block_size / vector_length(); } + template + inline int team_size_recommended(const FunctorType& f, + const ParallelReduceTag&) const { + typedef Impl::FunctorAnalysis + functor_analysis_type; + typedef typename Impl::ParallelReduceReturnValue< + void, typename functor_analysis_type::value_type, + FunctorType>::reducer_type reducer_type; + typedef Impl::ParallelReduce, + reducer_type> + closure_type; + return internal_team_size_recommended(f); + } - inline static - int vector_length_max() - { return Impl::CudaTraits::WarpSize; } + template + int team_size_recommended(const FunctorType& f, const ReducerType&, + const ParallelReduceTag&) const { + typedef Impl::ParallelReduce, + ReducerType> + closure_type; + return internal_team_size_recommended(f); + } - inline static - int verify_requested_vector_length( int requested_vector_length ) { - int test_vector_length = std::min( requested_vector_length, vector_length_max() ); + inline static int vector_length_max() { return Impl::CudaTraits::WarpSize; } - // Allow only power-of-two vector_length - if ( !(is_integral_power_of_two( test_vector_length ) ) ) { - int test_pow2 = 1; - for (int i = 0; i < 5; i++) { - test_pow2 = test_pow2 << 1; - if (test_pow2 > test_vector_length) { - break; - } - } - test_vector_length = test_pow2 >> 1; + inline static int verify_requested_vector_length( + int requested_vector_length) { + int test_vector_length = + std::min(requested_vector_length, vector_length_max()); + + // Allow only power-of-two vector_length + if (!(is_integral_power_of_two(test_vector_length))) { + int test_pow2 = 1; + for (int i = 0; i < 5; i++) { + test_pow2 = test_pow2 << 1; + if (test_pow2 > test_vector_length) { + break; + } } + test_vector_length = test_pow2 >> 1; + } - return test_vector_length; + return test_vector_length; } - inline static - int scratch_size_max(int level) - { return (level==0? - 1024*40: // 48kB is the max for CUDA, but we need some for team_member.reduce etc. - 20*1024*1024); // arbitrarily setting this to 20MB, for a Volta V100 that would give us about 3.2GB for 2 teams per SM - } + inline static int scratch_size_max(int level) { + return ( + level == 0 ? 1024 * 40 : // 48kB is the max for CUDA, but we need some + // for team_member.reduce etc. + 20 * 1024 * + 1024); // arbitrarily setting this to 20MB, for a Volta V100 + // that would give us about 3.2GB for 2 teams per SM + } //---------------------------------------- - inline int vector_length() const { return m_vector_length ; } - inline int team_size() const { return m_team_size ; } - inline int league_size() const { return m_league_size ; } + inline int vector_length() const { return m_vector_length; } + inline int team_size() const { return m_team_size; } + inline int league_size() const { return m_league_size; } inline int scratch_size(int level, int team_size_ = -1) const { - if(team_size_<0) team_size_ = m_team_size; - return m_team_scratch_size[level] + team_size_*m_thread_scratch_size[level]; + if (team_size_ < 0) team_size_ = m_team_size; + return m_team_scratch_size[level] + + team_size_ * m_thread_scratch_size[level]; } inline int team_scratch_size(int level) const { return m_team_scratch_size[level]; @@ -282,189 +304,259 @@ public: return m_thread_scratch_size[level]; } - inline typename traits::execution_space space() const { - return m_space; - } + inline typename traits::execution_space space() const { return m_space; } TeamPolicyInternal() - : m_space(typename traits::execution_space()) - , m_league_size( 0 ) - , m_team_size( -1 ) - , m_vector_length( 0 ) - , m_team_scratch_size {0,0} - , m_thread_scratch_size {0,0} - , m_chunk_size ( 32 ) - {} + : m_space(typename traits::execution_space()), + m_league_size(0), + m_team_size(-1), + m_vector_length(0), + m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, + m_chunk_size(32) {} /** \brief Specify league size, request team size */ - TeamPolicyInternal( const execution_space space_ - , int league_size_ - , int team_size_request - , int vector_length_request = 1 ) - : m_space( space_ ) - , m_league_size( league_size_ ) - , m_team_size( team_size_request ) - , m_vector_length( verify_requested_vector_length(vector_length_request) ) - , m_team_scratch_size {0,0} - , m_thread_scratch_size {0,0} - , m_chunk_size ( 32 ) - { - // Make sure league size is permissible - if(league_size_ >= int(Impl::cuda_internal_maximum_grid_count())) - Impl::throw_runtime_exception( "Requested too large league_size for TeamPolicy on Cuda execution space."); - - // Make sure total block size is permissible - if ( m_team_size * m_vector_length > 1024 ) { - Impl::throw_runtime_exception(std::string("Kokkos::TeamPolicy< Cuda > the team size is too large. Team size x vector length must be smaller than 1024.")); - } + TeamPolicyInternal(const execution_space space_, int league_size_, + int team_size_request, int vector_length_request = 1) + : m_space(space_), + m_league_size(league_size_), + m_team_size(team_size_request), + m_vector_length(verify_requested_vector_length(vector_length_request)), + m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, + m_chunk_size(32) { + // Make sure league size is permissable + if (league_size_ >= int(Impl::cuda_internal_maximum_grid_count())) + Impl::throw_runtime_exception( + "Requested too large league_size for TeamPolicy on Cuda execution " + "space."); + + // Make sure total block size is permissable + if (m_team_size * m_vector_length > 1024) { + Impl::throw_runtime_exception( + std::string("Kokkos::TeamPolicy< Cuda > the team size is too large. " + "Team size x vector length must be smaller than 1024.")); } + } /** \brief Specify league size, request team size */ - TeamPolicyInternal( const execution_space space_ - , int league_size_ - , const Kokkos::AUTO_t & /* team_size_request */ - , int vector_length_request = 1 ) - : m_space( space_ ) - , m_league_size( league_size_ ) - , m_team_size( -1 ) - , m_vector_length( verify_requested_vector_length(vector_length_request) ) - , m_team_scratch_size {0,0} - , m_thread_scratch_size {0,0} - , m_chunk_size ( 32 ) - { - // Make sure league size is permissible - if(league_size_ >= int(Impl::cuda_internal_maximum_grid_count())) - Impl::throw_runtime_exception( "Requested too large league_size for TeamPolicy on Cuda execution space."); - } - - TeamPolicyInternal( int league_size_ - , int team_size_request - , int vector_length_request = 1 ) - : m_space( typename traits::execution_space() ) - , m_league_size( league_size_ ) - , m_team_size( team_size_request ) - , m_vector_length ( verify_requested_vector_length(vector_length_request) ) - , m_team_scratch_size {0,0} - , m_thread_scratch_size {0,0} - , m_chunk_size ( 32 ) - { - // Make sure league size is permissible - if(league_size_ >= int(Impl::cuda_internal_maximum_grid_count())) - Impl::throw_runtime_exception( "Requested too large league_size for TeamPolicy on Cuda execution space."); + TeamPolicyInternal(const execution_space space_, int league_size_, + const Kokkos::AUTO_t& /* team_size_request */ + , + int vector_length_request = 1) + : m_space(space_), + m_league_size(league_size_), + m_team_size(-1), + m_vector_length(verify_requested_vector_length(vector_length_request)), + m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, + m_chunk_size(32) { + // Make sure league size is permissable + if (league_size_ >= int(Impl::cuda_internal_maximum_grid_count())) + Impl::throw_runtime_exception( + "Requested too large league_size for TeamPolicy on Cuda execution " + "space."); + } - // Make sure total block size is permissible - if ( m_team_size * m_vector_length > 1024 ) { - Impl::throw_runtime_exception(std::string("Kokkos::TeamPolicy< Cuda > the team size is too large. Team size x vector length must be smaller than 1024.")); - } + TeamPolicyInternal(int league_size_, int team_size_request, + int vector_length_request = 1) + : m_space(typename traits::execution_space()), + m_league_size(league_size_), + m_team_size(team_size_request), + m_vector_length(verify_requested_vector_length(vector_length_request)), + m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, + m_chunk_size(32) { + // Make sure league size is permissable + if (league_size_ >= int(Impl::cuda_internal_maximum_grid_count())) + Impl::throw_runtime_exception( + "Requested too large league_size for TeamPolicy on Cuda execution " + "space."); + + // Make sure total block size is permissable + if (m_team_size * m_vector_length > 1024) { + Impl::throw_runtime_exception( + std::string("Kokkos::TeamPolicy< Cuda > the team size is too large. " + "Team size x vector length must be smaller than 1024.")); } + } - TeamPolicyInternal( int league_size_ - , const Kokkos::AUTO_t & /* team_size_request */ - , int vector_length_request = 1 ) - : m_space( typename traits::execution_space() ) - , m_league_size( league_size_ ) - , m_team_size( -1 ) - , m_vector_length ( verify_requested_vector_length(vector_length_request) ) - , m_team_scratch_size {0,0} - , m_thread_scratch_size {0,0} - , m_chunk_size ( 32 ) - { - // Make sure league size is permissible - if(league_size_ >= int(Impl::cuda_internal_maximum_grid_count())) - Impl::throw_runtime_exception( "Requested too large league_size for TeamPolicy on Cuda execution space."); - } + TeamPolicyInternal(int league_size_, + const Kokkos::AUTO_t& /* team_size_request */ + , + int vector_length_request = 1) + : m_space(typename traits::execution_space()), + m_league_size(league_size_), + m_team_size(-1), + m_vector_length(verify_requested_vector_length(vector_length_request)), + m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, + m_chunk_size(32) { + // Make sure league size is permissable + if (league_size_ >= int(Impl::cuda_internal_maximum_grid_count())) + Impl::throw_runtime_exception( + "Requested too large league_size for TeamPolicy on Cuda execution " + "space."); + } - inline int chunk_size() const { return m_chunk_size ; } + inline int chunk_size() const { return m_chunk_size; } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE /** \brief set chunk_size to a discrete value*/ - inline TeamPolicyInternal set_chunk_size(typename traits::index_type chunk_size_) const { + inline TeamPolicyInternal set_chunk_size( + typename traits::index_type chunk_size_) const { TeamPolicyInternal p = *this; - p.m_chunk_size = chunk_size_; + p.m_chunk_size = chunk_size_; return p; } - /** \brief set per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal set_scratch_size(const int& level, const PerTeamValue& per_team) const { - TeamPolicyInternal p = *this; + /** \brief set per team scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal set_scratch_size( + const int& level, const PerTeamValue& per_team) const { + TeamPolicyInternal p = *this; p.m_team_scratch_size[level] = per_team.value; return p; }; - /** \brief set per thread scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal set_scratch_size(const int& level, const PerThreadValue& per_thread) const { - TeamPolicyInternal p = *this; + /** \brief set per thread scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal set_scratch_size( + const int& level, const PerThreadValue& per_thread) const { + TeamPolicyInternal p = *this; p.m_thread_scratch_size[level] = per_thread.value; return p; }; - /** \brief set per thread and per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal set_scratch_size(const int& level, const PerTeamValue& per_team, const PerThreadValue& per_thread) const { - TeamPolicyInternal p = *this; - p.m_team_scratch_size[level] = per_team.value; + /** \brief set per thread and per team scratch size for a specific level of + * the scratch hierarchy */ + inline TeamPolicyInternal set_scratch_size( + const int& level, const PerTeamValue& per_team, + const PerThreadValue& per_thread) const { + TeamPolicyInternal p = *this; + p.m_team_scratch_size[level] = per_team.value; p.m_thread_scratch_size[level] = per_thread.value; return p; }; #else /** \brief set chunk_size to a discrete value*/ - inline TeamPolicyInternal& set_chunk_size(typename traits::index_type chunk_size_) { + inline TeamPolicyInternal& set_chunk_size( + typename traits::index_type chunk_size_) { m_chunk_size = chunk_size_; return *this; } - /** \brief set per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal& set_scratch_size(const int& level, const PerTeamValue& per_team) { + /** \brief set per team scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal& set_scratch_size(const int& level, + const PerTeamValue& per_team) { m_team_scratch_size[level] = per_team.value; return *this; } - /** \brief set per thread scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal& set_scratch_size(const int& level, const PerThreadValue& per_thread) { + /** \brief set per thread scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal& set_scratch_size( + const int& level, const PerThreadValue& per_thread) { m_thread_scratch_size[level] = per_thread.value; return *this; } - /** \brief set per thread and per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal& set_scratch_size(const int& level, const PerTeamValue& per_team, const PerThreadValue& per_thread) { - m_team_scratch_size[level] = per_team.value; + /** \brief set per thread and per team scratch size for a specific level of + * the scratch hierarchy */ + inline TeamPolicyInternal& set_scratch_size( + const int& level, const PerTeamValue& per_team, + const PerThreadValue& per_thread) { + m_team_scratch_size[level] = per_team.value; m_thread_scratch_size[level] = per_thread.value; return *this; } #endif - typedef Kokkos::Impl::CudaTeamMember member_type ; + typedef Kokkos::Impl::CudaTeamMember member_type; -protected: + protected: #ifdef KOKKOS_ENABLE_DEPRECATED_CODE /** \brief set chunk_size to a discrete value*/ - inline TeamPolicyInternal internal_set_chunk_size(typename traits::index_type chunk_size_) { + inline TeamPolicyInternal internal_set_chunk_size( + typename traits::index_type chunk_size_) { m_chunk_size = chunk_size_; return *this; } - /** \brief set per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal internal_set_scratch_size(const int& level, const PerTeamValue& per_team) { + /** \brief set per team scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal internal_set_scratch_size( + const int& level, const PerTeamValue& per_team) { m_team_scratch_size[level] = per_team.value; return *this; } - /** \brief set per thread scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal internal_set_scratch_size(const int& level, const PerThreadValue& per_thread) { + /** \brief set per thread scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal internal_set_scratch_size( + const int& level, const PerThreadValue& per_thread) { m_thread_scratch_size[level] = per_thread.value; return *this; } - /** \brief set per thread and per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal internal_set_scratch_size(const int& level, const PerTeamValue& per_team, const PerThreadValue& per_thread) { - m_team_scratch_size[level] = per_team.value; + /** \brief set per thread and per team scratch size for a specific level of + * the scratch hierarchy */ + inline TeamPolicyInternal internal_set_scratch_size( + const int& level, const PerTeamValue& per_team, + const PerThreadValue& per_thread) { + m_team_scratch_size[level] = per_team.value; m_thread_scratch_size[level] = per_thread.value; return *this; } #endif + + template + int internal_team_size_common(const FunctorType& f, + BlockSizeCallable&& block_size_callable) const { + using closure_type = ClosureType; + using functor_value_traits = + Impl::FunctorValueTraits; + + cudaFuncAttributes attr = + CudaParallelLaunch:: + get_cuda_func_attributes(); + const int block_size = std::forward(block_size_callable)( + space().impl_internal_space_instance(), attr, f, + (size_t)vector_length(), + (size_t)team_scratch_size(0) + 2 * sizeof(double), + (size_t)thread_scratch_size(0) + sizeof(double) + + ((functor_value_traits::StaticValueSize != 0) + ? 0 + : functor_value_traits::value_size(f))); + KOKKOS_ASSERT(block_size > 0); + + // Currently we require Power-of-2 team size for reductions. + int p2 = 1; + while (p2 <= block_size) p2 *= 2; + p2 /= 2; + return p2 / vector_length(); + } + + template + int internal_team_size_max(const FunctorType& f) const { + return internal_team_size_common( + f, + Kokkos::Impl::cuda_get_max_block_size); + } + + template + int internal_team_size_recommended(const FunctorType& f) const { + return internal_team_size_common( + f, + Kokkos::Impl::cuda_get_opt_block_size); + } }; -} // namspace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -472,262 +564,268 @@ protected: namespace Kokkos { namespace Impl { -template< class FunctorType , class ... Traits > -class ParallelFor< FunctorType - , Kokkos::RangePolicy< Traits ... > - , Kokkos::Cuda - > -{ -public: - typedef Kokkos::RangePolicy< Traits ... > Policy; -private: +template +class ParallelFor, Kokkos::Cuda> { + public: + typedef Kokkos::RangePolicy Policy; - typedef typename Policy::member_type Member ; - typedef typename Policy::work_tag WorkTag ; - typedef typename Policy::launch_bounds LaunchBounds ; + private: + typedef typename Policy::member_type Member; + typedef typename Policy::work_tag WorkTag; + typedef typename Policy::launch_bounds LaunchBounds; - const FunctorType m_functor ; - const Policy m_policy ; + const FunctorType m_functor; + const Policy m_policy; - ParallelFor() = delete ; - ParallelFor & operator = ( const ParallelFor & ) = delete ; + ParallelFor() = delete; + ParallelFor& operator=(const ParallelFor&) = delete; - template< class TagType > + template inline __device__ - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec_range( const Member i ) const - { m_functor( i ); } + typename std::enable_if::value>::type + exec_range(const Member i) const { + m_functor(i); + } - template< class TagType > + template inline __device__ - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec_range( const Member i ) const - { m_functor( TagType() , i ); } + typename std::enable_if::value>::type + exec_range(const Member i) const { + m_functor(TagType(), i); + } -public: + public: + typedef FunctorType functor_type; - typedef FunctorType functor_type ; + inline __device__ void operator()(void) const { + const Member work_stride = blockDim.y * gridDim.x; + const Member work_end = m_policy.end(); - inline - __device__ - void operator()(void) const - { - const Member work_stride = blockDim.y * gridDim.x ; - const Member work_end = m_policy.end(); - - for ( Member - iwork = m_policy.begin() + threadIdx.y + blockDim.y * blockIdx.x ; - iwork < work_end ; - iwork = iwork < work_end - work_stride ? iwork + work_stride : work_end) { - this-> template exec_range< WorkTag >( iwork ); - } + for (Member iwork = + m_policy.begin() + threadIdx.y + blockDim.y * blockIdx.x; + iwork < work_end; + iwork = iwork < work_end - work_stride ? iwork + work_stride + : work_end) { + this->template exec_range(iwork); } + } - inline - void execute() const - { - const typename Policy::index_type nwork = m_policy.end() - m_policy.begin(); - - cudaFuncAttributes attr = CudaParallelLaunch< ParallelFor, LaunchBounds >:: - get_cuda_func_attributes(); - const int block_size = Kokkos::Impl::cuda_get_opt_block_size< FunctorType, LaunchBounds>( - m_policy.space().impl_internal_space_instance(), - attr, m_functor , 1, 0 , 0 ); - const dim3 block( 1 , block_size , 1); - const dim3 grid( std::min( typename Policy::index_type(( nwork + block.y - 1 ) / block.y) , - typename Policy::index_type(cuda_internal_maximum_grid_count()) ) , 1 , 1); - - CudaParallelLaunch< ParallelFor, LaunchBounds >( *this , grid , block , 0 , m_policy.space().impl_internal_space_instance() , false ); + inline void execute() const { + const typename Policy::index_type nwork = m_policy.end() - m_policy.begin(); + + cudaFuncAttributes attr = + CudaParallelLaunch::get_cuda_func_attributes(); + const int block_size = + Kokkos::Impl::cuda_get_opt_block_size( + m_policy.space().impl_internal_space_instance(), attr, m_functor, 1, + 0, 0); + dim3 block(1, block_size, 1); + dim3 grid( + std::min( + typename Policy::index_type((nwork + block.y - 1) / block.y), + typename Policy::index_type(cuda_internal_maximum_grid_count())), + 1, 1); +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + if (Kokkos::Impl::CudaInternal::cuda_use_serial_execution()) { + block = dim3(1, 1, 1); + grid = dim3(1, 1, 1); } +#endif - ParallelFor( const FunctorType & arg_functor , - const Policy & arg_policy ) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - { } + CudaParallelLaunch( + *this, grid, block, 0, m_policy.space().impl_internal_space_instance(), + false); + } + ParallelFor(const FunctorType& arg_functor, const Policy& arg_policy) + : m_functor(arg_functor), m_policy(arg_policy) {} }; - // MDRangePolicy impl -template< class FunctorType , class ... Traits > -class ParallelFor< FunctorType - , Kokkos::MDRangePolicy< Traits ... > - , Kokkos::Cuda - > -{ -public: - typedef Kokkos::MDRangePolicy< Traits ... > Policy ; -private: +template +class ParallelFor, Kokkos::Cuda> { + public: + typedef Kokkos::MDRangePolicy Policy; + + private: using RP = Policy; typedef typename Policy::array_index_type array_index_type; typedef typename Policy::index_type index_type; typedef typename Policy::launch_bounds LaunchBounds; + const FunctorType m_functor; + const Policy m_rp; - const FunctorType m_functor ; - const Policy m_rp ; - -public: - - inline - __device__ - void operator()(void) const - { - Kokkos::Impl::Refactor::DeviceIterateTile(m_rp,m_functor).exec_range(); - } - + public: + inline __device__ void operator()(void) const { + Kokkos::Impl::Refactor::DeviceIterateTile( + m_rp, m_functor) + .exec_range(); + } - inline - void execute() const - { - if(m_rp.m_num_tiles==0) return; - const array_index_type maxblocks = static_cast(m_rp.space().impl_internal_space_instance()->m_maxBlock); - if ( RP::rank == 2 ) - { - const dim3 block( m_rp.m_tile[0] , m_rp.m_tile[1] , 1); + inline void execute() const { + if (m_rp.m_num_tiles == 0) return; + const array_index_type maxblocks = static_cast( + m_rp.space().impl_internal_space_instance()->m_maxBlock); + if (RP::rank == 2) { + const dim3 block(m_rp.m_tile[0], m_rp.m_tile[1], 1); const dim3 grid( - std::min( ( m_rp.m_upper[0] - m_rp.m_lower[0] + block.x - 1 ) / block.x , maxblocks ) - , std::min( ( m_rp.m_upper[1] - m_rp.m_lower[1] + block.y - 1 ) / block.y , maxblocks ) - , 1 - ); - CudaParallelLaunch< ParallelFor, LaunchBounds >( *this , grid , block , 0 , m_rp.space().impl_internal_space_instance() , false ); - } - else if ( RP::rank == 3 ) - { - const dim3 block( m_rp.m_tile[0] , m_rp.m_tile[1] , m_rp.m_tile[2] ); + std::min((m_rp.m_upper[0] - m_rp.m_lower[0] + block.x - 1) / block.x, + maxblocks), + std::min((m_rp.m_upper[1] - m_rp.m_lower[1] + block.y - 1) / block.y, + maxblocks), + 1); + CudaParallelLaunch( + *this, grid, block, 0, m_rp.space().impl_internal_space_instance(), + false); + } else if (RP::rank == 3) { + const dim3 block(m_rp.m_tile[0], m_rp.m_tile[1], m_rp.m_tile[2]); const dim3 grid( - std::min( ( m_rp.m_upper[0] - m_rp.m_lower[0] + block.x - 1 ) / block.x , maxblocks ) - , std::min( ( m_rp.m_upper[1] - m_rp.m_lower[1] + block.y - 1 ) / block.y , maxblocks ) - , std::min( ( m_rp.m_upper[2] - m_rp.m_lower[2] + block.z - 1 ) / block.z , maxblocks ) - ); - CudaParallelLaunch< ParallelFor, LaunchBounds >( *this , grid , block , 0 , m_rp.space().impl_internal_space_instance() , false ); - } - else if ( RP::rank == 4 ) - { - // id0,id1 encoded within threadIdx.x; id2 to threadIdx.y; id3 to threadIdx.z - const dim3 block( m_rp.m_tile[0]*m_rp.m_tile[1] , m_rp.m_tile[2] , m_rp.m_tile[3] ); + std::min((m_rp.m_upper[0] - m_rp.m_lower[0] + block.x - 1) / block.x, + maxblocks), + std::min((m_rp.m_upper[1] - m_rp.m_lower[1] + block.y - 1) / block.y, + maxblocks), + std::min((m_rp.m_upper[2] - m_rp.m_lower[2] + block.z - 1) / block.z, + maxblocks)); + CudaParallelLaunch( + *this, grid, block, 0, m_rp.space().impl_internal_space_instance(), + false); + } else if (RP::rank == 4) { + // id0,id1 encoded within threadIdx.x; id2 to threadIdx.y; id3 to + // threadIdx.z + const dim3 block(m_rp.m_tile[0] * m_rp.m_tile[1], m_rp.m_tile[2], + m_rp.m_tile[3]); const dim3 grid( - std::min( static_cast( m_rp.m_tile_end[0] * m_rp.m_tile_end[1] ) - , static_cast(maxblocks) ) - , std::min( ( m_rp.m_upper[2] - m_rp.m_lower[2] + block.y - 1 ) / block.y , maxblocks ) - , std::min( ( m_rp.m_upper[3] - m_rp.m_lower[3] + block.z - 1 ) / block.z , maxblocks ) - ); - CudaParallelLaunch< ParallelFor, LaunchBounds >( *this , grid , block , 0 , m_rp.space().impl_internal_space_instance() , false ); - } - else if ( RP::rank == 5 ) - { - // id0,id1 encoded within threadIdx.x; id2,id3 to threadIdx.y; id4 to threadIdx.z - const dim3 block( m_rp.m_tile[0]*m_rp.m_tile[1] , m_rp.m_tile[2]*m_rp.m_tile[3] , m_rp.m_tile[4] ); + std::min( + static_cast(m_rp.m_tile_end[0] * m_rp.m_tile_end[1]), + static_cast(maxblocks)), + std::min((m_rp.m_upper[2] - m_rp.m_lower[2] + block.y - 1) / block.y, + maxblocks), + std::min((m_rp.m_upper[3] - m_rp.m_lower[3] + block.z - 1) / block.z, + maxblocks)); + CudaParallelLaunch( + *this, grid, block, 0, m_rp.space().impl_internal_space_instance(), + false); + } else if (RP::rank == 5) { + // id0,id1 encoded within threadIdx.x; id2,id3 to threadIdx.y; id4 to + // threadIdx.z + const dim3 block(m_rp.m_tile[0] * m_rp.m_tile[1], + m_rp.m_tile[2] * m_rp.m_tile[3], m_rp.m_tile[4]); const dim3 grid( - std::min( static_cast( m_rp.m_tile_end[0] * m_rp.m_tile_end[1] ) - , static_cast(maxblocks) ) - , std::min( static_cast( m_rp.m_tile_end[2] * m_rp.m_tile_end[3] ) - , static_cast(maxblocks) ) - , std::min( ( m_rp.m_upper[4] - m_rp.m_lower[4] + block.z - 1 ) / block.z , maxblocks ) - ); - CudaParallelLaunch< ParallelFor, LaunchBounds >( *this , grid , block , 0 , m_rp.space().impl_internal_space_instance() , false ); - } - else if ( RP::rank == 6 ) - { - // id0,id1 encoded within threadIdx.x; id2,id3 to threadIdx.y; id4,id5 to threadIdx.z - const dim3 block( m_rp.m_tile[0]*m_rp.m_tile[1] , m_rp.m_tile[2]*m_rp.m_tile[3] , m_rp.m_tile[4]*m_rp.m_tile[5] ); + std::min( + static_cast(m_rp.m_tile_end[0] * m_rp.m_tile_end[1]), + static_cast(maxblocks)), + std::min( + static_cast(m_rp.m_tile_end[2] * m_rp.m_tile_end[3]), + static_cast(maxblocks)), + std::min((m_rp.m_upper[4] - m_rp.m_lower[4] + block.z - 1) / block.z, + maxblocks)); + CudaParallelLaunch( + *this, grid, block, 0, m_rp.space().impl_internal_space_instance(), + false); + } else if (RP::rank == 6) { + // id0,id1 encoded within threadIdx.x; id2,id3 to threadIdx.y; id4,id5 to + // threadIdx.z + const dim3 block(m_rp.m_tile[0] * m_rp.m_tile[1], + m_rp.m_tile[2] * m_rp.m_tile[3], + m_rp.m_tile[4] * m_rp.m_tile[5]); const dim3 grid( - std::min( static_cast( m_rp.m_tile_end[0] * m_rp.m_tile_end[1] ) - , static_cast(maxblocks) ) - , std::min( static_cast( m_rp.m_tile_end[2] * m_rp.m_tile_end[3] ) - , static_cast(maxblocks) ) - , std::min( static_cast( m_rp.m_tile_end[4] * m_rp.m_tile_end[5] ) - , static_cast(maxblocks) ) - ); - CudaParallelLaunch< ParallelFor, LaunchBounds >( *this , grid , block , 0 , m_rp.space().impl_internal_space_instance() , false ); - } - else - { + std::min( + static_cast(m_rp.m_tile_end[0] * m_rp.m_tile_end[1]), + static_cast(maxblocks)), + std::min( + static_cast(m_rp.m_tile_end[2] * m_rp.m_tile_end[3]), + static_cast(maxblocks)), + std::min( + static_cast(m_rp.m_tile_end[4] * m_rp.m_tile_end[5]), + static_cast(maxblocks))); + CudaParallelLaunch( + *this, grid, block, 0, m_rp.space().impl_internal_space_instance(), + false); + } else { printf("Kokkos::MDRange Error: Exceeded rank bounds with Cuda\n"); Kokkos::abort("Aborting"); } - } //end execute + } // end execute -// inline - ParallelFor( const FunctorType & arg_functor - , Policy arg_policy ) - : m_functor( arg_functor ) - , m_rp( arg_policy ) - {} + // inline + ParallelFor(const FunctorType& arg_functor, Policy arg_policy) + : m_functor(arg_functor), m_rp(arg_policy) {} }; +template +class ParallelFor, + Kokkos::Cuda> { + public: + typedef TeamPolicyInternal Policy; -template< class FunctorType , class ... Properties > -class ParallelFor< FunctorType - , Kokkos::TeamPolicy< Properties ... > - , Kokkos::Cuda - > -{ -public: - typedef TeamPolicyInternal< Kokkos::Cuda , Properties ... > Policy ; -private: - - typedef typename Policy::member_type Member ; - typedef typename Policy::work_tag WorkTag ; - typedef typename Policy::launch_bounds LaunchBounds ; - -public: - - typedef FunctorType functor_type ; - typedef Cuda::size_type size_type ; + private: + typedef typename Policy::member_type Member; + typedef typename Policy::work_tag WorkTag; + typedef typename Policy::launch_bounds LaunchBounds; -private: + public: + typedef FunctorType functor_type; + typedef Cuda::size_type size_type; - // Algorithmic constraints: blockDim.y is a power of two AND blockDim.y == blockDim.z == 1 - // shared memory utilization: + private: + // Algorithmic constraints: blockDim.y is a power of two AND blockDim.y == + // blockDim.z == 1 shared memory utilization: // // [ team reduce space ] // [ team shared space ] // - const FunctorType m_functor ; - const Policy m_policy ; - const size_type m_league_size ; - int m_team_size ; - const size_type m_vector_size ; - int m_shmem_begin ; - int m_shmem_size ; - void* m_scratch_ptr[2] ; - int m_scratch_size[2] ; - - template< class TagType > + const FunctorType m_functor; + const Policy m_policy; + const size_type m_league_size; + int m_team_size; + const size_type m_vector_size; + int m_shmem_begin; + int m_shmem_size; + void* m_scratch_ptr[2]; + int m_scratch_size[2]; + + template __device__ inline - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec_team( const Member & member ) const - { m_functor( member ); } + typename std::enable_if::value>::type + exec_team(const Member& member) const { + m_functor(member); + } - template< class TagType > + template __device__ inline - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec_team( const Member & member ) const - { m_functor( TagType() , member ); } - -public: + typename std::enable_if::value>::type + exec_team(const Member& member) const { + m_functor(TagType(), member); + } - __device__ inline - void operator()(void) const - { + public: + __device__ inline void operator()(void) const { // Iterate this block through the league int64_t threadid = 0; - if ( m_scratch_size[1]>0 ) { + if (m_scratch_size[1] > 0) { __shared__ int64_t base_thread_id; - if (threadIdx.x==0 && threadIdx.y==0 ) { - threadid = (blockIdx.x*blockDim.z + threadIdx.z) % - (Kokkos::Impl::g_device_cuda_lock_arrays.n / (blockDim.x * blockDim.y)); + if (threadIdx.x == 0 && threadIdx.y == 0) { + threadid = (blockIdx.x * blockDim.z + threadIdx.z) % + (Kokkos::Impl::g_device_cuda_lock_arrays.n / + (blockDim.x * blockDim.y)); threadid *= blockDim.x * blockDim.y; int done = 0; while (!done) { - done = (0 == atomicCAS(&Kokkos::Impl::g_device_cuda_lock_arrays.scratch[threadid],0,1)); - if(!done) { + done = + (0 == + atomicCAS( + &Kokkos::Impl::g_device_cuda_lock_arrays.scratch[threadid], + 0, 1)); + if (!done) { threadid += blockDim.x * blockDim.y; - if(int64_t(threadid+blockDim.x * blockDim.y) >= int64_t(Kokkos::Impl::g_device_cuda_lock_arrays.n)) threadid = 0; + if (int64_t(threadid + blockDim.x * blockDim.y) >= + int64_t(Kokkos::Impl::g_device_cuda_lock_arrays.n)) + threadid = 0; } } base_thread_id = threadid; @@ -736,79 +834,102 @@ public: threadid = base_thread_id; } - const int int_league_size = (int)m_league_size; - for ( int league_rank = blockIdx.x ; league_rank < int_league_size ; league_rank += gridDim.x ) { - - this-> template exec_team< WorkTag >( - typename Policy::member_type( kokkos_impl_cuda_shared_memory() - , m_shmem_begin - , m_shmem_size - , (void*) ( ((char*)m_scratch_ptr[1]) + ptrdiff_t(threadid/(blockDim.x*blockDim.y)) * m_scratch_size[1]) - , m_scratch_size[1] - , league_rank - , m_league_size ) ); - } - if ( m_scratch_size[1]>0 ) { + for (int league_rank = blockIdx.x; league_rank < int_league_size; + league_rank += gridDim.x) { + this->template exec_team(typename Policy::member_type( + kokkos_impl_cuda_shared_memory(), m_shmem_begin, m_shmem_size, + (void*)(((char*)m_scratch_ptr[1]) + + ptrdiff_t(threadid / (blockDim.x * blockDim.y)) * + m_scratch_size[1]), + m_scratch_size[1], league_rank, m_league_size)); + } + if (m_scratch_size[1] > 0) { __syncthreads(); - if (threadIdx.x==0 && threadIdx.y==0 ) - Kokkos::Impl::g_device_cuda_lock_arrays.scratch[threadid]=0; + if (threadIdx.x == 0 && threadIdx.y == 0) + Kokkos::Impl::g_device_cuda_lock_arrays.scratch[threadid] = 0; } } - inline - void execute() const - { - const int64_t shmem_size_total = m_shmem_begin + m_shmem_size ; - const dim3 grid( int(m_league_size) , 1 , 1 ); - const dim3 block( int(m_vector_size) , int(m_team_size) , 1 ); - - CudaParallelLaunch< ParallelFor, LaunchBounds >( *this, grid, block, shmem_size_total, m_policy.space().impl_internal_space_instance() , true ); // copy to device and execute + inline void execute() const { + const int64_t shmem_size_total = m_shmem_begin + m_shmem_size; + dim3 grid(int(m_league_size), 1, 1); + const dim3 block(int(m_vector_size), int(m_team_size), 1); +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + if (Kokkos::Impl::CudaInternal::cuda_use_serial_execution()) { + grid = dim3(1, 1, 1); } +#endif - ParallelFor( const FunctorType & arg_functor - , const Policy & arg_policy - ) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - , m_league_size( arg_policy.league_size() ) - , m_team_size( arg_policy.team_size() ) - , m_vector_size( arg_policy.vector_length() ) - { - cudaFuncAttributes attr = CudaParallelLaunch< ParallelFor, LaunchBounds >:: - get_cuda_func_attributes(); - m_team_size = m_team_size>=0?m_team_size:Kokkos::Impl::cuda_get_opt_block_size< FunctorType, LaunchBounds>( + CudaParallelLaunch( + *this, grid, block, shmem_size_total, m_policy.space().impl_internal_space_instance(), - attr, m_functor , m_vector_size, - m_policy.team_scratch_size(0), m_policy.thread_scratch_size(0) )/m_vector_size; - - m_shmem_begin = ( sizeof(double) * ( m_team_size + 2 ) ); - m_shmem_size = ( m_policy.scratch_size(0,m_team_size) + FunctorTeamShmemSize< FunctorType >::value( m_functor , m_team_size ) ); - m_scratch_size[0] = m_policy.scratch_size(0,m_team_size); - m_scratch_size[1] = m_policy.scratch_size(1,m_team_size); - - // Functor's reduce memory, team scan memory, and team shared memory depend upon team size. - m_scratch_ptr[0] = NULL; - m_scratch_ptr[1] = m_team_size<=0?NULL:cuda_resize_scratch_space(static_cast(m_scratch_size[1])*static_cast(Cuda::concurrency()/(m_team_size*m_vector_size))); - - const int shmem_size_total = m_shmem_begin + m_shmem_size ; - if ( m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock < shmem_size_total ) { - printf("%i %i\n",m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock,shmem_size_total); - Kokkos::Impl::throw_runtime_exception(std::string("Kokkos::Impl::ParallelFor< Cuda > insufficient shared memory")); - } + true); // copy to device and execute + } - if ( int(m_team_size) > - int(Kokkos::Impl::cuda_get_max_block_size< FunctorType, LaunchBounds > - ( m_policy.space().impl_internal_space_instance(), - attr, arg_functor , arg_policy.vector_length(), arg_policy.team_scratch_size(0),arg_policy.thread_scratch_size(0) ) / arg_policy.vector_length())) { - Kokkos::Impl::throw_runtime_exception(std::string("Kokkos::Impl::ParallelFor< Cuda > requested too large team size.")); - } + ParallelFor(const FunctorType& arg_functor, const Policy& arg_policy) + : m_functor(arg_functor), + m_policy(arg_policy), + m_league_size(arg_policy.league_size()), + m_team_size(arg_policy.team_size()), + m_vector_size(arg_policy.vector_length()) { + cudaFuncAttributes attr = + CudaParallelLaunch::get_cuda_func_attributes(); + m_team_size = + m_team_size >= 0 + ? m_team_size + : Kokkos::Impl::cuda_get_opt_block_size( + m_policy.space().impl_internal_space_instance(), attr, + m_functor, m_vector_size, m_policy.team_scratch_size(0), + m_policy.thread_scratch_size(0)) / + m_vector_size; + + m_shmem_begin = (sizeof(double) * (m_team_size + 2)); + m_shmem_size = + (m_policy.scratch_size(0, m_team_size) + + FunctorTeamShmemSize::value(m_functor, m_team_size)); + m_scratch_size[0] = m_policy.scratch_size(0, m_team_size); + m_scratch_size[1] = m_policy.scratch_size(1, m_team_size); + + // Functor's reduce memory, team scan memory, and team shared memory depend + // upon team size. + m_scratch_ptr[0] = NULL; + m_scratch_ptr[1] = + m_team_size <= 0 + ? NULL + : cuda_resize_scratch_space( + static_cast(m_scratch_size[1]) * + static_cast(Cuda::concurrency() / + (m_team_size * m_vector_size))); + + const int shmem_size_total = m_shmem_begin + m_shmem_size; + if (m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock < + shmem_size_total) { + printf( + "%i %i\n", + m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock, + shmem_size_total); + Kokkos::Impl::throw_runtime_exception(std::string( + "Kokkos::Impl::ParallelFor< Cuda > insufficient shared memory")); + } + + if (int(m_team_size) > + int(Kokkos::Impl::cuda_get_max_block_size( + m_policy.space().impl_internal_space_instance(), attr, + arg_functor, arg_policy.vector_length(), + arg_policy.team_scratch_size(0), + arg_policy.thread_scratch_size(0)) / + arg_policy.vector_length())) { + Kokkos::Impl::throw_runtime_exception(std::string( + "Kokkos::Impl::ParallelFor< Cuda > requested too large team size.")); } + } }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -816,576 +937,696 @@ public: namespace Kokkos { namespace Impl { -template< class FunctorType , class ReducerType, class ... Traits > -class ParallelReduce< FunctorType - , Kokkos::RangePolicy< Traits ... > - , ReducerType - , Kokkos::Cuda - > -{ -public: - typedef Kokkos::RangePolicy< Traits ... > Policy ; -private: +template +class ParallelReduce, ReducerType, + Kokkos::Cuda> { + public: + typedef Kokkos::RangePolicy Policy; + private: + typedef typename Policy::WorkRange WorkRange; + typedef typename Policy::work_tag WorkTag; + typedef typename Policy::member_type Member; + typedef typename Policy::launch_bounds LaunchBounds; - typedef typename Policy::WorkRange WorkRange ; - typedef typename Policy::work_tag WorkTag ; - typedef typename Policy::member_type Member ; - typedef typename Policy::launch_bounds LaunchBounds ; - - typedef Kokkos::Impl::if_c< std::is_same::value, FunctorType, ReducerType> ReducerConditional; + typedef Kokkos::Impl::if_c::value, + FunctorType, ReducerType> + ReducerConditional; typedef typename ReducerConditional::type ReducerTypeFwd; - typedef typename Kokkos::Impl::if_c< std::is_same::value, WorkTag, void>::type WorkTagFwd; - - typedef Kokkos::Impl::FunctorValueTraits< ReducerTypeFwd, WorkTagFwd > ValueTraits ; - typedef Kokkos::Impl::FunctorValueInit< ReducerTypeFwd, WorkTagFwd > ValueInit ; - typedef Kokkos::Impl::FunctorValueJoin< ReducerTypeFwd, WorkTagFwd > ValueJoin ; - -public: - - typedef typename ValueTraits::pointer_type pointer_type ; - typedef typename ValueTraits::value_type value_type ; - typedef typename ValueTraits::reference_type reference_type ; - typedef FunctorType functor_type ; - typedef Kokkos::Cuda::size_type size_type ; - typedef typename Policy::index_type index_type ; - - // Algorithmic constraints: blockSize is a power of two AND blockDim.y == blockDim.z == 1 - - const FunctorType m_functor ; - const Policy m_policy ; - const ReducerType m_reducer ; - const pointer_type m_result_ptr ; - const bool m_result_ptr_device_accessible ; - size_type * m_scratch_space ; - size_type * m_scratch_flags ; - size_type * m_unified_space ; - - // Shall we use the shfl based reduction or not (only use it for static sized types of more than 128bit) - enum { UseShflReduction = false };//((sizeof(value_type)>2*sizeof(double)) && ValueTraits::StaticValueSize) }; - // Some crutch to do function overloading -private: + typedef + typename Kokkos::Impl::if_c::value, + WorkTag, void>::type WorkTagFwd; + + typedef Kokkos::Impl::FunctorValueTraits + ValueTraits; + typedef Kokkos::Impl::FunctorValueInit ValueInit; + typedef Kokkos::Impl::FunctorValueJoin ValueJoin; + + public: + typedef typename ValueTraits::pointer_type pointer_type; + typedef typename ValueTraits::value_type value_type; + typedef typename ValueTraits::reference_type reference_type; + typedef FunctorType functor_type; + typedef Kokkos::Cuda::size_type size_type; + typedef typename Policy::index_type index_type; + + // Algorithmic constraints: blockSize is a power of two AND blockDim.y == + // blockDim.z == 1 + + const FunctorType m_functor; + const Policy m_policy; + const ReducerType m_reducer; + const pointer_type m_result_ptr; + const bool m_result_ptr_device_accessible; + size_type* m_scratch_space; + size_type* m_scratch_flags; + size_type* m_unified_space; + + // Shall we use the shfl based reduction or not (only use it for static sized + // types of more than 128bit) + enum { + UseShflReduction = false + }; //((sizeof(value_type)>2*sizeof(double)) && ValueTraits::StaticValueSize) + //}; + // Some crutch to do function overloading + private: typedef double DummyShflReductionType; typedef int DummySHMEMReductionType; -public: + public: // Make the exec_range calls call to Reduce::DeviceIterateTile - template< class TagType > - __device__ inline - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec_range( const Member & i , reference_type update ) const - { m_functor( i , update ); } - - template< class TagType > + template __device__ inline - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec_range( const Member & i , reference_type update ) const - { m_functor( TagType() , i , update ); } + typename std::enable_if::value>::type + exec_range(const Member& i, reference_type update) const { + m_functor(i, update); + } + template __device__ inline - void operator() () const { -/* run(Kokkos::Impl::if_c::select(1,1.0) ); + typename std::enable_if::value>::type + exec_range(const Member& i, reference_type update) const { + m_functor(TagType(), i, update); } - __device__ inline - void run(const DummySHMEMReductionType& ) const - {*/ - const integral_nonzero_constant< size_type , ValueTraits::StaticValueSize / sizeof(size_type) > - word_count( ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ) / sizeof(size_type) ); + __device__ inline void operator()() const { + /* run(Kokkos::Impl::if_c::select(1,1.0) ); + } + + __device__ inline + void run(const DummySHMEMReductionType& ) const + {*/ + const integral_nonzero_constant + word_count(ValueTraits::value_size( + ReducerConditional::select(m_functor, m_reducer)) / + sizeof(size_type)); { reference_type value = - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , kokkos_impl_cuda_shared_memory() + threadIdx.y * word_count.value ); + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), + kokkos_impl_cuda_shared_memory() + + threadIdx.y * word_count.value); - // Number of blocks is bounded so that the reduction can be limited to two passes. - // Each thread block is given an approximately equal amount of work to perform. - // Accumulate the values for this block. - // The accumulation ordering does not match the final pass, but is arithmatically equivalent. + // Number of blocks is bounded so that the reduction can be limited to two + // passes. Each thread block is given an approximately equal amount of + // work to perform. Accumulate the values for this block. The accumulation + // ordering does not match the final pass, but is arithmatically + // equivalent. - const WorkRange range( m_policy , blockIdx.x , gridDim.x ); + const WorkRange range(m_policy, blockIdx.x, gridDim.x); - for ( Member iwork = range.begin() + threadIdx.y , iwork_end = range.end() ; - iwork < iwork_end ; iwork += blockDim.y ) { - this-> template exec_range< WorkTag >( iwork , value ); + for (Member iwork = range.begin() + threadIdx.y, iwork_end = range.end(); + iwork < iwork_end; iwork += blockDim.y) { + this->template exec_range(iwork, value); } } // Reduce with final value at blockDim.y - 1 location. - if ( cuda_single_inter_block_reduce_scan( - ReducerConditional::select(m_functor , m_reducer) , blockIdx.x , gridDim.x , - kokkos_impl_cuda_shared_memory() , m_scratch_space , m_scratch_flags ) ) { - - // This is the final block with the final result at the final threads' location - - size_type * const shared = kokkos_impl_cuda_shared_memory() + ( blockDim.y - 1 ) * word_count.value ; - size_type * const global = m_result_ptr_device_accessible? reinterpret_cast(m_result_ptr) : - ( m_unified_space ? m_unified_space : m_scratch_space ); - - if ( threadIdx.y == 0 ) { - Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTagFwd >::final( ReducerConditional::select(m_functor , m_reducer) , shared ); + if (cuda_single_inter_block_reduce_scan( + ReducerConditional::select(m_functor, m_reducer), blockIdx.x, + gridDim.x, kokkos_impl_cuda_shared_memory(), + m_scratch_space, m_scratch_flags)) { + // This is the final block with the final result at the final threads' + // location + + size_type* const shared = kokkos_impl_cuda_shared_memory() + + (blockDim.y - 1) * word_count.value; + size_type* const global = + m_result_ptr_device_accessible + ? reinterpret_cast(m_result_ptr) + : (m_unified_space ? m_unified_space : m_scratch_space); + + if (threadIdx.y == 0) { + Kokkos::Impl::FunctorFinal::final( + ReducerConditional::select(m_functor, m_reducer), shared); } - if ( CudaTraits::WarpSize < word_count.value ) { __syncthreads(); } + if (CudaTraits::WarpSize < word_count.value) { + __syncthreads(); + } - for ( unsigned i = threadIdx.y ; i < word_count.value ; i += blockDim.y ) { global[i] = shared[i]; } + for (unsigned i = threadIdx.y; i < word_count.value; i += blockDim.y) { + global[i] = shared[i]; + } } } -/* __device__ inline - void run(const DummyShflReductionType&) const - { - value_type value; - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , &value); - // Number of blocks is bounded so that the reduction can be limited to two passes. - // Each thread block is given an approximately equal amount of work to perform. - // Accumulate the values for this block. - // The accumulation ordering does not match the final pass, but is arithmatically equivalent. - - const WorkRange range( m_policy , blockIdx.x , gridDim.x ); - - for ( Member iwork = range.begin() + threadIdx.y , iwork_end = range.end() ; - iwork < iwork_end ; iwork += blockDim.y ) { - this-> template exec_range< WorkTag >( iwork , value ); - } - - pointer_type const result = (pointer_type) (m_unified_space ? m_unified_space : m_scratch_space) ; - - int max_active_thread = range.end()-range.begin() < blockDim.y ? range.end() - range.begin():blockDim.y; - - max_active_thread = (max_active_thread == 0)?blockDim.y:max_active_thread; + /* __device__ inline + void run(const DummyShflReductionType&) const + { + value_type value; + ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , + &value); + // Number of blocks is bounded so that the reduction can be limited to + two passes. + // Each thread block is given an approximately equal amount of work to + perform. + // Accumulate the values for this block. + // The accumulation ordering does not match the final pass, but is + arithmatically equivalent. + + const WorkRange range( m_policy , blockIdx.x , gridDim.x ); + + for ( Member iwork = range.begin() + threadIdx.y , iwork_end = + range.end() ; iwork < iwork_end ; iwork += blockDim.y ) { this-> template + exec_range< WorkTag >( iwork , value ); + } - value_type init; - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , &init); - if(Impl::cuda_inter_block_reduction - (value,init,ValueJoin(ReducerConditional::select(m_functor , m_reducer)),m_scratch_space,result,m_scratch_flags,max_active_thread)) { - const unsigned id = threadIdx.y*blockDim.x + threadIdx.x; - if(id==0) { - Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTagFwd >::final( ReducerConditional::select(m_functor , m_reducer) , (void*) &value ); - *result = value; + pointer_type const result = (pointer_type) (m_unified_space ? + m_unified_space : m_scratch_space) ; + + int max_active_thread = range.end()-range.begin() < blockDim.y ? + range.end() - range.begin():blockDim.y; + + max_active_thread = (max_active_thread == + 0)?blockDim.y:max_active_thread; + + value_type init; + ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , + &init); + if(Impl::cuda_inter_block_reduction + (value,init,ValueJoin(ReducerConditional::select(m_functor , + m_reducer)),m_scratch_space,result,m_scratch_flags,max_active_thread)) { + const unsigned id = threadIdx.y*blockDim.x + threadIdx.x; + if(id==0) { + Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTagFwd >::final( + ReducerConditional::select(m_functor , m_reducer) , (void*) &value ); + *result = value; + } } - } - }*/ + }*/ // Determine block size constrained by shared memory: - inline - unsigned local_block_size( const FunctorType & f ) - { - unsigned n = CudaTraits::WarpSize * 8 ; - int shmem_size = cuda_single_inter_block_reduce_scan_shmem( f , n ); - while ( (n && (m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock < shmem_size)) || - (n > static_cast(Kokkos::Impl::cuda_get_max_block_size< ParallelReduce, LaunchBounds>( f , 1, shmem_size , 0 )))) { - n >>= 1 ; - shmem_size = cuda_single_inter_block_reduce_scan_shmem( f , n ); - } - return n ; - } - - inline - void execute() - { - const index_type nwork = m_policy.end() - m_policy.begin(); - if ( nwork ) { - const int block_size = local_block_size( m_functor ); - - m_scratch_space = cuda_internal_scratch_space( m_policy.space(), ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ) * block_size /* block_size == max block_count */ ); - m_scratch_flags = cuda_internal_scratch_flags( m_policy.space(), sizeof(size_type) ); - m_unified_space = cuda_internal_scratch_unified( m_policy.space(), ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ) ); - - // REQUIRED ( 1 , N , 1 ) - const dim3 block( 1 , block_size , 1 ); - // Required grid.x <= block.y - const dim3 grid( std::min( int(block.y) , int( ( nwork + block.y - 1 ) / block.y ) ) , 1 , 1 ); + inline unsigned local_block_size(const FunctorType& f) { + unsigned n = CudaTraits::WarpSize * 8; + int shmem_size = + cuda_single_inter_block_reduce_scan_shmem( + f, n); + while ( + (n && + (m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock < + shmem_size)) || + (n > static_cast( + Kokkos::Impl::cuda_get_max_block_size< + ParallelReduce, LaunchBounds>(f, 1, shmem_size, 0)))) { + n >>= 1; + shmem_size = cuda_single_inter_block_reduce_scan_shmem(f, n); + } + return n; + } - const int shmem = UseShflReduction?0:cuda_single_inter_block_reduce_scan_shmem( m_functor , block.y ); + inline void execute() { + const index_type nwork = m_policy.end() - m_policy.begin(); + if (nwork) { + const int block_size = local_block_size(m_functor); + + m_scratch_space = cuda_internal_scratch_space( + m_policy.space(), ValueTraits::value_size(ReducerConditional::select( + m_functor, m_reducer)) * + block_size /* block_size == max block_count */); + m_scratch_flags = + cuda_internal_scratch_flags(m_policy.space(), sizeof(size_type)); + m_unified_space = cuda_internal_scratch_unified( + m_policy.space(), ValueTraits::value_size(ReducerConditional::select( + m_functor, m_reducer))); + + // REQUIRED ( 1 , N , 1 ) + dim3 block(1, block_size, 1); + // Required grid.x <= block.y + dim3 grid(std::min(int(block.y), int((nwork + block.y - 1) / block.y)), 1, + 1); + + const int shmem = + UseShflReduction + ? 0 + : cuda_single_inter_block_reduce_scan_shmem(m_functor, + block.y); + +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + if (Kokkos::Impl::CudaInternal::cuda_use_serial_execution()) { + block = dim3(1, 1, 1); + grid = dim3(1, 1, 1); + } +#endif - CudaParallelLaunch< ParallelReduce, LaunchBounds >( *this, grid, block, shmem , m_policy.space().impl_internal_space_instance() , false ); // copy to device and execute + CudaParallelLaunch( + *this, grid, block, shmem, + m_policy.space().impl_internal_space_instance(), + false); // copy to device and execute - if(!m_result_ptr_device_accessible) { + if (!m_result_ptr_device_accessible) { Cuda().fence(); - if ( m_result_ptr ) { - if ( m_unified_space ) { - const int count = ValueTraits::value_count( ReducerConditional::select(m_functor , m_reducer) ); - for ( int i = 0 ; i < count ; ++i ) { m_result_ptr[i] = pointer_type(m_unified_space)[i] ; } - } - else { - const int size = ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ); - DeepCopy( m_result_ptr , m_scratch_space , size ); + if (m_result_ptr) { + if (m_unified_space) { + const int count = ValueTraits::value_count( + ReducerConditional::select(m_functor, m_reducer)); + for (int i = 0; i < count; ++i) { + m_result_ptr[i] = pointer_type(m_unified_space)[i]; + } + } else { + const int size = ValueTraits::value_size( + ReducerConditional::select(m_functor, m_reducer)); + DeepCopy(m_result_ptr, m_scratch_space, size); } } } - } - else { + } else { if (m_result_ptr) { - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , m_result_ptr ); + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), + m_result_ptr); } } } - template< class ViewType > - ParallelReduce( const FunctorType & arg_functor - , const Policy & arg_policy - , const ViewType & arg_result - , typename std::enable_if< - Kokkos::is_view< ViewType >::value - ,void*>::type = NULL) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - , m_reducer( InvalidType() ) - , m_result_ptr( arg_result.data() ) - , m_result_ptr_device_accessible(MemorySpaceAccess< Kokkos::CudaSpace , typename ViewType::memory_space>::accessible ) - , m_scratch_space( 0 ) - , m_scratch_flags( 0 ) - , m_unified_space( 0 ) - { } - - ParallelReduce( const FunctorType & arg_functor - , const Policy & arg_policy - , const ReducerType & reducer) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - , m_reducer( reducer ) - , m_result_ptr( reducer.view().data() ) - , m_result_ptr_device_accessible(MemorySpaceAccess< Kokkos::CudaSpace , typename ReducerType::result_view_type::memory_space>::accessible ) - , m_scratch_space( 0 ) - , m_scratch_flags( 0 ) - , m_unified_space( 0 ) - { } + template + ParallelReduce(const FunctorType& arg_functor, const Policy& arg_policy, + const ViewType& arg_result, + typename std::enable_if::value, + void*>::type = NULL) + : m_functor(arg_functor), + m_policy(arg_policy), + m_reducer(InvalidType()), + m_result_ptr(arg_result.data()), + m_result_ptr_device_accessible( + MemorySpaceAccess::accessible), + m_scratch_space(0), + m_scratch_flags(0), + m_unified_space(0) {} + + ParallelReduce(const FunctorType& arg_functor, const Policy& arg_policy, + const ReducerType& reducer) + : m_functor(arg_functor), + m_policy(arg_policy), + m_reducer(reducer), + m_result_ptr(reducer.view().data()), + m_result_ptr_device_accessible( + MemorySpaceAccess::accessible), + m_scratch_space(0), + m_scratch_flags(0), + m_unified_space(0) {} }; - // MDRangePolicy impl -template< class FunctorType , class ReducerType, class ... Traits > -class ParallelReduce< FunctorType - , Kokkos::MDRangePolicy< Traits ... > - , ReducerType - , Kokkos::Cuda - > -{ -public: - typedef Kokkos::MDRangePolicy< Traits ... > Policy ; -private: - - typedef typename Policy::array_index_type array_index_type; - typedef typename Policy::index_type index_type; - - typedef typename Policy::work_tag WorkTag ; - typedef typename Policy::member_type Member ; - typedef typename Policy::launch_bounds LaunchBounds; - - typedef Kokkos::Impl::if_c< std::is_same::value, FunctorType, ReducerType> ReducerConditional; - typedef typename ReducerConditional::type ReducerTypeFwd; - typedef typename Kokkos::Impl::if_c< std::is_same::value, WorkTag, void>::type WorkTagFwd; +template +class ParallelReduce, ReducerType, + Kokkos::Cuda> { + public: + typedef Kokkos::MDRangePolicy Policy; - typedef Kokkos::Impl::FunctorValueTraits< ReducerTypeFwd, WorkTagFwd > ValueTraits ; - typedef Kokkos::Impl::FunctorValueInit< ReducerTypeFwd, WorkTagFwd > ValueInit ; - typedef Kokkos::Impl::FunctorValueJoin< ReducerTypeFwd, WorkTagFwd > ValueJoin ; - -public: - - typedef typename ValueTraits::pointer_type pointer_type ; - typedef typename ValueTraits::value_type value_type ; - typedef typename ValueTraits::reference_type reference_type ; - typedef FunctorType functor_type ; - typedef Cuda::size_type size_type ; - - // Algorithmic constraints: blockSize is a power of two AND blockDim.y == blockDim.z == 1 - - const FunctorType m_functor ; - const Policy m_policy ; // used for workrange and nwork - const ReducerType m_reducer ; - const pointer_type m_result_ptr ; - const bool m_result_ptr_device_accessible ; - size_type * m_scratch_space ; - size_type * m_scratch_flags ; - size_type * m_unified_space ; + private: + typedef typename Policy::array_index_type array_index_type; + typedef typename Policy::index_type index_type; - typedef typename Kokkos::Impl::Reduce::DeviceIterateTile DeviceIteratePattern; + typedef typename Policy::work_tag WorkTag; + typedef typename Policy::member_type Member; + typedef typename Policy::launch_bounds LaunchBounds; - // Shall we use the shfl based reduction or not (only use it for static sized types of more than 128bit - enum { UseShflReduction = ((sizeof(value_type)>2*sizeof(double)) && (ValueTraits::StaticValueSize!=0)) }; + typedef Kokkos::Impl::if_c::value, + FunctorType, ReducerType> + ReducerConditional; + typedef typename ReducerConditional::type ReducerTypeFwd; + typedef + typename Kokkos::Impl::if_c::value, + WorkTag, void>::type WorkTagFwd; + + typedef Kokkos::Impl::FunctorValueTraits + ValueTraits; + typedef Kokkos::Impl::FunctorValueInit ValueInit; + typedef Kokkos::Impl::FunctorValueJoin ValueJoin; + + public: + typedef typename ValueTraits::pointer_type pointer_type; + typedef typename ValueTraits::value_type value_type; + typedef typename ValueTraits::reference_type reference_type; + typedef FunctorType functor_type; + typedef Cuda::size_type size_type; + + // Algorithmic constraints: blockSize is a power of two AND blockDim.y == + // blockDim.z == 1 + + const FunctorType m_functor; + const Policy m_policy; // used for workrange and nwork + const ReducerType m_reducer; + const pointer_type m_result_ptr; + const bool m_result_ptr_device_accessible; + size_type* m_scratch_space; + size_type* m_scratch_flags; + size_type* m_unified_space; + + typedef typename Kokkos::Impl::Reduce::DeviceIterateTile< + Policy::rank, Policy, FunctorType, typename Policy::work_tag, + reference_type> + DeviceIteratePattern; + + // Shall we use the shfl based reduction or not (only use it for static sized + // types of more than 128bit + enum { + UseShflReduction = ((sizeof(value_type) > 2 * sizeof(double)) && + (ValueTraits::StaticValueSize != 0)) + }; // Some crutch to do function overloading -private: + private: typedef double DummyShflReductionType; typedef int DummySHMEMReductionType; -public: - inline - __device__ - void - exec_range( reference_type update ) const - { - Kokkos::Impl::Reduce::DeviceIterateTile(m_policy, m_functor, update).exec_range(); + public: + inline __device__ void exec_range(reference_type update) const { + Kokkos::Impl::Reduce::DeviceIterateTile(m_policy, m_functor, + update) + .exec_range(); } - inline - __device__ - void operator() (void) const { -/* run(Kokkos::Impl::if_c::select(1,1.0) ); - } + inline __device__ void operator()(void) const { + /* run(Kokkos::Impl::if_c::select(1,1.0) ); + } - __device__ inline - void run(const DummySHMEMReductionType& ) const - {*/ - const integral_nonzero_constant< size_type , ValueTraits::StaticValueSize / sizeof(size_type) > - word_count( ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ) / sizeof(size_type) ); + __device__ inline + void run(const DummySHMEMReductionType& ) const + {*/ + const integral_nonzero_constant + word_count(ValueTraits::value_size( + ReducerConditional::select(m_functor, m_reducer)) / + sizeof(size_type)); { reference_type value = - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , kokkos_impl_cuda_shared_memory() + threadIdx.y * word_count.value ); + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), + kokkos_impl_cuda_shared_memory() + + threadIdx.y * word_count.value); - // Number of blocks is bounded so that the reduction can be limited to two passes. - // Each thread block is given an approximately equal amount of work to perform. - // Accumulate the values for this block. - // The accumulation ordering does not match the final pass, but is arithmatically equivalent. + // Number of blocks is bounded so that the reduction can be limited to two + // passes. Each thread block is given an approximately equal amount of + // work to perform. Accumulate the values for this block. The accumulation + // ordering does not match the final pass, but is arithmatically + // equivalent. - this-> exec_range( value ); + this->exec_range(value); } // Reduce with final value at blockDim.y - 1 location. // Problem: non power-of-two blockDim - if ( cuda_single_inter_block_reduce_scan( - ReducerConditional::select(m_functor , m_reducer) , blockIdx.x , gridDim.x , - kokkos_impl_cuda_shared_memory() , m_scratch_space , m_scratch_flags ) ) { - - // This is the final block with the final result at the final threads' location - size_type * const shared = kokkos_impl_cuda_shared_memory() + ( blockDim.y - 1 ) * word_count.value ; - size_type * const global = m_result_ptr_device_accessible? reinterpret_cast(m_result_ptr) : - ( m_unified_space ? m_unified_space : m_scratch_space ); - - if ( threadIdx.y == 0 ) { - Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTagFwd >::final( ReducerConditional::select(m_functor , m_reducer) , shared ); + if (cuda_single_inter_block_reduce_scan( + ReducerConditional::select(m_functor, m_reducer), blockIdx.x, + gridDim.x, kokkos_impl_cuda_shared_memory(), + m_scratch_space, m_scratch_flags)) { + // This is the final block with the final result at the final threads' + // location + size_type* const shared = kokkos_impl_cuda_shared_memory() + + (blockDim.y - 1) * word_count.value; + size_type* const global = + m_result_ptr_device_accessible + ? reinterpret_cast(m_result_ptr) + : (m_unified_space ? m_unified_space : m_scratch_space); + + if (threadIdx.y == 0) { + Kokkos::Impl::FunctorFinal::final( + ReducerConditional::select(m_functor, m_reducer), shared); } - if ( CudaTraits::WarpSize < word_count.value ) { __syncthreads(); } + if (CudaTraits::WarpSize < word_count.value) { + __syncthreads(); + } - for ( unsigned i = threadIdx.y ; i < word_count.value ; i += blockDim.y ) { global[i] = shared[i]; } + for (unsigned i = threadIdx.y; i < word_count.value; i += blockDim.y) { + global[i] = shared[i]; + } } } -/* __device__ inline - void run(const DummyShflReductionType&) const - { - - value_type value; - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , &value); - // Number of blocks is bounded so that the reduction can be limited to two passes. - // Each thread block is given an approximately equal amount of work to perform. - // Accumulate the values for this block. - // The accumulation ordering does not match the final pass, but is arithmatically equivalent. - - const Member work_part = - ( ( m_policy.m_num_tiles + ( gridDim.x - 1 ) ) / gridDim.x ); //portion of tiles handled by each block - - this-> exec_range( value ); - - pointer_type const result = (pointer_type) (m_unified_space ? m_unified_space : m_scratch_space) ; - - int max_active_thread = work_part < blockDim.y ? work_part:blockDim.y; - max_active_thread = (max_active_thread == 0)?blockDim.y:max_active_thread; - - value_type init; - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , &init); - if(Impl::cuda_inter_block_reduction - (value,init,ValueJoin(ReducerConditional::select(m_functor , m_reducer)),m_scratch_space,result,m_scratch_flags,max_active_thread)) { - const unsigned id = threadIdx.y*blockDim.x + threadIdx.x; - if(id==0) { - Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTagFwd >::final( ReducerConditional::select(m_functor , m_reducer) , (void*) &value ); - *result = value; + /* __device__ inline + void run(const DummyShflReductionType&) const + { + + value_type value; + ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , + &value); + // Number of blocks is bounded so that the reduction can be limited to + two passes. + // Each thread block is given an approximately equal amount of work to + perform. + // Accumulate the values for this block. + // The accumulation ordering does not match the final pass, but is + arithmatically equivalent. + + const Member work_part = + ( ( m_policy.m_num_tiles + ( gridDim.x - 1 ) ) / gridDim.x ); //portion + of tiles handled by each block + + this-> exec_range( value ); + + pointer_type const result = (pointer_type) (m_unified_space ? + m_unified_space : m_scratch_space) ; + + int max_active_thread = work_part < blockDim.y ? work_part:blockDim.y; + max_active_thread = (max_active_thread == + 0)?blockDim.y:max_active_thread; + + value_type init; + ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , + &init); + if(Impl::cuda_inter_block_reduction + (value,init,ValueJoin(ReducerConditional::select(m_functor , + m_reducer)),m_scratch_space,result,m_scratch_flags,max_active_thread)) { + const unsigned id = threadIdx.y*blockDim.x + threadIdx.x; + if(id==0) { + Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTagFwd >::final( + ReducerConditional::select(m_functor , m_reducer) , (void*) &value ); + *result = value; + } } } - } -*/ + */ // Determine block size constrained by shared memory: - inline - unsigned local_block_size( const FunctorType & f ) - { - unsigned n = CudaTraits::WarpSize * 8 ; - int shmem_size = cuda_single_inter_block_reduce_scan_shmem( f , n ); - while ( (n && (m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock < shmem_size)) || - (n > static_cast(Kokkos::Impl::cuda_get_max_block_size< ParallelReduce, LaunchBounds>( f , 1, shmem_size , 0 )))) { - n >>= 1 ; - shmem_size = cuda_single_inter_block_reduce_scan_shmem( f , n ); - } - return n ; - } - - inline - void execute() - { - const int nwork = m_policy.m_num_tiles; - if ( nwork ) { - int block_size = m_policy.m_prod_tile_dims; - // CONSTRAINT: Algorithm requires block_size >= product of tile dimensions - // Nearest power of two - int exponent_pow_two = std::ceil( std::log2(block_size) ); - block_size = std::pow(2, exponent_pow_two); - int suggested_blocksize = local_block_size( m_functor ); - - block_size = (block_size > suggested_blocksize) ? block_size : suggested_blocksize ; //Note: block_size must be less than or equal to 512 - - - m_scratch_space = cuda_internal_scratch_space( m_policy.space(), ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ) * block_size /* block_size == max block_count */ ); - m_scratch_flags = cuda_internal_scratch_flags( m_policy.space(), sizeof(size_type) ); - m_unified_space = cuda_internal_scratch_unified( m_policy.space(), ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ) ); - - // REQUIRED ( 1 , N , 1 ) - const dim3 block( 1 , block_size , 1 ); - // Required grid.x <= block.y - const dim3 grid( std::min( int(block.y) , int( nwork ) ) , 1 , 1 ); - - const int shmem = UseShflReduction?0:cuda_single_inter_block_reduce_scan_shmem( m_functor , block.y ); + inline unsigned local_block_size(const FunctorType& f) { + unsigned n = CudaTraits::WarpSize * 8; + int shmem_size = + cuda_single_inter_block_reduce_scan_shmem( + f, n); + while ( + (n && + (m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock < + shmem_size)) || + (n > static_cast( + Kokkos::Impl::cuda_get_max_block_size< + ParallelReduce, LaunchBounds>(f, 1, shmem_size, 0)))) { + n >>= 1; + shmem_size = cuda_single_inter_block_reduce_scan_shmem(f, n); + } + return n; + } - CudaParallelLaunch< ParallelReduce, LaunchBounds >( *this, grid, block, shmem , m_policy.space().impl_internal_space_instance() , false ); // copy to device and execute + inline void execute() { + const int nwork = m_policy.m_num_tiles; + if (nwork) { + int block_size = m_policy.m_prod_tile_dims; + // CONSTRAINT: Algorithm requires block_size >= product of tile dimensions + // Nearest power of two + int exponent_pow_two = std::ceil(std::log2(block_size)); + block_size = std::pow(2, exponent_pow_two); + int suggested_blocksize = local_block_size(m_functor); + + block_size = (block_size > suggested_blocksize) + ? block_size + : suggested_blocksize; // Note: block_size must be less + // than or equal to 512 + + m_scratch_space = cuda_internal_scratch_space( + m_policy.space(), ValueTraits::value_size(ReducerConditional::select( + m_functor, m_reducer)) * + block_size /* block_size == max block_count */); + m_scratch_flags = + cuda_internal_scratch_flags(m_policy.space(), sizeof(size_type)); + m_unified_space = cuda_internal_scratch_unified( + m_policy.space(), ValueTraits::value_size(ReducerConditional::select( + m_functor, m_reducer))); + + // REQUIRED ( 1 , N , 1 ) + const dim3 block(1, block_size, 1); + // Required grid.x <= block.y + const dim3 grid(std::min(int(block.y), int(nwork)), 1, 1); + + const int shmem = + UseShflReduction + ? 0 + : cuda_single_inter_block_reduce_scan_shmem(m_functor, + block.y); + + CudaParallelLaunch( + *this, grid, block, shmem, + m_policy.space().impl_internal_space_instance(), + false); // copy to device and execute - if(!m_result_ptr_device_accessible) { + if (!m_result_ptr_device_accessible) { Cuda().fence(); - if ( m_result_ptr ) { - if ( m_unified_space ) { - const int count = ValueTraits::value_count( ReducerConditional::select(m_functor , m_reducer) ); - for ( int i = 0 ; i < count ; ++i ) { m_result_ptr[i] = pointer_type(m_unified_space)[i] ; } - } - else { - const int size = ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ); - DeepCopy( m_result_ptr , m_scratch_space , size ); + if (m_result_ptr) { + if (m_unified_space) { + const int count = ValueTraits::value_count( + ReducerConditional::select(m_functor, m_reducer)); + for (int i = 0; i < count; ++i) { + m_result_ptr[i] = pointer_type(m_unified_space)[i]; + } + } else { + const int size = ValueTraits::value_size( + ReducerConditional::select(m_functor, m_reducer)); + DeepCopy(m_result_ptr, m_scratch_space, size); } } } - } - else { + } else { if (m_result_ptr) { - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , m_result_ptr ); + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), + m_result_ptr); } } } - template< class ViewType > - ParallelReduce( const FunctorType & arg_functor - , const Policy & arg_policy - , const ViewType & arg_result - , typename std::enable_if< - Kokkos::is_view< ViewType >::value - ,void*>::type = NULL) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - , m_reducer( InvalidType() ) - , m_result_ptr( arg_result.data() ) - , m_result_ptr_device_accessible(MemorySpaceAccess< Kokkos::CudaSpace , typename ViewType::memory_space>::accessible ) - , m_scratch_space( 0 ) - , m_scratch_flags( 0 ) - , m_unified_space( 0 ) - {} - - ParallelReduce( const FunctorType & arg_functor - , const Policy & arg_policy - , const ReducerType & reducer) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - , m_reducer( reducer ) - , m_result_ptr( reducer.view().data() ) - , m_result_ptr_device_accessible(MemorySpaceAccess< Kokkos::CudaSpace , typename ReducerType::result_view_type::memory_space>::accessible ) - , m_scratch_space( 0 ) - , m_scratch_flags( 0 ) - , m_unified_space( 0 ) - {} + template + ParallelReduce(const FunctorType& arg_functor, const Policy& arg_policy, + const ViewType& arg_result, + typename std::enable_if::value, + void*>::type = NULL) + : m_functor(arg_functor), + m_policy(arg_policy), + m_reducer(InvalidType()), + m_result_ptr(arg_result.data()), + m_result_ptr_device_accessible( + MemorySpaceAccess::accessible), + m_scratch_space(0), + m_scratch_flags(0), + m_unified_space(0) {} + + ParallelReduce(const FunctorType& arg_functor, const Policy& arg_policy, + const ReducerType& reducer) + : m_functor(arg_functor), + m_policy(arg_policy), + m_reducer(reducer), + m_result_ptr(reducer.view().data()), + m_result_ptr_device_accessible( + MemorySpaceAccess::accessible), + m_scratch_space(0), + m_scratch_flags(0), + m_unified_space(0) {} }; - //---------------------------------------------------------------------------- -template< class FunctorType , class ReducerType, class ... Properties > -class ParallelReduce< FunctorType - , Kokkos::TeamPolicy< Properties ... > - , ReducerType - , Kokkos::Cuda - > -{ -public: - typedef TeamPolicyInternal< Kokkos::Cuda, Properties ... > Policy ; -private: - - typedef typename Policy::member_type Member ; - typedef typename Policy::work_tag WorkTag ; - typedef typename Policy::launch_bounds LaunchBounds ; - - typedef Kokkos::Impl::if_c< std::is_same::value, FunctorType, ReducerType> ReducerConditional; - typedef typename ReducerConditional::type ReducerTypeFwd; - typedef typename Kokkos::Impl::if_c< std::is_same::value, WorkTag, void>::type WorkTagFwd; +template +class ParallelReduce, + ReducerType, Kokkos::Cuda> { + public: + typedef TeamPolicyInternal Policy; + + private: + typedef typename Policy::member_type Member; + typedef typename Policy::work_tag WorkTag; + typedef typename Policy::launch_bounds LaunchBounds; - typedef Kokkos::Impl::FunctorValueTraits< ReducerTypeFwd, WorkTagFwd > ValueTraits ; - typedef Kokkos::Impl::FunctorValueInit< ReducerTypeFwd, WorkTagFwd > ValueInit ; - typedef Kokkos::Impl::FunctorValueJoin< ReducerTypeFwd, WorkTagFwd > ValueJoin ; + typedef Kokkos::Impl::if_c::value, + FunctorType, ReducerType> + ReducerConditional; + typedef typename ReducerConditional::type ReducerTypeFwd; + typedef + typename Kokkos::Impl::if_c::value, + WorkTag, void>::type WorkTagFwd; - typedef typename ValueTraits::pointer_type pointer_type ; - typedef typename ValueTraits::reference_type reference_type ; - typedef typename ValueTraits::value_type value_type ; + typedef Kokkos::Impl::FunctorValueTraits + ValueTraits; + typedef Kokkos::Impl::FunctorValueInit ValueInit; + typedef Kokkos::Impl::FunctorValueJoin ValueJoin; -public: + typedef typename ValueTraits::pointer_type pointer_type; + typedef typename ValueTraits::reference_type reference_type; + typedef typename ValueTraits::value_type value_type; - typedef FunctorType functor_type ; - typedef Cuda::size_type size_type ; + public: + typedef FunctorType functor_type; + typedef Cuda::size_type size_type; - enum { UseShflReduction = (true && (ValueTraits::StaticValueSize!=0)) }; + enum { UseShflReduction = (true && (ValueTraits::StaticValueSize != 0)) }; -private: + private: typedef double DummyShflReductionType; typedef int DummySHMEMReductionType; - // Algorithmic constraints: blockDim.y is a power of two AND blockDim.y == blockDim.z == 1 - // shared memory utilization: + // Algorithmic constraints: blockDim.y is a power of two AND blockDim.y == + // blockDim.z == 1 shared memory utilization: // // [ global reduce space ] // [ team reduce space ] // [ team shared space ] // - const FunctorType m_functor ; - const Policy m_policy ; - const ReducerType m_reducer ; - const pointer_type m_result_ptr ; - const bool m_result_ptr_device_accessible ; - size_type * m_scratch_space ; - size_type * m_scratch_flags ; - size_type * m_unified_space ; - size_type m_team_begin ; - size_type m_shmem_begin ; - size_type m_shmem_size ; - void* m_scratch_ptr[2] ; - int m_scratch_size[2] ; - const size_type m_league_size ; - int m_team_size ; - const size_type m_vector_size ; - - template< class TagType > + const FunctorType m_functor; + const Policy m_policy; + const ReducerType m_reducer; + const pointer_type m_result_ptr; + const bool m_result_ptr_device_accessible; + size_type* m_scratch_space; + size_type* m_scratch_flags; + size_type* m_unified_space; + size_type m_team_begin; + size_type m_shmem_begin; + size_type m_shmem_size; + void* m_scratch_ptr[2]; + int m_scratch_size[2]; + const size_type m_league_size; + int m_team_size; + const size_type m_vector_size; + + template __device__ inline - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec_team( const Member & member , reference_type update ) const - { m_functor( member , update ); } + typename std::enable_if::value>::type + exec_team(const Member& member, reference_type update) const { + m_functor(member, update); + } - template< class TagType > + template __device__ inline - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec_team( const Member & member , reference_type update ) const - { m_functor( TagType() , member , update ); } - -public: + typename std::enable_if::value>::type + exec_team(const Member& member, reference_type update) const { + m_functor(TagType(), member, update); + } - __device__ inline - void operator() () const { + public: + __device__ inline void operator()() const { int64_t threadid = 0; - if ( m_scratch_size[1]>0 ) { + if (m_scratch_size[1] > 0) { __shared__ int64_t base_thread_id; - if (threadIdx.x==0 && threadIdx.y==0 ) { - threadid = (blockIdx.x*blockDim.z + threadIdx.z) % - (Kokkos::Impl::g_device_cuda_lock_arrays.n / (blockDim.x * blockDim.y)); + if (threadIdx.x == 0 && threadIdx.y == 0) { + threadid = (blockIdx.x * blockDim.z + threadIdx.z) % + (Kokkos::Impl::g_device_cuda_lock_arrays.n / + (blockDim.x * blockDim.y)); threadid *= blockDim.x * blockDim.y; int done = 0; while (!done) { - done = (0 == atomicCAS(&Kokkos::Impl::g_device_cuda_lock_arrays.scratch[threadid],0,1)); - if(!done) { + done = + (0 == + atomicCAS( + &Kokkos::Impl::g_device_cuda_lock_arrays.scratch[threadid], + 0, 1)); + if (!done) { threadid += blockDim.x * blockDim.y; - if(int64_t(threadid + blockDim.x * blockDim.y) >= int64_t(Kokkos::Impl::g_device_cuda_lock_arrays.n)) threadid = 0; + if (int64_t(threadid + blockDim.x * blockDim.y) >= + int64_t(Kokkos::Impl::g_device_cuda_lock_arrays.n)) + threadid = 0; } } base_thread_id = threadid; @@ -1394,272 +1635,374 @@ public: threadid = base_thread_id; } - run(Kokkos::Impl::if_c::select(1,1.0), threadid ); - if ( m_scratch_size[1]>0 ) { + run(Kokkos::Impl::if_c::select(1, 1.0), + threadid); + if (m_scratch_size[1] > 0) { __syncthreads(); - if (threadIdx.x==0 && threadIdx.y==0 ) - Kokkos::Impl::g_device_cuda_lock_arrays.scratch[threadid]=0; + if (threadIdx.x == 0 && threadIdx.y == 0) + Kokkos::Impl::g_device_cuda_lock_arrays.scratch[threadid] = 0; } } - __device__ inline - void run(const DummySHMEMReductionType&, const int& threadid) const - { - const integral_nonzero_constant< size_type , ValueTraits::StaticValueSize / sizeof(size_type) > - word_count( ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ) / sizeof(size_type) ); + __device__ inline void run(const DummySHMEMReductionType&, + const int& threadid) const { + const integral_nonzero_constant + word_count(ValueTraits::value_size( + ReducerConditional::select(m_functor, m_reducer)) / + sizeof(size_type)); reference_type value = - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , kokkos_impl_cuda_shared_memory() + threadIdx.y * word_count.value ); + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), + kokkos_impl_cuda_shared_memory() + + threadIdx.y * word_count.value); // Iterate this block through the league const int int_league_size = (int)m_league_size; - for ( int league_rank = blockIdx.x ; league_rank < int_league_size ; league_rank += gridDim.x ) { - this-> template exec_team< WorkTag > - ( Member( kokkos_impl_cuda_shared_memory() + m_team_begin - , m_shmem_begin - , m_shmem_size - , (void*) ( ((char*)m_scratch_ptr[1]) + ptrdiff_t(threadid/(blockDim.x*blockDim.y)) * m_scratch_size[1]) - , m_scratch_size[1] - , league_rank - , m_league_size ) - , value ); + for (int league_rank = blockIdx.x; league_rank < int_league_size; + league_rank += gridDim.x) { + this->template exec_team( + Member(kokkos_impl_cuda_shared_memory() + m_team_begin, + m_shmem_begin, m_shmem_size, + (void*)(((char*)m_scratch_ptr[1]) + + ptrdiff_t(threadid / (blockDim.x * blockDim.y)) * + m_scratch_size[1]), + m_scratch_size[1], league_rank, m_league_size), + value); } // Reduce with final value at blockDim.y - 1 location. - if ( cuda_single_inter_block_reduce_scan( - ReducerConditional::select(m_functor , m_reducer) , blockIdx.x , gridDim.x , - kokkos_impl_cuda_shared_memory() , m_scratch_space , m_scratch_flags ) ) { - - // This is the final block with the final result at the final threads' location - - size_type * const shared = kokkos_impl_cuda_shared_memory() + ( blockDim.y - 1 ) * word_count.value ; - size_type * const global = m_result_ptr_device_accessible? reinterpret_cast(m_result_ptr) : - ( m_unified_space ? m_unified_space : m_scratch_space ); - - if ( threadIdx.y == 0 ) { - Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTagFwd >::final( ReducerConditional::select(m_functor , m_reducer) , shared ); + if (cuda_single_inter_block_reduce_scan( + ReducerConditional::select(m_functor, m_reducer), blockIdx.x, + gridDim.x, kokkos_impl_cuda_shared_memory(), + m_scratch_space, m_scratch_flags)) { + // This is the final block with the final result at the final threads' + // location + + size_type* const shared = kokkos_impl_cuda_shared_memory() + + (blockDim.y - 1) * word_count.value; + size_type* const global = + m_result_ptr_device_accessible + ? reinterpret_cast(m_result_ptr) + : (m_unified_space ? m_unified_space : m_scratch_space); + + if (threadIdx.y == 0) { + Kokkos::Impl::FunctorFinal::final( + ReducerConditional::select(m_functor, m_reducer), shared); } - if ( CudaTraits::WarpSize < word_count.value ) { __syncthreads(); } + if (CudaTraits::WarpSize < word_count.value) { + __syncthreads(); + } - for ( unsigned i = threadIdx.y ; i < word_count.value ; i += blockDim.y ) { global[i] = shared[i]; } + for (unsigned i = threadIdx.y; i < word_count.value; i += blockDim.y) { + global[i] = shared[i]; + } } - } - __device__ inline - void run(const DummyShflReductionType&, const int& threadid) const - { + __device__ inline void run(const DummyShflReductionType&, + const int& threadid) const { value_type value; - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , &value); + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), &value); // Iterate this block through the league const int int_league_size = (int)m_league_size; - for ( int league_rank = blockIdx.x ; league_rank < int_league_size ; league_rank += gridDim.x ) { - this-> template exec_team< WorkTag > - ( Member( kokkos_impl_cuda_shared_memory() + m_team_begin - , m_shmem_begin - , m_shmem_size - , (void*) ( ((char*)m_scratch_ptr[1]) + ptrdiff_t(threadid/(blockDim.x*blockDim.y)) * m_scratch_size[1]) - , m_scratch_size[1] - , league_rank - , m_league_size ) - , value ); - } - - pointer_type const result = m_result_ptr_device_accessible? m_result_ptr : - (pointer_type) ( m_unified_space ? m_unified_space : m_scratch_space ); + for (int league_rank = blockIdx.x; league_rank < int_league_size; + league_rank += gridDim.x) { + this->template exec_team( + Member(kokkos_impl_cuda_shared_memory() + m_team_begin, + m_shmem_begin, m_shmem_size, + (void*)(((char*)m_scratch_ptr[1]) + + ptrdiff_t(threadid / (blockDim.x * blockDim.y)) * + m_scratch_size[1]), + m_scratch_size[1], league_rank, m_league_size), + value); + } + + pointer_type const result = + m_result_ptr_device_accessible + ? m_result_ptr + : (pointer_type)(m_unified_space ? m_unified_space + : m_scratch_space); value_type init; - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , &init); - if( - Impl::cuda_inter_block_reduction - (value,init,ValueJoin(ReducerConditional::select(m_functor , m_reducer)),m_scratch_space,result,m_scratch_flags,blockDim.y) - //This breaks a test - // Kokkos::Impl::CudaReductionsFunctor::scalar_inter_block_reduction(ReducerConditional::select(m_functor , m_reducer) , blockIdx.x , gridDim.x , - // kokkos_impl_cuda_shared_memory() , m_scratch_space , m_scratch_flags) + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), &init); + if (Impl::cuda_inter_block_reduction( + value, init, + ValueJoin(ReducerConditional::select(m_functor, m_reducer)), + m_scratch_space, result, m_scratch_flags, blockDim.y) + // This breaks a test + // Kokkos::Impl::CudaReductionsFunctor::scalar_inter_block_reduction(ReducerConditional::select(m_functor + // , m_reducer) , blockIdx.x , gridDim.x , + // kokkos_impl_cuda_shared_memory() , + // m_scratch_space , m_scratch_flags) ) { - const unsigned id = threadIdx.y*blockDim.x + threadIdx.x; - if(id==0) { - Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTagFwd >::final( ReducerConditional::select(m_functor , m_reducer) , (void*) &value ); + const unsigned id = threadIdx.y * blockDim.x + threadIdx.x; + if (id == 0) { + Kokkos::Impl::FunctorFinal::final( + ReducerConditional::select(m_functor, m_reducer), (void*)&value); *result = value; } } } - inline - void execute() - { - const int nwork = m_league_size * m_team_size ; - if ( nwork ) { - const int block_count = UseShflReduction? std::min( m_league_size , size_type(1024*32) ) - :std::min( int(m_league_size) , m_team_size ); - - m_scratch_space = cuda_internal_scratch_space(m_policy.space(), ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ) * block_count ); - m_scratch_flags = cuda_internal_scratch_flags(m_policy.space(), sizeof(size_type) ); - m_unified_space = cuda_internal_scratch_unified( m_policy.space(),ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ) ); - - const dim3 block( m_vector_size , m_team_size , 1 ); - const dim3 grid( block_count , 1 , 1 ); - const int shmem_size_total = m_team_begin + m_shmem_begin + m_shmem_size ; + inline void execute() { + const int nwork = m_league_size * m_team_size; + if (nwork) { + const int block_count = + UseShflReduction ? std::min(m_league_size, size_type(1024 * 32)) + : std::min(int(m_league_size), m_team_size); + + m_scratch_space = cuda_internal_scratch_space( + m_policy.space(), ValueTraits::value_size(ReducerConditional::select( + m_functor, m_reducer)) * + block_count); + m_scratch_flags = + cuda_internal_scratch_flags(m_policy.space(), sizeof(size_type)); + m_unified_space = cuda_internal_scratch_unified( + m_policy.space(), ValueTraits::value_size(ReducerConditional::select( + m_functor, m_reducer))); + + dim3 block(m_vector_size, m_team_size, 1); + dim3 grid(block_count, 1, 1); + const int shmem_size_total = m_team_begin + m_shmem_begin + m_shmem_size; + +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + if (Kokkos::Impl::CudaInternal::cuda_use_serial_execution()) { + block = dim3(1, 1, 1); + grid = dim3(1, 1, 1); + } +#endif - CudaParallelLaunch< ParallelReduce, LaunchBounds >( *this, grid, block, shmem_size_total , m_policy.space().impl_internal_space_instance() , true ); // copy to device and execute + CudaParallelLaunch( + *this, grid, block, shmem_size_total, + m_policy.space().impl_internal_space_instance(), + true); // copy to device and execute - if(!m_result_ptr_device_accessible) { - Cuda().fence(); + if (!m_result_ptr_device_accessible) { + Cuda().fence(); - if ( m_result_ptr ) { - if ( m_unified_space ) { - const int count = ValueTraits::value_count( ReducerConditional::select(m_functor , m_reducer) ); - for ( int i = 0 ; i < count ; ++i ) { m_result_ptr[i] = pointer_type(m_unified_space)[i] ; } - } - else { - const int size = ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ); - DeepCopy( m_result_ptr, m_scratch_space, size ); + if (m_result_ptr) { + if (m_unified_space) { + const int count = ValueTraits::value_count( + ReducerConditional::select(m_functor, m_reducer)); + for (int i = 0; i < count; ++i) { + m_result_ptr[i] = pointer_type(m_unified_space)[i]; } + } else { + const int size = ValueTraits::value_size( + ReducerConditional::select(m_functor, m_reducer)); + DeepCopy(m_result_ptr, m_scratch_space, size); } } } - else { - if (m_result_ptr) { - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , m_result_ptr ); - } + } else { + if (m_result_ptr) { + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), + m_result_ptr); } } + } - template< class ViewType > - ParallelReduce( const FunctorType & arg_functor - , const Policy & arg_policy - , const ViewType & arg_result - , typename std::enable_if< - Kokkos::is_view< ViewType >::value - ,void*>::type = NULL) - : m_functor( arg_functor ) - , m_policy ( arg_policy ) - , m_reducer( InvalidType() ) - , m_result_ptr( arg_result.data() ) - , m_result_ptr_device_accessible(MemorySpaceAccess< Kokkos::CudaSpace , typename ViewType::memory_space>::accessible ) - , m_scratch_space( 0 ) - , m_scratch_flags( 0 ) - , m_unified_space( 0 ) - , m_team_begin( 0 ) - , m_shmem_begin( 0 ) - , m_shmem_size( 0 ) - , m_scratch_ptr{NULL,NULL} - , m_league_size( arg_policy.league_size() ) - , m_team_size( arg_policy.team_size() ) - , m_vector_size( arg_policy.vector_length() ) - { - cudaFuncAttributes attr = CudaParallelLaunch< ParallelReduce, LaunchBounds >:: - get_cuda_func_attributes(); - m_team_size = m_team_size>=0?m_team_size: - Kokkos::Impl::cuda_get_opt_block_size< FunctorType, LaunchBounds>( - m_policy.space().impl_internal_space_instance(), - attr, m_functor , m_vector_size, - m_policy.team_scratch_size(0), m_policy.thread_scratch_size(0) )/m_vector_size; + template + ParallelReduce(const FunctorType& arg_functor, const Policy& arg_policy, + const ViewType& arg_result, + typename std::enable_if::value, + void*>::type = NULL) + : m_functor(arg_functor), + m_policy(arg_policy), + m_reducer(InvalidType()), + m_result_ptr(arg_result.data()), + m_result_ptr_device_accessible( + MemorySpaceAccess::accessible), + m_scratch_space(0), + m_scratch_flags(0), + m_unified_space(0), + m_team_begin(0), + m_shmem_begin(0), + m_shmem_size(0), + m_scratch_ptr{NULL, NULL}, + m_league_size(arg_policy.league_size()), + m_team_size(arg_policy.team_size()), + m_vector_size(arg_policy.vector_length()) { + cudaFuncAttributes attr = + CudaParallelLaunch::get_cuda_func_attributes(); + m_team_size = + m_team_size >= 0 + ? m_team_size + : Kokkos::Impl::cuda_get_opt_block_size( + m_policy.space().impl_internal_space_instance(), attr, + m_functor, m_vector_size, m_policy.team_scratch_size(0), + m_policy.thread_scratch_size(0)) / + m_vector_size; // Return Init value if the number of worksets is zero - if( m_league_size*m_team_size == 0) { - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , arg_result.data() ); - return ; - } - - m_team_begin = UseShflReduction?0:cuda_single_inter_block_reduce_scan_shmem( arg_functor , m_team_size ); - m_shmem_begin = sizeof(double) * ( m_team_size + 2 ); - m_shmem_size = m_policy.scratch_size(0,m_team_size) + FunctorTeamShmemSize< FunctorType >::value( arg_functor , m_team_size ); + if (m_league_size * m_team_size == 0) { + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), + arg_result.data()); + return; + } + + m_team_begin = + UseShflReduction + ? 0 + : cuda_single_inter_block_reduce_scan_shmem(arg_functor, + m_team_size); + m_shmem_begin = sizeof(double) * (m_team_size + 2); + m_shmem_size = + m_policy.scratch_size(0, m_team_size) + + FunctorTeamShmemSize::value(arg_functor, m_team_size); m_scratch_size[0] = m_shmem_size; - m_scratch_size[1] = m_policy.scratch_size(1,m_team_size); - m_scratch_ptr[1] = m_team_size<=0?NULL:cuda_resize_scratch_space(static_cast(m_scratch_size[1])*(static_cast(Cuda::concurrency()/(m_team_size*m_vector_size)))); - - // The global parallel_reduce does not support vector_length other than 1 at the moment - if( (arg_policy.vector_length() > 1) && !UseShflReduction ) - Impl::throw_runtime_exception( "Kokkos::parallel_reduce with a TeamPolicy using a vector length of greater than 1 is not currently supported for CUDA for dynamic sized reduction types."); - - if( (m_team_size < 32) && !UseShflReduction ) - Impl::throw_runtime_exception( "Kokkos::parallel_reduce with a TeamPolicy using a team_size smaller than 32 is not currently supported with CUDA for dynamic sized reduction types."); - - // Functor's reduce memory, team scan memory, and team shared memory depend upon team size. - - const int shmem_size_total = m_team_begin + m_shmem_begin + m_shmem_size ; - - if (! Kokkos::Impl::is_integral_power_of_two( m_team_size ) && !UseShflReduction ) { - Kokkos::Impl::throw_runtime_exception(std::string("Kokkos::Impl::ParallelReduce< Cuda > bad team size")); - } - - if ( m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock < shmem_size_total ) { - Kokkos::Impl::throw_runtime_exception(std::string("Kokkos::Impl::ParallelReduce< Cuda > requested too much L0 scratch memory")); - } - - if ( int(m_team_size) > arg_policy.team_size_max(m_functor,ParallelReduceTag()) ) { - Kokkos::Impl::throw_runtime_exception(std::string("Kokkos::Impl::ParallelReduce< Cuda > requested too large team size.")); + m_scratch_size[1] = m_policy.scratch_size(1, m_team_size); + m_scratch_ptr[1] = + m_team_size <= 0 + ? NULL + : cuda_resize_scratch_space( + static_cast(m_scratch_size[1]) * + (static_cast(Cuda::concurrency() / + (m_team_size * m_vector_size)))); + + // The global parallel_reduce does not support vector_length other than 1 at + // the moment + if ((arg_policy.vector_length() > 1) && !UseShflReduction) + Impl::throw_runtime_exception( + "Kokkos::parallel_reduce with a TeamPolicy using a vector length of " + "greater than 1 is not currently supported for CUDA for dynamic " + "sized reduction types."); + + if ((m_team_size < 32) && !UseShflReduction) + Impl::throw_runtime_exception( + "Kokkos::parallel_reduce with a TeamPolicy using a team_size smaller " + "than 32 is not currently supported with CUDA for dynamic sized " + "reduction types."); + + // Functor's reduce memory, team scan memory, and team shared memory depend + // upon team size. + + const int shmem_size_total = m_team_begin + m_shmem_begin + m_shmem_size; + + if (!Kokkos::Impl::is_integral_power_of_two(m_team_size) && + !UseShflReduction) { + Kokkos::Impl::throw_runtime_exception( + std::string("Kokkos::Impl::ParallelReduce< Cuda > bad team size")); + } + + if (m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock < + shmem_size_total) { + Kokkos::Impl::throw_runtime_exception( + std::string("Kokkos::Impl::ParallelReduce< Cuda > requested too much " + "L0 scratch memory")); + } + + if (int(m_team_size) > + arg_policy.team_size_max(m_functor, m_reducer, ParallelReduceTag())) { + Kokkos::Impl::throw_runtime_exception( + std::string("Kokkos::Impl::ParallelReduce< Cuda > requested too " + "large team size.")); } - } - ParallelReduce( const FunctorType & arg_functor - , const Policy & arg_policy - , const ReducerType & reducer) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - , m_reducer( reducer ) - , m_result_ptr( reducer.view().data() ) - , m_result_ptr_device_accessible(MemorySpaceAccess< Kokkos::CudaSpace , typename ReducerType::result_view_type::memory_space>::accessible ) - , m_scratch_space( 0 ) - , m_scratch_flags( 0 ) - , m_unified_space( 0 ) - , m_team_begin( 0 ) - , m_shmem_begin( 0 ) - , m_shmem_size( 0 ) - , m_scratch_ptr{NULL,NULL} - , m_league_size( arg_policy.league_size() ) - , m_team_size( arg_policy.team_size() ) - , m_vector_size( arg_policy.vector_length() ) - { - cudaFuncAttributes attr = CudaParallelLaunch< ParallelReduce, LaunchBounds >:: - get_cuda_func_attributes(); - m_team_size = m_team_size>=0?m_team_size: - Kokkos::Impl::cuda_get_opt_block_size< FunctorType, LaunchBounds>( - m_policy.space().impl_internal_space_instance(), - attr, m_functor , m_vector_size, - m_policy.team_scratch_size(0), m_policy.thread_scratch_size(0) )/m_vector_size; + ParallelReduce(const FunctorType& arg_functor, const Policy& arg_policy, + const ReducerType& reducer) + : m_functor(arg_functor), + m_policy(arg_policy), + m_reducer(reducer), + m_result_ptr(reducer.view().data()), + m_result_ptr_device_accessible( + MemorySpaceAccess::accessible), + m_scratch_space(0), + m_scratch_flags(0), + m_unified_space(0), + m_team_begin(0), + m_shmem_begin(0), + m_shmem_size(0), + m_scratch_ptr{NULL, NULL}, + m_league_size(arg_policy.league_size()), + m_team_size(arg_policy.team_size()), + m_vector_size(arg_policy.vector_length()) { + cudaFuncAttributes attr = + CudaParallelLaunch::get_cuda_func_attributes(); + m_team_size = + m_team_size >= 0 + ? m_team_size + : Kokkos::Impl::cuda_get_opt_block_size( + m_policy.space().impl_internal_space_instance(), attr, + m_functor, m_vector_size, m_policy.team_scratch_size(0), + m_policy.thread_scratch_size(0)) / + m_vector_size; // Return Init value if the number of worksets is zero - if( arg_policy.league_size() == 0) { - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , m_result_ptr ); - return ; - } - - m_team_begin = UseShflReduction?0:cuda_single_inter_block_reduce_scan_shmem( arg_functor , m_team_size ); - m_shmem_begin = sizeof(double) * ( m_team_size + 2 ); - m_shmem_size = m_policy.scratch_size(0,m_team_size) + FunctorTeamShmemSize< FunctorType >::value( arg_functor , m_team_size ); + if (arg_policy.league_size() == 0) { + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), + m_result_ptr); + return; + } + + m_team_begin = + UseShflReduction + ? 0 + : cuda_single_inter_block_reduce_scan_shmem(arg_functor, + m_team_size); + m_shmem_begin = sizeof(double) * (m_team_size + 2); + m_shmem_size = + m_policy.scratch_size(0, m_team_size) + + FunctorTeamShmemSize::value(arg_functor, m_team_size); m_scratch_size[0] = m_shmem_size; - m_scratch_size[1] = m_policy.scratch_size(1,m_team_size); - m_scratch_ptr[1] = m_team_size<=0?NULL:cuda_resize_scratch_space(static_cast(m_scratch_size[1])*static_cast(Cuda::concurrency()/(m_team_size*m_vector_size))); - - // The global parallel_reduce does not support vector_length other than 1 at the moment - if( (arg_policy.vector_length() > 1) && !UseShflReduction ) - Impl::throw_runtime_exception( "Kokkos::parallel_reduce with a TeamPolicy using a vector length of greater than 1 is not currently supported for CUDA for dynamic sized reduction types."); - - if( (m_team_size < 32) && !UseShflReduction ) - Impl::throw_runtime_exception( "Kokkos::parallel_reduce with a TeamPolicy using a team_size smaller than 32 is not currently supported with CUDA for dynamic sized reduction types."); - - // Functor's reduce memory, team scan memory, and team shared memory depend upon team size. - - const int shmem_size_total = m_team_begin + m_shmem_begin + m_shmem_size ; - - if ( (! Kokkos::Impl::is_integral_power_of_two( m_team_size ) && !UseShflReduction ) || - m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock < shmem_size_total ) { - Kokkos::Impl::throw_runtime_exception(std::string("Kokkos::Impl::ParallelReduce< Cuda > bad team size")); + m_scratch_size[1] = m_policy.scratch_size(1, m_team_size); + m_scratch_ptr[1] = + m_team_size <= 0 + ? NULL + : cuda_resize_scratch_space( + static_cast(m_scratch_size[1]) * + static_cast(Cuda::concurrency() / + (m_team_size * m_vector_size))); + + // The global parallel_reduce does not support vector_length other than 1 at + // the moment + if ((arg_policy.vector_length() > 1) && !UseShflReduction) + Impl::throw_runtime_exception( + "Kokkos::parallel_reduce with a TeamPolicy using a vector length of " + "greater than 1 is not currently supported for CUDA for dynamic " + "sized reduction types."); + + if ((m_team_size < 32) && !UseShflReduction) + Impl::throw_runtime_exception( + "Kokkos::parallel_reduce with a TeamPolicy using a team_size smaller " + "than 32 is not currently supported with CUDA for dynamic sized " + "reduction types."); + + // Functor's reduce memory, team scan memory, and team shared memory depend + // upon team size. + + const int shmem_size_total = m_team_begin + m_shmem_begin + m_shmem_size; + + if ((!Kokkos::Impl::is_integral_power_of_two(m_team_size) && + !UseShflReduction) || + m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock < + shmem_size_total) { + Kokkos::Impl::throw_runtime_exception( + std::string("Kokkos::Impl::ParallelReduce< Cuda > bad team size")); + } + if (int(m_team_size) > + arg_policy.team_size_max(m_functor, m_reducer, ParallelReduceTag())) { + Kokkos::Impl::throw_runtime_exception( + std::string("Kokkos::Impl::ParallelReduce< Cuda > requested too " + "large team size.")); } - if ( int(m_team_size) > arg_policy.team_size_max(m_functor,ParallelReduceTag()) ) { - Kokkos::Impl::throw_runtime_exception(std::string("Kokkos::Impl::ParallelReduce< Cuda > requested too large team size.")); - } - } }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -1667,463 +2010,595 @@ public: namespace Kokkos { namespace Impl { -template< class FunctorType , class ... Traits > -class ParallelScan< FunctorType - , Kokkos::RangePolicy< Traits ... > - , Kokkos::Cuda - > -{ -public: - typedef Kokkos::RangePolicy< Traits ... > Policy ; -private: - typedef typename Policy::member_type Member ; - typedef typename Policy::work_tag WorkTag ; - typedef typename Policy::WorkRange WorkRange ; - typedef typename Policy::launch_bounds LaunchBounds ; - - typedef Kokkos::Impl::FunctorValueTraits< FunctorType, WorkTag > ValueTraits ; - typedef Kokkos::Impl::FunctorValueInit< FunctorType, WorkTag > ValueInit ; - typedef Kokkos::Impl::FunctorValueOps< FunctorType, WorkTag > ValueOps ; - -public: - - typedef typename ValueTraits::pointer_type pointer_type ; - typedef typename ValueTraits::reference_type reference_type ; - typedef FunctorType functor_type ; - typedef Cuda::size_type size_type ; - -private: +template +class ParallelScan, Kokkos::Cuda> { + public: + typedef Kokkos::RangePolicy Policy; + + private: + typedef typename Policy::member_type Member; + typedef typename Policy::work_tag WorkTag; + typedef typename Policy::WorkRange WorkRange; + typedef typename Policy::launch_bounds LaunchBounds; + + typedef Kokkos::Impl::FunctorValueTraits ValueTraits; + typedef Kokkos::Impl::FunctorValueInit ValueInit; + typedef Kokkos::Impl::FunctorValueOps ValueOps; + + public: + typedef typename ValueTraits::pointer_type pointer_type; + typedef typename ValueTraits::reference_type reference_type; + typedef FunctorType functor_type; + typedef Cuda::size_type size_type; + private: // Algorithmic constraints: // (a) blockDim.y is a power of two // (b) blockDim.y == blockDim.z == 1 // (c) gridDim.x <= blockDim.y * blockDim.y // (d) gridDim.y == gridDim.z == 1 - const FunctorType m_functor ; - const Policy m_policy ; - size_type * m_scratch_space ; - size_type * m_scratch_flags ; - size_type m_final ; + const FunctorType m_functor; + const Policy m_policy; + size_type* m_scratch_space; + size_type* m_scratch_flags; + size_type m_final; +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + bool m_run_serial; +#endif - template< class TagType > + template __device__ inline - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec_range( const Member & i , reference_type update , const bool final_result ) const - { m_functor( i , update , final_result ); } + typename std::enable_if::value>::type + exec_range(const Member& i, reference_type update, + const bool final_result) const { + m_functor(i, update, final_result); + } - template< class TagType > + template __device__ inline - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec_range( const Member & i , reference_type update , const bool final_result ) const - { m_functor( TagType() , i , update , final_result ); } + typename std::enable_if::value>::type + exec_range(const Member& i, reference_type update, + const bool final_result) const { + m_functor(TagType(), i, update, final_result); + } //---------------------------------------- - __device__ inline - void initial(void) const - { - const integral_nonzero_constant< size_type , ValueTraits::StaticValueSize / sizeof(size_type) > - word_count( ValueTraits::value_size( m_functor ) / sizeof(size_type) ); + __device__ inline void initial(void) const { + const integral_nonzero_constant + word_count(ValueTraits::value_size(m_functor) / sizeof(size_type)); - size_type * const shared_value = kokkos_impl_cuda_shared_memory() + word_count.value * threadIdx.y ; + size_type* const shared_value = + kokkos_impl_cuda_shared_memory() + + word_count.value * threadIdx.y; - ValueInit::init( m_functor , shared_value ); + ValueInit::init(m_functor, shared_value); - // Number of blocks is bounded so that the reduction can be limited to two passes. - // Each thread block is given an approximately equal amount of work to perform. - // Accumulate the values for this block. - // The accumulation ordering does not match the final pass, but is arithmatically equivalent. + // Number of blocks is bounded so that the reduction can be limited to two + // passes. Each thread block is given an approximately equal amount of work + // to perform. Accumulate the values for this block. The accumulation + // ordering does not match the final pass, but is arithmatically equivalent. - const WorkRange range( m_policy , blockIdx.x , gridDim.x ); + const WorkRange range(m_policy, blockIdx.x, gridDim.x); - for ( Member iwork = range.begin() + threadIdx.y , iwork_end = range.end() ; - iwork < iwork_end ; iwork += blockDim.y ) { - this-> template exec_range< WorkTag >( iwork , ValueOps::reference( shared_value ) , false ); + for (Member iwork = range.begin() + threadIdx.y, iwork_end = range.end(); + iwork < iwork_end; iwork += blockDim.y) { + this->template exec_range( + iwork, ValueOps::reference(shared_value), false); } - // Reduce and scan, writing out scan of blocks' totals and block-groups' totals. - // Blocks' scan values are written to 'blockIdx.x' location. - // Block-groups' scan values are at: i = ( j * blockDim.y - 1 ) for i < gridDim.x - cuda_single_inter_block_reduce_scan( m_functor , blockIdx.x , gridDim.x , kokkos_impl_cuda_shared_memory() , m_scratch_space , m_scratch_flags ); + // Reduce and scan, writing out scan of blocks' totals and block-groups' + // totals. Blocks' scan values are written to 'blockIdx.x' location. + // Block-groups' scan values are at: i = ( j * blockDim.y - 1 ) for i < + // gridDim.x + cuda_single_inter_block_reduce_scan( + m_functor, blockIdx.x, gridDim.x, + kokkos_impl_cuda_shared_memory(), m_scratch_space, + m_scratch_flags); } //---------------------------------------- - __device__ inline - void final(void) const - { - const integral_nonzero_constant< size_type , ValueTraits::StaticValueSize / sizeof(size_type) > - word_count( ValueTraits::value_size( m_functor ) / sizeof(size_type) ); + __device__ inline void final(void) const { + const integral_nonzero_constant + word_count(ValueTraits::value_size(m_functor) / sizeof(size_type)); - // Use shared memory as an exclusive scan: { 0 , value[0] , value[1] , value[2] , ... } - size_type * const shared_data = kokkos_impl_cuda_shared_memory(); - size_type * const shared_prefix = shared_data + word_count.value * threadIdx.y ; - size_type * const shared_accum = shared_data + word_count.value * ( blockDim.y + 1 ); + // Use shared memory as an exclusive scan: { 0 , value[0] , value[1] , + // value[2] , ... } + size_type* const shared_data = kokkos_impl_cuda_shared_memory(); + size_type* const shared_prefix = + shared_data + word_count.value * threadIdx.y; + size_type* const shared_accum = + shared_data + word_count.value * (blockDim.y + 1); // Starting value for this thread block is the previous block's total. - if ( blockIdx.x ) { - size_type * const block_total = m_scratch_space + word_count.value * ( blockIdx.x - 1 ); - for ( unsigned i = threadIdx.y ; i < word_count.value ; ++i ) { shared_accum[i] = block_total[i] ; } - } - else if ( 0 == threadIdx.y ) { - ValueInit::init( m_functor , shared_accum ); + if (blockIdx.x) { + size_type* const block_total = + m_scratch_space + word_count.value * (blockIdx.x - 1); + for (unsigned i = threadIdx.y; i < word_count.value; ++i) { + shared_accum[i] = block_total[i]; + } + } else if (0 == threadIdx.y) { + ValueInit::init(m_functor, shared_accum); } - const WorkRange range( m_policy , blockIdx.x , gridDim.x ); + const WorkRange range(m_policy, blockIdx.x, gridDim.x); - for ( typename Policy::member_type iwork_base = range.begin(); iwork_base < range.end() ; iwork_base += blockDim.y ) { - #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - unsigned MASK=KOKKOS_IMPL_CUDA_ACTIVEMASK; - #endif - const typename Policy::member_type iwork = iwork_base + threadIdx.y ; + for (typename Policy::member_type iwork_base = range.begin(); + iwork_base < range.end(); iwork_base += blockDim.y) { +#ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK + unsigned MASK = KOKKOS_IMPL_CUDA_ACTIVEMASK; +#endif + const typename Policy::member_type iwork = iwork_base + threadIdx.y; - __syncthreads(); // Don't overwrite previous iteration values until they are used + __syncthreads(); // Don't overwrite previous iteration values until they + // are used - ValueInit::init( m_functor , shared_prefix + word_count.value ); + ValueInit::init(m_functor, shared_prefix + word_count.value); - // Copy previous block's accumulation total into thread[0] prefix and inclusive scan value of this block - for ( unsigned i = threadIdx.y ; i < word_count.value ; ++i ) { - shared_data[i + word_count.value] = shared_data[i] = shared_accum[i] ; + // Copy previous block's accumulation total into thread[0] prefix and + // inclusive scan value of this block + for (unsigned i = threadIdx.y; i < word_count.value; ++i) { + shared_data[i + word_count.value] = shared_data[i] = shared_accum[i]; } - #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK +#ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK KOKKOS_IMPL_CUDA_SYNCWARP_MASK(MASK); - #else +#else KOKKOS_IMPL_CUDA_SYNCWARP; - #endif - if ( CudaTraits::WarpSize < word_count.value ) { __syncthreads(); } // Protect against large scan values. +#endif + if (CudaTraits::WarpSize < word_count.value) { + __syncthreads(); + } // Protect against large scan values. // Call functor to accumulate inclusive scan value for this work item - if ( iwork < range.end() ) { - this-> template exec_range< WorkTag >( iwork , ValueOps::reference( shared_prefix + word_count.value ) , false ); + if (iwork < range.end()) { + this->template exec_range( + iwork, ValueOps::reference(shared_prefix + word_count.value), + false); } // Scan block values into locations shared_data[1..blockDim.y] - cuda_intra_block_reduce_scan( m_functor , typename ValueTraits::pointer_type(shared_data+word_count.value) ); + cuda_intra_block_reduce_scan( + m_functor, + typename ValueTraits::pointer_type(shared_data + word_count.value)); { - size_type * const block_total = shared_data + word_count.value * blockDim.y ; - for ( unsigned i = threadIdx.y ; i < word_count.value ; ++i ) { shared_accum[i] = block_total[i]; } + size_type* const block_total = + shared_data + word_count.value * blockDim.y; + for (unsigned i = threadIdx.y; i < word_count.value; ++i) { + shared_accum[i] = block_total[i]; + } } // Call functor with exclusive scan value - if ( iwork < range.end() ) { - this-> template exec_range< WorkTag >( iwork , ValueOps::reference( shared_prefix ) , true ); + if (iwork < range.end()) { + this->template exec_range( + iwork, ValueOps::reference(shared_prefix), true); } } } -public: - + public: //---------------------------------------- - __device__ inline - void operator()(void) const - { - if ( ! m_final ) { - initial(); - } - else { - final(); + __device__ inline void operator()(void) const { +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + if (m_run_serial) { + typename ValueTraits::value_type value; + ValueInit::init(m_functor, (void*)&value); + const WorkRange range(m_policy, blockIdx.x, gridDim.x); + + for (typename Policy::member_type iwork_base = range.begin(); + iwork_base < range.end(); iwork_base++) { + this->template exec_range(iwork_base, value, true); + } + } else { +#endif + if (!m_final) { + initial(); + } else { + final(); + } +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION } +#endif } // Determine block size constrained by shared memory: - inline - unsigned local_block_size( const FunctorType & f ) - { - // blockDim.y must be power of two = 128 (4 warps) or 256 (8 warps) or 512 (16 warps) - // gridDim.x <= blockDim.y * blockDim.y - // - // 4 warps was 10% faster than 8 warps and 20% faster than 16 warps in unit testing - - unsigned n = CudaTraits::WarpSize * 4 ; - while ( n && unsigned(m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock) < cuda_single_inter_block_reduce_scan_shmem( f , n ) ) { n >>= 1 ; } - return n ; - } - - inline - void execute() - { - const int nwork = m_policy.end() - m_policy.begin(); - if ( nwork ) { - enum { GridMaxComputeCapability_2x = 0x0ffff }; + inline unsigned local_block_size(const FunctorType& f) { + // blockDim.y must be power of two = 128 (4 warps) or 256 (8 warps) or 512 + // (16 warps) gridDim.x <= blockDim.y * blockDim.y + // + // 4 warps was 10% faster than 8 warps and 20% faster than 16 warps in unit + // testing + + unsigned n = CudaTraits::WarpSize * 4; + while (n && + unsigned(m_policy.space() + .impl_internal_space_instance() + ->m_maxShmemPerBlock) < + cuda_single_inter_block_reduce_scan_shmem(f, n)) { + n >>= 1; + } + return n; + } - const int block_size = local_block_size( m_functor ); + inline void execute() { + const int nwork = m_policy.end() - m_policy.begin(); + if (nwork) { + enum { GridMaxComputeCapability_2x = 0x0ffff }; - const int grid_max = - ( block_size * block_size ) < GridMaxComputeCapability_2x ? - ( block_size * block_size ) : GridMaxComputeCapability_2x ; + const int block_size = local_block_size(m_functor); - // At most 'max_grid' blocks: - const int max_grid = std::min( int(grid_max) , int(( nwork + block_size - 1 ) / block_size )); + const int grid_max = + (block_size * block_size) < GridMaxComputeCapability_2x + ? (block_size * block_size) + : GridMaxComputeCapability_2x; - // How much work per block: - const int work_per_block = ( nwork + max_grid - 1 ) / max_grid ; + // At most 'max_grid' blocks: + const int max_grid = + std::min(int(grid_max), int((nwork + block_size - 1) / block_size)); - // How many block are really needed for this much work: - const int grid_x = ( nwork + work_per_block - 1 ) / work_per_block ; + // How much work per block: + const int work_per_block = (nwork + max_grid - 1) / max_grid; - m_scratch_space = cuda_internal_scratch_space( m_policy.space(), ValueTraits::value_size( m_functor ) * grid_x ); - m_scratch_flags = cuda_internal_scratch_flags( m_policy.space(), sizeof(size_type) * 1 ); + // How many block are really needed for this much work: + const int grid_x = (nwork + work_per_block - 1) / work_per_block; - const dim3 grid( grid_x , 1 , 1 ); - const dim3 block( 1 , block_size , 1 ); // REQUIRED DIMENSIONS ( 1 , N , 1 ) - const int shmem = ValueTraits::value_size( m_functor ) * ( block_size + 2 ); + m_scratch_space = cuda_internal_scratch_space( + m_policy.space(), ValueTraits::value_size(m_functor) * grid_x); + m_scratch_flags = + cuda_internal_scratch_flags(m_policy.space(), sizeof(size_type) * 1); - m_final = false ; - CudaParallelLaunch< ParallelScan, LaunchBounds >( *this, grid, block, shmem , m_policy.space().impl_internal_space_instance() , false ); // copy to device and execute + dim3 grid(grid_x, 1, 1); + dim3 block(1, block_size, 1); // REQUIRED DIMENSIONS ( 1 , N , 1 ) + const int shmem = ValueTraits::value_size(m_functor) * (block_size + 2); - m_final = true ; - CudaParallelLaunch< ParallelScan, LaunchBounds >( *this, grid, block, shmem , m_policy.space().impl_internal_space_instance() , false ); // copy to device and execute +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + if (m_run_serial) { + block = dim3(1, 1, 1); + grid = dim3(1, 1, 1); + } else { +#endif + m_final = false; + CudaParallelLaunch( + *this, grid, block, shmem, + m_policy.space().impl_internal_space_instance(), + false); // copy to device and execute +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION } +#endif + m_final = true; + CudaParallelLaunch( + *this, grid, block, shmem, + m_policy.space().impl_internal_space_instance(), + false); // copy to device and execute } + } - ParallelScan( const FunctorType & arg_functor , - const Policy & arg_policy ) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - , m_scratch_space( 0 ) - , m_scratch_flags( 0 ) - , m_final( false ) - { } + ParallelScan(const FunctorType& arg_functor, const Policy& arg_policy) + : m_functor(arg_functor), + m_policy(arg_policy), + m_scratch_space(0), + m_scratch_flags(0), + m_final(false) +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + , + m_run_serial(Kokkos::Impl::CudaInternal::cuda_use_serial_execution()) +#endif + { + } }; //---------------------------------------------------------------------------- -template< class FunctorType, class ReturnType, class ... Traits > -class ParallelScanWithTotal< FunctorType - , Kokkos::RangePolicy< Traits ... > - , ReturnType - , Kokkos::Cuda - > -{ -public: - typedef Kokkos::RangePolicy< Traits ... > Policy ; - -private: - typedef typename Policy::member_type Member ; - typedef typename Policy::work_tag WorkTag ; - typedef typename Policy::WorkRange WorkRange ; - typedef typename Policy::launch_bounds LaunchBounds ; - - typedef Kokkos::Impl::FunctorValueTraits< FunctorType, WorkTag > ValueTraits ; - typedef Kokkos::Impl::FunctorValueInit< FunctorType, WorkTag > ValueInit ; - typedef Kokkos::Impl::FunctorValueOps< FunctorType, WorkTag > ValueOps ; - -public: - - typedef typename ValueTraits::pointer_type pointer_type ; - typedef typename ValueTraits::reference_type reference_type ; - typedef FunctorType functor_type ; - typedef Cuda::size_type size_type ; - -private: +template +class ParallelScanWithTotal, + ReturnType, Kokkos::Cuda> { + public: + typedef Kokkos::RangePolicy Policy; + + private: + typedef typename Policy::member_type Member; + typedef typename Policy::work_tag WorkTag; + typedef typename Policy::WorkRange WorkRange; + typedef typename Policy::launch_bounds LaunchBounds; + + typedef Kokkos::Impl::FunctorValueTraits ValueTraits; + typedef Kokkos::Impl::FunctorValueInit ValueInit; + typedef Kokkos::Impl::FunctorValueOps ValueOps; + public: + typedef typename ValueTraits::pointer_type pointer_type; + typedef typename ValueTraits::reference_type reference_type; + typedef FunctorType functor_type; + typedef Cuda::size_type size_type; + + private: // Algorithmic constraints: // (a) blockDim.y is a power of two // (b) blockDim.y == blockDim.z == 1 // (c) gridDim.x <= blockDim.y * blockDim.y // (d) gridDim.y == gridDim.z == 1 - const FunctorType m_functor ; - const Policy m_policy ; - size_type * m_scratch_space ; - size_type * m_scratch_flags ; - size_type m_final ; - ReturnType & m_returnvalue; + const FunctorType m_functor; + const Policy m_policy; + size_type* m_scratch_space; + size_type* m_scratch_flags; + size_type m_final; + ReturnType& m_returnvalue; +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + bool m_run_serial; +#endif - template< class TagType > + template __device__ inline - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec_range( const Member & i , reference_type update , const bool final_result ) const - { m_functor( i , update , final_result ); } + typename std::enable_if::value>::type + exec_range(const Member& i, reference_type update, + const bool final_result) const { + m_functor(i, update, final_result); + } - template< class TagType > + template __device__ inline - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec_range( const Member & i , reference_type update , const bool final_result ) const - { m_functor( TagType() , i , update , final_result ); } + typename std::enable_if::value>::type + exec_range(const Member& i, reference_type update, + const bool final_result) const { + m_functor(TagType(), i, update, final_result); + } //---------------------------------------- - __device__ inline - void initial(void) const - { - const integral_nonzero_constant< size_type , ValueTraits::StaticValueSize / sizeof(size_type) > - word_count( ValueTraits::value_size( m_functor ) / sizeof(size_type) ); + __device__ inline void initial(void) const { + const integral_nonzero_constant + word_count(ValueTraits::value_size(m_functor) / sizeof(size_type)); - size_type * const shared_value = kokkos_impl_cuda_shared_memory() + word_count.value * threadIdx.y ; + size_type* const shared_value = + kokkos_impl_cuda_shared_memory() + + word_count.value * threadIdx.y; - ValueInit::init( m_functor , shared_value ); + ValueInit::init(m_functor, shared_value); - // Number of blocks is bounded so that the reduction can be limited to two passes. - // Each thread block is given an approximately equal amount of work to perform. - // Accumulate the values for this block. - // The accumulation ordering does not match the final pass, but is arithmatically equivalent. + // Number of blocks is bounded so that the reduction can be limited to two + // passes. Each thread block is given an approximately equal amount of work + // to perform. Accumulate the values for this block. The accumulation + // ordering does not match the final pass, but is arithmatically equivalent. - const WorkRange range( m_policy , blockIdx.x , gridDim.x ); + const WorkRange range(m_policy, blockIdx.x, gridDim.x); - for ( Member iwork = range.begin() + threadIdx.y , iwork_end = range.end() ; - iwork < iwork_end ; iwork += blockDim.y ) { - this-> template exec_range< WorkTag >( iwork , ValueOps::reference( shared_value ) , false ); + for (Member iwork = range.begin() + threadIdx.y, iwork_end = range.end(); + iwork < iwork_end; iwork += blockDim.y) { + this->template exec_range( + iwork, ValueOps::reference(shared_value), false); } - // Reduce and scan, writing out scan of blocks' totals and block-groups' totals. - // Blocks' scan values are written to 'blockIdx.x' location. - // Block-groups' scan values are at: i = ( j * blockDim.y - 1 ) for i < gridDim.x - cuda_single_inter_block_reduce_scan( m_functor , blockIdx.x , gridDim.x , kokkos_impl_cuda_shared_memory() , m_scratch_space , m_scratch_flags ); + // Reduce and scan, writing out scan of blocks' totals and block-groups' + // totals. Blocks' scan values are written to 'blockIdx.x' location. + // Block-groups' scan values are at: i = ( j * blockDim.y - 1 ) for i < + // gridDim.x + cuda_single_inter_block_reduce_scan( + m_functor, blockIdx.x, gridDim.x, + kokkos_impl_cuda_shared_memory(), m_scratch_space, + m_scratch_flags); } //---------------------------------------- - __device__ inline - void final(void) const - { - const integral_nonzero_constant< size_type , ValueTraits::StaticValueSize / sizeof(size_type) > - word_count( ValueTraits::value_size( m_functor ) / sizeof(size_type) ); + __device__ inline void final(void) const { + const integral_nonzero_constant + word_count(ValueTraits::value_size(m_functor) / sizeof(size_type)); - // Use shared memory as an exclusive scan: { 0 , value[0] , value[1] , value[2] , ... } - size_type * const shared_data = kokkos_impl_cuda_shared_memory(); - size_type * const shared_prefix = shared_data + word_count.value * threadIdx.y ; - size_type * const shared_accum = shared_data + word_count.value * ( blockDim.y + 1 ); + // Use shared memory as an exclusive scan: { 0 , value[0] , value[1] , + // value[2] , ... } + size_type* const shared_data = kokkos_impl_cuda_shared_memory(); + size_type* const shared_prefix = + shared_data + word_count.value * threadIdx.y; + size_type* const shared_accum = + shared_data + word_count.value * (blockDim.y + 1); // Starting value for this thread block is the previous block's total. - if ( blockIdx.x ) { - size_type * const block_total = m_scratch_space + word_count.value * ( blockIdx.x - 1 ); - for ( unsigned i = threadIdx.y ; i < word_count.value ; ++i ) { shared_accum[i] = block_total[i] ; } - } - else if ( 0 == threadIdx.y ) { - ValueInit::init( m_functor , shared_accum ); + if (blockIdx.x) { + size_type* const block_total = + m_scratch_space + word_count.value * (blockIdx.x - 1); + for (unsigned i = threadIdx.y; i < word_count.value; ++i) { + shared_accum[i] = block_total[i]; + } + } else if (0 == threadIdx.y) { + ValueInit::init(m_functor, shared_accum); } - const WorkRange range( m_policy , blockIdx.x , gridDim.x ); + const WorkRange range(m_policy, blockIdx.x, gridDim.x); - for ( typename Policy::member_type iwork_base = range.begin(); iwork_base < range.end() ; iwork_base += blockDim.y ) { - #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - unsigned MASK=KOKKOS_IMPL_CUDA_ACTIVEMASK; - #endif + for (typename Policy::member_type iwork_base = range.begin(); + iwork_base < range.end(); iwork_base += blockDim.y) { +#ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK + unsigned MASK = KOKKOS_IMPL_CUDA_ACTIVEMASK; +#endif - const typename Policy::member_type iwork = iwork_base + threadIdx.y ; + const typename Policy::member_type iwork = iwork_base + threadIdx.y; - __syncthreads(); // Don't overwrite previous iteration values until they are used + __syncthreads(); // Don't overwrite previous iteration values until they + // are used - ValueInit::init( m_functor , shared_prefix + word_count.value ); + ValueInit::init(m_functor, shared_prefix + word_count.value); - // Copy previous block's accumulation total into thread[0] prefix and inclusive scan value of this block - for ( unsigned i = threadIdx.y ; i < word_count.value ; ++i ) { - shared_data[i + word_count.value] = shared_data[i] = shared_accum[i] ; + // Copy previous block's accumulation total into thread[0] prefix and + // inclusive scan value of this block + for (unsigned i = threadIdx.y; i < word_count.value; ++i) { + shared_data[i + word_count.value] = shared_data[i] = shared_accum[i]; } - #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK +#ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK KOKKOS_IMPL_CUDA_SYNCWARP_MASK(MASK); - #else +#else KOKKOS_IMPL_CUDA_SYNCWARP; - #endif - if ( CudaTraits::WarpSize < word_count.value ) { __syncthreads(); } // Protect against large scan values. +#endif + if (CudaTraits::WarpSize < word_count.value) { + __syncthreads(); + } // Protect against large scan values. // Call functor to accumulate inclusive scan value for this work item - if ( iwork < range.end() ) { - this-> template exec_range< WorkTag >( iwork , ValueOps::reference( shared_prefix + word_count.value ) , false ); + if (iwork < range.end()) { + this->template exec_range( + iwork, ValueOps::reference(shared_prefix + word_count.value), + false); } // Scan block values into locations shared_data[1..blockDim.y] - cuda_intra_block_reduce_scan( m_functor , typename ValueTraits::pointer_type(shared_data+word_count.value) ); + cuda_intra_block_reduce_scan( + m_functor, + typename ValueTraits::pointer_type(shared_data + word_count.value)); { - size_type * const block_total = shared_data + word_count.value * blockDim.y ; - for ( unsigned i = threadIdx.y ; i < word_count.value ; ++i ) { shared_accum[i] = block_total[i]; } + size_type* const block_total = + shared_data + word_count.value * blockDim.y; + for (unsigned i = threadIdx.y; i < word_count.value; ++i) { + shared_accum[i] = block_total[i]; + } } // Call functor with exclusive scan value - if ( iwork < range.end() ) { - this-> template exec_range< WorkTag >( iwork , ValueOps::reference( shared_prefix ) , true ); + if (iwork < range.end()) { + this->template exec_range( + iwork, ValueOps::reference(shared_prefix), true); } } } -public: - + public: //---------------------------------------- - __device__ inline - void operator()(void) const - { - if ( ! m_final ) { - initial(); - } - else { - final(); + __device__ inline void operator()(void) const { +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + if (m_run_serial) { + typename ValueTraits::value_type value; + ValueInit::init(m_functor, (void*)&value); + const WorkRange range(m_policy, blockIdx.x, gridDim.x); + + for (typename Policy::member_type iwork_base = range.begin(); + iwork_base < range.end(); iwork_base++) { + this->template exec_range(iwork_base, value, true); + } + *((typename ValueTraits::value_type*)m_scratch_space) = value; + } else { +#endif + if (!m_final) { + initial(); + } else { + final(); + } +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION } +#endif } // Determine block size constrained by shared memory: - inline - unsigned local_block_size( const FunctorType & f ) - { - // blockDim.y must be power of two = 128 (4 warps) or 256 (8 warps) or 512 (16 warps) - // gridDim.x <= blockDim.y * blockDim.y - // - // 4 warps was 10% faster than 8 warps and 20% faster than 16 warps in unit testing - - unsigned n = CudaTraits::WarpSize * 4 ; - while ( n && unsigned(m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock) < cuda_single_inter_block_reduce_scan_shmem( f , n ) ) { n >>= 1 ; } - return n ; - } - - inline - void execute() - { - const int nwork = m_policy.end() - m_policy.begin(); - if ( nwork ) { - enum { GridMaxComputeCapability_2x = 0x0ffff }; + inline unsigned local_block_size(const FunctorType& f) { + // blockDim.y must be power of two = 128 (4 warps) or 256 (8 warps) or 512 + // (16 warps) gridDim.x <= blockDim.y * blockDim.y + // + // 4 warps was 10% faster than 8 warps and 20% faster than 16 warps in unit + // testing + + unsigned n = CudaTraits::WarpSize * 4; + while (n && + unsigned(m_policy.space() + .impl_internal_space_instance() + ->m_maxShmemPerBlock) < + cuda_single_inter_block_reduce_scan_shmem(f, n)) { + n >>= 1; + } + return n; + } - const int block_size = local_block_size( m_functor ); + inline void execute() { + const int nwork = m_policy.end() - m_policy.begin(); + if (nwork) { + enum { GridMaxComputeCapability_2x = 0x0ffff }; - const int grid_max = - ( block_size * block_size ) < GridMaxComputeCapability_2x ? - ( block_size * block_size ) : GridMaxComputeCapability_2x ; + const int block_size = local_block_size(m_functor); - // At most 'max_grid' blocks: - const int max_grid = std::min( int(grid_max) , int(( nwork + block_size - 1 ) / block_size )); + const int grid_max = + (block_size * block_size) < GridMaxComputeCapability_2x + ? (block_size * block_size) + : GridMaxComputeCapability_2x; - // How much work per block: - const int work_per_block = ( nwork + max_grid - 1 ) / max_grid ; + // At most 'max_grid' blocks: + const int max_grid = + std::min(int(grid_max), int((nwork + block_size - 1) / block_size)); - // How many block are really needed for this much work: - const int grid_x = ( nwork + work_per_block - 1 ) / work_per_block ; + // How much work per block: + const int work_per_block = (nwork + max_grid - 1) / max_grid; - m_scratch_space = cuda_internal_scratch_space( m_policy.space(), ValueTraits::value_size( m_functor ) * grid_x ); - m_scratch_flags = cuda_internal_scratch_flags( m_policy.space(), sizeof(size_type) * 1 ); + // How many block are really needed for this much work: + const int grid_x = (nwork + work_per_block - 1) / work_per_block; - const dim3 grid( grid_x , 1 , 1 ); - const dim3 block( 1 , block_size , 1 ); // REQUIRED DIMENSIONS ( 1 , N , 1 ) - const int shmem = ValueTraits::value_size( m_functor ) * ( block_size + 2 ); + m_scratch_space = cuda_internal_scratch_space( + m_policy.space(), ValueTraits::value_size(m_functor) * grid_x); + m_scratch_flags = + cuda_internal_scratch_flags(m_policy.space(), sizeof(size_type) * 1); - m_final = false ; - CudaParallelLaunch< ParallelScanWithTotal, LaunchBounds >( *this, grid, block, shmem , m_policy.space().impl_internal_space_instance() , false ); // copy to device and execute + dim3 grid(grid_x, 1, 1); + dim3 block(1, block_size, 1); // REQUIRED DIMENSIONS ( 1 , N , 1 ) + const int shmem = ValueTraits::value_size(m_functor) * (block_size + 2); - m_final = true ; - CudaParallelLaunch< ParallelScanWithTotal, LaunchBounds >( *this, grid, block, shmem , m_policy.space().impl_internal_space_instance() , false ); // copy to device and execute +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + if (m_run_serial) { + block = dim3(1, 1, 1); + grid = dim3(1, 1, 1); + } else { +#endif - const int size = ValueTraits::value_size( m_functor ); - DeepCopy( &m_returnvalue, m_scratch_space + (grid_x - 1)*size/sizeof(int), size ); + m_final = false; + CudaParallelLaunch( + *this, grid, block, shmem, + m_policy.space().impl_internal_space_instance(), + false); // copy to device and execute +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION } +#endif + m_final = true; + CudaParallelLaunch( + *this, grid, block, shmem, + m_policy.space().impl_internal_space_instance(), + false); // copy to device and execute + + const int size = ValueTraits::value_size(m_functor); +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + if (m_run_serial) + DeepCopy(&m_returnvalue, m_scratch_space, size); + else +#endif + DeepCopy( + &m_returnvalue, m_scratch_space + (grid_x - 1) * size / sizeof(int), + size); } + } - ParallelScanWithTotal( const FunctorType & arg_functor , - const Policy & arg_policy , - ReturnType & arg_returnvalue ) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - , m_scratch_space( 0 ) - , m_scratch_flags( 0 ) - , m_final( false ) - , m_returnvalue( arg_returnvalue ) - { } + ParallelScanWithTotal(const FunctorType& arg_functor, + const Policy& arg_policy, ReturnType& arg_returnvalue) + : m_functor(arg_functor), + m_policy(arg_policy), + m_scratch_space(0), + m_scratch_flags(0), + m_final(false), + m_returnvalue(arg_returnvalue) +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + , + m_run_serial(Kokkos::Impl::CudaInternal::cuda_use_serial_execution()) +#endif + { + } }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -2131,155 +2606,228 @@ public: namespace Kokkos { namespace Impl { - template< class FunctorType, class ExecPolicy, class ValueType , class Tag = typename ExecPolicy::work_tag> - struct CudaFunctorAdapter { - const FunctorType f; - typedef ValueType value_type; - CudaFunctorAdapter(const FunctorType& f_):f(f_) {} - - __device__ inline - void operator() (typename ExecPolicy::work_tag, const typename ExecPolicy::member_type& i, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals third argument type of FunctorType::operator() - f(typename ExecPolicy::work_tag(), i, val); - } - - __device__ inline - void operator() (typename ExecPolicy::work_tag, const typename ExecPolicy::member_type& i, const typename ExecPolicy::member_type& j, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals third argument type of FunctorType::operator() - f(typename ExecPolicy::work_tag(), i, j, val); - } - - __device__ inline - void operator() (typename ExecPolicy::work_tag, const typename ExecPolicy::member_type& i, const typename ExecPolicy::member_type& j, const typename ExecPolicy::member_type& k, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals third argument type of FunctorType::operator() - f(typename ExecPolicy::work_tag(), i, j, k, val); - } - - __device__ inline - void operator() (typename ExecPolicy::work_tag, const typename ExecPolicy::member_type& i, const typename ExecPolicy::member_type& j, const typename ExecPolicy::member_type& k, const typename ExecPolicy::member_type& l, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals third argument type of FunctorType::operator() - f(typename ExecPolicy::work_tag(), i, j, k, l, val); - } - - __device__ inline - void operator() (typename ExecPolicy::work_tag, const typename ExecPolicy::member_type& i, const typename ExecPolicy::member_type& j, const typename ExecPolicy::member_type& k, const typename ExecPolicy::member_type& l, const typename ExecPolicy::member_type& m, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals third argument type of FunctorType::operator() - f(typename ExecPolicy::work_tag(), i, j, k, l, m, val); - } - - __device__ inline - void operator() (typename ExecPolicy::work_tag, const typename ExecPolicy::member_type& i, const typename ExecPolicy::member_type& j, const typename ExecPolicy::member_type& k, const typename ExecPolicy::member_type& l, const typename ExecPolicy::member_type& m, const typename ExecPolicy::member_type& n, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals third argument type of FunctorType::operator() - f(typename ExecPolicy::work_tag(), i, j, k, l, m, n, val); - } +template +struct CudaFunctorAdapter { + const FunctorType f; + typedef ValueType value_type; + CudaFunctorAdapter(const FunctorType& f_) : f(f_) {} + + __device__ inline void operator()(typename ExecPolicy::work_tag, + const typename ExecPolicy::member_type& i, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals third argument + // type of FunctorType::operator() + f(typename ExecPolicy::work_tag(), i, val); + } - }; + __device__ inline void operator()(typename ExecPolicy::work_tag, + const typename ExecPolicy::member_type& i, + const typename ExecPolicy::member_type& j, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals third argument + // type of FunctorType::operator() + f(typename ExecPolicy::work_tag(), i, j, val); + } - template< class FunctorType, class ExecPolicy, class ValueType > - struct CudaFunctorAdapter { - const FunctorType f; - typedef ValueType value_type; - CudaFunctorAdapter(const FunctorType& f_):f(f_) {} + __device__ inline void operator()(typename ExecPolicy::work_tag, + const typename ExecPolicy::member_type& i, + const typename ExecPolicy::member_type& j, + const typename ExecPolicy::member_type& k, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals third argument + // type of FunctorType::operator() + f(typename ExecPolicy::work_tag(), i, j, k, val); + } - __device__ inline - void operator() (const typename ExecPolicy::member_type& i, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,val); - } + __device__ inline void operator()(typename ExecPolicy::work_tag, + const typename ExecPolicy::member_type& i, + const typename ExecPolicy::member_type& j, + const typename ExecPolicy::member_type& k, + const typename ExecPolicy::member_type& l, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals third argument + // type of FunctorType::operator() + f(typename ExecPolicy::work_tag(), i, j, k, l, val); + } - __device__ inline - void operator() (const typename ExecPolicy::member_type& i, const typename ExecPolicy::member_type& j, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,j,val); - } + __device__ inline void operator()(typename ExecPolicy::work_tag, + const typename ExecPolicy::member_type& i, + const typename ExecPolicy::member_type& j, + const typename ExecPolicy::member_type& k, + const typename ExecPolicy::member_type& l, + const typename ExecPolicy::member_type& m, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals third argument + // type of FunctorType::operator() + f(typename ExecPolicy::work_tag(), i, j, k, l, m, val); + } - __device__ inline - void operator() (const typename ExecPolicy::member_type& i, const typename ExecPolicy::member_type& j, const typename ExecPolicy::member_type& k, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,j,k,val); - } + __device__ inline void operator()(typename ExecPolicy::work_tag, + const typename ExecPolicy::member_type& i, + const typename ExecPolicy::member_type& j, + const typename ExecPolicy::member_type& k, + const typename ExecPolicy::member_type& l, + const typename ExecPolicy::member_type& m, + const typename ExecPolicy::member_type& n, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals third argument + // type of FunctorType::operator() + f(typename ExecPolicy::work_tag(), i, j, k, l, m, n, val); + } +}; - __device__ inline - void operator() (const typename ExecPolicy::member_type& i, const typename ExecPolicy::member_type& j, const typename ExecPolicy::member_type& k, const typename ExecPolicy::member_type& l, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,j,k,l,val); - } +template +struct CudaFunctorAdapter { + const FunctorType f; + typedef ValueType value_type; + CudaFunctorAdapter(const FunctorType& f_) : f(f_) {} + + __device__ inline void operator()(const typename ExecPolicy::member_type& i, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, val); + } - __device__ inline - void operator() (const typename ExecPolicy::member_type& i, const typename ExecPolicy::member_type& j, const typename ExecPolicy::member_type& k, const typename ExecPolicy::member_type& l, const typename ExecPolicy::member_type& m, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,j,k,l,m,val); - } + __device__ inline void operator()(const typename ExecPolicy::member_type& i, + const typename ExecPolicy::member_type& j, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, j, val); + } - __device__ inline - void operator() (const typename ExecPolicy::member_type& i, const typename ExecPolicy::member_type& j, const typename ExecPolicy::member_type& k, const typename ExecPolicy::member_type& l, const typename ExecPolicy::member_type& m, const typename ExecPolicy::member_type& n, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,j,k,l,m,n,val); - } + __device__ inline void operator()(const typename ExecPolicy::member_type& i, + const typename ExecPolicy::member_type& j, + const typename ExecPolicy::member_type& k, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, j, k, val); + } + __device__ inline void operator()(const typename ExecPolicy::member_type& i, + const typename ExecPolicy::member_type& j, + const typename ExecPolicy::member_type& k, + const typename ExecPolicy::member_type& l, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, j, k, l, val); + } - __device__ inline - void operator() (typename ExecPolicy::member_type& i, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,val); - } + __device__ inline void operator()(const typename ExecPolicy::member_type& i, + const typename ExecPolicy::member_type& j, + const typename ExecPolicy::member_type& k, + const typename ExecPolicy::member_type& l, + const typename ExecPolicy::member_type& m, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, j, k, l, m, val); + } - __device__ inline - void operator() (typename ExecPolicy::member_type& i, typename ExecPolicy::member_type& j, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,j,val); - } + __device__ inline void operator()(const typename ExecPolicy::member_type& i, + const typename ExecPolicy::member_type& j, + const typename ExecPolicy::member_type& k, + const typename ExecPolicy::member_type& l, + const typename ExecPolicy::member_type& m, + const typename ExecPolicy::member_type& n, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, j, k, l, m, n, val); + } - __device__ inline - void operator() (typename ExecPolicy::member_type& i, typename ExecPolicy::member_type& j, typename ExecPolicy::member_type& k, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,j,k,val); - } + __device__ inline void operator()(typename ExecPolicy::member_type& i, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, val); + } - __device__ inline - void operator() (typename ExecPolicy::member_type& i, typename ExecPolicy::member_type& j, typename ExecPolicy::member_type& k, typename ExecPolicy::member_type& l, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,j,k,l,val); - } + __device__ inline void operator()(typename ExecPolicy::member_type& i, + typename ExecPolicy::member_type& j, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, j, val); + } - __device__ inline - void operator() (typename ExecPolicy::member_type& i, typename ExecPolicy::member_type& j, typename ExecPolicy::member_type& k, typename ExecPolicy::member_type& l, typename ExecPolicy::member_type& m, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,j,k,l,m,val); - } + __device__ inline void operator()(typename ExecPolicy::member_type& i, + typename ExecPolicy::member_type& j, + typename ExecPolicy::member_type& k, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, j, k, val); + } - __device__ inline - void operator() (typename ExecPolicy::member_type& i, typename ExecPolicy::member_type& j, typename ExecPolicy::member_type& k, typename ExecPolicy::member_type& l, typename ExecPolicy::member_type& m, typename ExecPolicy::member_type& n, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,j,k,l,m,n,val); - } + __device__ inline void operator()(typename ExecPolicy::member_type& i, + typename ExecPolicy::member_type& j, + typename ExecPolicy::member_type& k, + typename ExecPolicy::member_type& l, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, j, k, l, val); + } - }; + __device__ inline void operator()(typename ExecPolicy::member_type& i, + typename ExecPolicy::member_type& j, + typename ExecPolicy::member_type& k, + typename ExecPolicy::member_type& l, + typename ExecPolicy::member_type& m, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, j, k, l, m, val); + } - template::value > - struct FunctorReferenceType { - typedef ResultType& reference_type; - }; + __device__ inline void operator()(typename ExecPolicy::member_type& i, + typename ExecPolicy::member_type& j, + typename ExecPolicy::member_type& k, + typename ExecPolicy::member_type& l, + typename ExecPolicy::member_type& m, + typename ExecPolicy::member_type& n, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, j, k, l, m, n, val); + } +}; - template - struct FunctorReferenceType { - typedef typename Kokkos::Impl::FunctorValueTraits< FunctorType ,Tag >::reference_type reference_type; - }; +template ::value> +struct FunctorReferenceType { + typedef ResultType& reference_type; +}; - template< class FunctorTypeIn, class ExecPolicy, class ValueType> - struct ParallelReduceFunctorType { +template +struct FunctorReferenceType { + typedef typename Kokkos::Impl::FunctorValueTraits< + FunctorType, Tag>::reference_type reference_type; +}; - enum {FunctorHasValueType = IsNonTrivialReduceFunctor::value }; - typedef typename Kokkos::Impl::if_c >::type functor_type; - static functor_type functor(const FunctorTypeIn& functor_in) { - return Impl::if_c::select(functor_in,functor_type(functor_in)); - } +template +struct ParallelReduceFunctorType { + enum { + FunctorHasValueType = IsNonTrivialReduceFunctor::value }; + typedef typename Kokkos::Impl::if_c< + FunctorHasValueType, FunctorTypeIn, + Impl::CudaFunctorAdapter>::type + functor_type; + static functor_type functor(const FunctorTypeIn& functor_in) { + return Impl::if_c::select( + functor_in, functor_type(functor_in)); + } +}; -} +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos #endif /* defined( __CUDACC__ ) */ #endif /* #ifndef KOKKOS_CUDA_PARALLEL_HPP */ - diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp index c39dddb198..41431bfb8d 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,7 +46,7 @@ #define KOKKOS_CUDA_REDUCESCAN_HPP #include -#if defined( __CUDACC__ ) && defined( KOKKOS_ENABLE_CUDA ) +#if defined(__CUDACC__) && defined(KOKKOS_ENABLE_CUDA) #include @@ -60,131 +61,6 @@ namespace Kokkos { namespace Impl { -//---------------------------------------------------------------------------- -// Shuffle operations require input to be a register (stack) variable - -// TODO: reconcile these implementations with those in Kokkos_Cuda_Vectorization.hpp - -template< typename T > -__device__ inline -void cuda_shfl( T & out , T const & in , int lane , - typename std::enable_if< sizeof(int) == sizeof(T) , int >::type width - , unsigned mask = 0xffffffff ) -{ - *reinterpret_cast(&out) = - KOKKOS_IMPL_CUDA_SHFL_MASK( mask , *reinterpret_cast(&in) , lane , width ); -} - -// TODO: figure out why 64-bit shfl fails in Clang -#if ( CUDA_VERSION >= 9000 ) && (!defined(KOKKOS_COMPILER_CLANG)) - -template< typename T > -__device__ inline -void cuda_shfl( T & out , T const & in , int lane , - typename std::enable_if< sizeof(long long) == sizeof(T) , int >::type width - , unsigned mask = 0xffffffff ) -{ - *reinterpret_cast(&out) = - KOKKOS_IMPL_CUDA_SHFL_MASK( mask , *reinterpret_cast(&in) , lane , width ); -} - -#endif - -template< typename T > -__device__ inline -void cuda_shfl( T & out , T const & in , int lane , - typename std::enable_if - < ( KOKKOS_IMPL_CUDA_MAX_SHFL_SIZEOF < sizeof(T) ) && ( 0 == ( sizeof(T) % sizeof(int) ) ) - , int >::type width, unsigned mask = 0xffffffff ) -{ - enum : int { N = sizeof(T) / sizeof(int) }; - - for ( int i = 0 ; i < N ; ++i ) { - reinterpret_cast(&out)[i] = - KOKKOS_IMPL_CUDA_SHFL_MASK( mask , reinterpret_cast(&in)[i] , lane , width ); - } -} - -//---------------------------------------------------------------------------- - -template< typename T > -__device__ inline -void cuda_shfl_down( T & out , T const & in , int delta , - typename std::enable_if< sizeof(int) == sizeof(T) , int >::type width , unsigned mask = 0xffffffff ) -{ - *reinterpret_cast(&out) = - KOKKOS_IMPL_CUDA_SHFL_DOWN_MASK( mask , *reinterpret_cast(&in) , delta , width ); -} - -// TODO: figure out why 64-bit shfl fails in Clang -#if ( CUDA_VERSION >= 9000 ) && (!defined(KOKKOS_COMPILER_CLANG)) - -template< typename T > -__device__ inline -void cuda_shfl_down( T & out , T const & in , int delta , - typename std::enable_if< sizeof(long long) == sizeof(T) , int >::type width , unsigned mask = 0xffffffff ) -{ - *reinterpret_cast(&out) = - KOKKOS_IMPL_CUDA_SHFL_DOWN_MASK( mask , *reinterpret_cast(&in) , delta , width ); -} - -#endif - -template< typename T > -__device__ inline -void cuda_shfl_down( T & out , T const & in , int delta , - typename std::enable_if - < ( KOKKOS_IMPL_CUDA_MAX_SHFL_SIZEOF < sizeof(T) ) && ( 0 == ( sizeof(T) % sizeof(int) ) ) - , int >::type width , unsigned mask = 0xffffffff ) -{ - enum : int { N = sizeof(T) / sizeof(int) }; - - for ( int i = 0 ; i < N ; ++i ) { - reinterpret_cast(&out)[i] = - KOKKOS_IMPL_CUDA_SHFL_DOWN_MASK( mask , reinterpret_cast(&in)[i] , delta , width ); - } -} - -//---------------------------------------------------------------------------- - -template< typename T > -__device__ inline -void cuda_shfl_up( T & out , T const & in , int delta , - typename std::enable_if< sizeof(int) == sizeof(T) , int >::type width , unsigned mask = 0xffffffff ) -{ - *reinterpret_cast(&out) = - KOKKOS_IMPL_CUDA_SHFL_UP_MASK( mask , *reinterpret_cast(&in) , delta , width ); -} - -// TODO: figure out why 64-bit shfl fails in Clang -#if ( CUDA_VERSION >= 9000 ) && (!defined(KOKKOS_COMPILER_CLANG)) - -template< typename T > -__device__ inline -void cuda_shfl_up( T & out , T const & in , int delta , - typename std::enable_if< sizeof(long long) == sizeof(T) , int >::type width , unsigned mask = 0xffffffff ) -{ - *reinterpret_cast(&out) = - KOKKOS_IMPL_CUDA_SHFL_UP_MASK( mask , *reinterpret_cast(&in) , delta , width ); -} - -#endif - -template< typename T > -__device__ inline -void cuda_shfl_up( T & out , T const & in , int delta , - typename std::enable_if - < ( KOKKOS_IMPL_CUDA_MAX_SHFL_SIZEOF < sizeof(T) ) && ( 0 == ( sizeof(T) % sizeof(int) ) ) - , int >::type width , unsigned mask = 0xffffffff ) -{ - enum : int { N = sizeof(T) / sizeof(int) }; - - for ( int i = 0 ; i < N ; ++i ) { - reinterpret_cast(&out)[i] = - KOKKOS_IMPL_CUDA_SHFL_UP_MASK( mask , reinterpret_cast(&in)[i] , delta , width ); - } -} - //---------------------------------------------------------------------------- /* * Algorithmic constraints: @@ -193,511 +69,502 @@ void cuda_shfl_up( T & out , T const & in , int delta , * (c) blockDim.z == 1 */ -template< class ValueType , class JoinOp> +template __device__ inline -typename std::enable_if< !Kokkos::is_reducer::value >::type -cuda_intra_warp_reduction( ValueType& result, - const JoinOp& join, - const uint32_t max_active_thread = blockDim.y) { - + typename std::enable_if::value>::type + cuda_intra_warp_reduction(ValueType& result, const JoinOp& join, + const uint32_t max_active_thread = blockDim.y) { unsigned int shift = 1; - //Reduce over values from threads with different threadIdx.y - while(blockDim.x * shift < 32 ) { - const ValueType tmp = shfl_down(result, blockDim.x*shift,32u); - //Only join if upper thread is active (this allows non power of two for blockDim.y - if(threadIdx.y + shift < max_active_thread) - join(result , tmp); - shift*=2; + // Reduce over values from threads with different threadIdx.y + while (blockDim.x * shift < 32) { + const ValueType tmp = shfl_down(result, blockDim.x * shift, 32u); + // Only join if upper thread is active (this allows non power of two for + // blockDim.y + if (threadIdx.y + shift < max_active_thread) join(result, tmp); + shift *= 2; } - result = shfl(result,0,32); + result = shfl(result, 0, 32); } -template< class ValueType , class JoinOp> +template __device__ inline -typename std::enable_if< !Kokkos::is_reducer::value >::type -cuda_inter_warp_reduction( ValueType& value, - const JoinOp& join, - const int max_active_thread = blockDim.y) { - - #define STEP_WIDTH 4 - // Depending on the ValueType _shared__ memory must be aligned up to 8byte boundaries - // The reason not to use ValueType directly is that for types with constructors it - // could lead to race conditions - __shared__ double sh_result[(sizeof(ValueType)+7)/8*STEP_WIDTH]; - ValueType* result = (ValueType*) & sh_result; - const int step = 32 / blockDim.x; - int shift = STEP_WIDTH; - const int id = threadIdx.y%step==0?threadIdx.y/step:65000; - if(id < STEP_WIDTH ) { + typename std::enable_if::value>::type + cuda_inter_warp_reduction(ValueType& value, const JoinOp& join, + const int max_active_thread = blockDim.y) { +#define STEP_WIDTH 4 + // Depending on the ValueType _shared__ memory must be aligned up to 8byte + // boundaries The reason not to use ValueType directly is that for types with + // constructors it could lead to race conditions + __shared__ double sh_result[(sizeof(ValueType) + 7) / 8 * STEP_WIDTH]; + ValueType* result = (ValueType*)&sh_result; + const int step = 32 / blockDim.x; + int shift = STEP_WIDTH; + const int id = threadIdx.y % step == 0 ? threadIdx.y / step : 65000; + if (id < STEP_WIDTH) { result[id] = value; } __syncthreads(); - while (shift<=max_active_thread/step) { - if(shift<=id && shift+STEP_WIDTH>id && threadIdx.x==0) { - join(result[id%STEP_WIDTH],value); + while (shift <= max_active_thread / step) { + if (shift <= id && shift + STEP_WIDTH > id && threadIdx.x == 0) { + join(result[id % STEP_WIDTH], value); } __syncthreads(); - shift+=STEP_WIDTH; + shift += STEP_WIDTH; } - value = result[0]; - for(int i = 1; (i*step +template __device__ inline -typename std::enable_if< !Kokkos::is_reducer::value >::type -cuda_intra_block_reduction( ValueType& value, - const JoinOp& join, - const int max_active_thread = blockDim.y) { - cuda_intra_warp_reduction(value,join,max_active_thread); - cuda_inter_warp_reduction(value,join,max_active_thread); + typename std::enable_if::value>::type + cuda_intra_block_reduction(ValueType& value, const JoinOp& join, + const int max_active_thread = blockDim.y) { + cuda_intra_warp_reduction(value, join, max_active_thread); + cuda_inter_warp_reduction(value, join, max_active_thread); } -template< class FunctorType , class JoinOp , class ArgTag = void > -__device__ -bool cuda_inter_block_reduction( typename FunctorValueTraits< FunctorType , ArgTag >::reference_type value, - typename FunctorValueTraits< FunctorType , ArgTag >::reference_type neutral, - const JoinOp& join, - Cuda::size_type * const m_scratch_space, - typename FunctorValueTraits< FunctorType , ArgTag >::pointer_type const result, - Cuda::size_type * const m_scratch_flags, - const int max_active_thread = blockDim.y) { +template +__device__ bool cuda_inter_block_reduction( + typename FunctorValueTraits::reference_type value, + typename FunctorValueTraits::reference_type neutral, + const JoinOp& join, Cuda::size_type* const m_scratch_space, + typename FunctorValueTraits::pointer_type const result, + Cuda::size_type* const m_scratch_flags, + const int max_active_thread = blockDim.y) { #ifdef __CUDA_ARCH__ - typedef typename FunctorValueTraits< FunctorType , ArgTag >::pointer_type pointer_type; - typedef typename FunctorValueTraits< FunctorType , ArgTag >::value_type value_type; + typedef typename FunctorValueTraits::pointer_type + pointer_type; + typedef + typename FunctorValueTraits::value_type value_type; - //Do the intra-block reduction with shfl operations and static shared memory - cuda_intra_block_reduction(value,join,max_active_thread); + // Do the intra-block reduction with shfl operations and static shared memory + cuda_intra_block_reduction(value, join, max_active_thread); - const int id = threadIdx.y*blockDim.x + threadIdx.x; + const int id = threadIdx.y * blockDim.x + threadIdx.x; - //One thread in the block writes block result to global scratch_memory - if(id == 0 ) { - pointer_type global = ((pointer_type) m_scratch_space) + blockIdx.x; - *global = value; + // One thread in the block writes block result to global scratch_memory + if (id == 0) { + pointer_type global = ((pointer_type)m_scratch_space) + blockIdx.x; + *global = value; } - //One warp of last block performs inter block reduction through loading the block values from global scratch_memory + // One warp of last block performs inter block reduction through loading the + // block values from global scratch_memory bool last_block = false; - + __threadfence(); __syncthreads(); - if ( id < 32 ) { + if (id < 32) { Cuda::size_type count; - //Figure out whether this is the last block - if(id == 0) - count = Kokkos::atomic_fetch_add(m_scratch_flags,1); - count = Kokkos::shfl(count,0,32); + // Figure out whether this is the last block + if (id == 0) count = Kokkos::atomic_fetch_add(m_scratch_flags, 1); + count = Kokkos::shfl(count, 0, 32); - //Last block does the inter block reduction - if( count == gridDim.x - 1) { - //set flag back to zero - if(id == 0) - *m_scratch_flags = 0; + // Last block does the inter block reduction + if (count == gridDim.x - 1) { + // set flag back to zero + if (id == 0) *m_scratch_flags = 0; last_block = true; - value = neutral; + value = neutral; - pointer_type const volatile global = (pointer_type) m_scratch_space ; + pointer_type const volatile global = (pointer_type)m_scratch_space; - //Reduce all global values with splitting work over threads in one warp - const int step_size = blockDim.x*blockDim.y < 32 ? blockDim.x*blockDim.y : 32; - for(int i=id; i<(int)gridDim.x; i+=step_size) { + // Reduce all global values with splitting work over threads in one warp + const int step_size = + blockDim.x * blockDim.y < 32 ? blockDim.x * blockDim.y : 32; + for (int i = id; i < (int)gridDim.x; i += step_size) { value_type tmp = global[i]; join(value, tmp); } - //Perform shfl reductions within the warp only join if contribution is valid (allows gridDim.x non power of two and <32) - if (int(blockDim.x*blockDim.y) > 1) { - value_type tmp = Kokkos::shfl_down(value, 1,32); - if( id + 1 < int(gridDim.x) ) - join(value, tmp); + // Perform shfl reductions within the warp only join if contribution is + // valid (allows gridDim.x non power of two and <32) + if (int(blockDim.x * blockDim.y) > 1) { + value_type tmp = Kokkos::shfl_down(value, 1, 32); + if (id + 1 < int(gridDim.x)) join(value, tmp); } #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK unsigned int mask = KOKKOS_IMPL_CUDA_ACTIVEMASK; - int active = KOKKOS_IMPL_CUDA_BALLOT_MASK(mask,1); + int active = KOKKOS_IMPL_CUDA_BALLOT_MASK(mask, 1); #else int active = KOKKOS_IMPL_CUDA_BALLOT(1); #endif - if (int(blockDim.x*blockDim.y) > 2) { - value_type tmp = Kokkos::shfl_down(value, 2,32); - if( id + 2 < int(gridDim.x) ) - join(value, tmp); + if (int(blockDim.x * blockDim.y) > 2) { + value_type tmp = Kokkos::shfl_down(value, 2, 32); + if (id + 2 < int(gridDim.x)) join(value, tmp); } #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask,1); + active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask, 1); #else active += KOKKOS_IMPL_CUDA_BALLOT(1); #endif - if (int(blockDim.x*blockDim.y) > 4) { - value_type tmp = Kokkos::shfl_down(value, 4,32); - if( id + 4 < int(gridDim.x) ) - join(value, tmp); + if (int(blockDim.x * blockDim.y) > 4) { + value_type tmp = Kokkos::shfl_down(value, 4, 32); + if (id + 4 < int(gridDim.x)) join(value, tmp); } #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask,1); + active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask, 1); #else active += KOKKOS_IMPL_CUDA_BALLOT(1); #endif - if (int(blockDim.x*blockDim.y) > 8) { - value_type tmp = Kokkos::shfl_down(value, 8,32); - if( id + 8 < int(gridDim.x) ) - join(value, tmp); + if (int(blockDim.x * blockDim.y) > 8) { + value_type tmp = Kokkos::shfl_down(value, 8, 32); + if (id + 8 < int(gridDim.x)) join(value, tmp); } #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask,1); + active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask, 1); #else active += KOKKOS_IMPL_CUDA_BALLOT(1); #endif - if (int(blockDim.x*blockDim.y) > 16) { - value_type tmp = Kokkos::shfl_down(value, 16,32); - if( id + 16 < int(gridDim.x) ) - join(value, tmp); + if (int(blockDim.x * blockDim.y) > 16) { + value_type tmp = Kokkos::shfl_down(value, 16, 32); + if (id + 16 < int(gridDim.x)) join(value, tmp); } #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask,1); + active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask, 1); #else active += KOKKOS_IMPL_CUDA_BALLOT(1); #endif } } - //The last block has in its thread=0 the global reduction value through "value" + // The last block has in its thread=0 the global reduction value through + // "value" return last_block; #else return true; #endif } -template< class ReducerType > +template __device__ inline -typename std::enable_if< Kokkos::is_reducer::value >::type -cuda_intra_warp_reduction( const ReducerType& reducer, - typename ReducerType::value_type& result, - const uint32_t max_active_thread = blockDim.y) { - + typename std::enable_if::value>::type + cuda_intra_warp_reduction(const ReducerType& reducer, + typename ReducerType::value_type& result, + const uint32_t max_active_thread = blockDim.y) { typedef typename ReducerType::value_type ValueType; unsigned int shift = 1; - //Reduce over values from threads with different threadIdx.y - while(blockDim.x * shift < 32 ) { - const ValueType tmp = shfl_down(result, blockDim.x*shift,32u); - //Only join if upper thread is active (this allows non power of two for blockDim.y - if(threadIdx.y + shift < max_active_thread) - reducer.join(result , tmp); - shift*=2; + // Reduce over values from threads with different threadIdx.y + while (blockDim.x * shift < 32) { + const ValueType tmp = shfl_down(result, blockDim.x * shift, 32u); + // Only join if upper thread is active (this allows non power of two for + // blockDim.y + if (threadIdx.y + shift < max_active_thread) reducer.join(result, tmp); + shift *= 2; } - result = shfl(result,0,32); + result = shfl(result, 0, 32); reducer.reference() = result; } -template< class ReducerType > +template __device__ inline -typename std::enable_if< Kokkos::is_reducer::value >::type -cuda_inter_warp_reduction( const ReducerType& reducer, - typename ReducerType::value_type value, - const int max_active_thread = blockDim.y) { - + typename std::enable_if::value>::type + cuda_inter_warp_reduction(const ReducerType& reducer, + typename ReducerType::value_type value, + const int max_active_thread = blockDim.y) { typedef typename ReducerType::value_type ValueType; - #define STEP_WIDTH 4 - // Depending on the ValueType _shared__ memory must be aligned up to 8byte boundaries - // The reason not to use ValueType directly is that for types with constructors it - // could lead to race conditions - __shared__ double sh_result[(sizeof(ValueType)+7)/8*STEP_WIDTH]; - ValueType* result = (ValueType*) & sh_result; - const int step = 32 / blockDim.x; - int shift = STEP_WIDTH; - const int id = threadIdx.y%step==0?threadIdx.y/step:65000; - if(id < STEP_WIDTH ) { +#define STEP_WIDTH 4 + // Depending on the ValueType _shared__ memory must be aligned up to 8byte + // boundaries The reason not to use ValueType directly is that for types with + // constructors it could lead to race conditions + __shared__ double sh_result[(sizeof(ValueType) + 7) / 8 * STEP_WIDTH]; + ValueType* result = (ValueType*)&sh_result; + const int step = 32 / blockDim.x; + int shift = STEP_WIDTH; + const int id = threadIdx.y % step == 0 ? threadIdx.y / step : 65000; + if (id < STEP_WIDTH) { result[id] = value; } __syncthreads(); - while (shift<=max_active_thread/step) { - if(shift<=id && shift+STEP_WIDTH>id && threadIdx.x==0) { - reducer.join(result[id%STEP_WIDTH],value); + while (shift <= max_active_thread / step) { + if (shift <= id && shift + STEP_WIDTH > id && threadIdx.x == 0) { + reducer.join(result[id % STEP_WIDTH], value); } __syncthreads(); - shift+=STEP_WIDTH; + shift += STEP_WIDTH; } - value = result[0]; - for(int i = 1; (i*step +template __device__ inline -typename std::enable_if< Kokkos::is_reducer::value >::type -cuda_intra_block_reduction( const ReducerType& reducer, - typename ReducerType::value_type value, - const int max_active_thread = blockDim.y) { - cuda_intra_warp_reduction(reducer,value,max_active_thread); - cuda_inter_warp_reduction(reducer,value,max_active_thread); + typename std::enable_if::value>::type + cuda_intra_block_reduction(const ReducerType& reducer, + typename ReducerType::value_type value, + const int max_active_thread = blockDim.y) { + cuda_intra_warp_reduction(reducer, value, max_active_thread); + cuda_inter_warp_reduction(reducer, value, max_active_thread); } -template< class ReducerType > +template __device__ inline -typename std::enable_if< Kokkos::is_reducer::value >::type -cuda_intra_block_reduction( const ReducerType& reducer, - const int max_active_thread = blockDim.y) { - cuda_intra_block_reduction(reducer,reducer.reference(),max_active_thread); + typename std::enable_if::value>::type + cuda_intra_block_reduction(const ReducerType& reducer, + const int max_active_thread = blockDim.y) { + cuda_intra_block_reduction(reducer, reducer.reference(), max_active_thread); } -template< class ReducerType> +template __device__ inline -typename std::enable_if< Kokkos::is_reducer::value , bool >::type -cuda_inter_block_reduction( const ReducerType& reducer, - Cuda::size_type * const m_scratch_space, - Cuda::size_type * const m_scratch_flags, - const int max_active_thread = blockDim.y) { + typename std::enable_if::value, bool>::type + cuda_inter_block_reduction(const ReducerType& reducer, + Cuda::size_type* const m_scratch_space, + Cuda::size_type* const m_scratch_flags, + const int max_active_thread = blockDim.y) { #ifdef __CUDA_ARCH__ typedef typename ReducerType::value_type* pointer_type; typedef typename ReducerType::value_type value_type; - //Do the intra-block reduction with shfl operations and static shared memory - cuda_intra_block_reduction(reducer,max_active_thread); + // Do the intra-block reduction with shfl operations and static shared memory + cuda_intra_block_reduction(reducer, max_active_thread); value_type value = reducer.reference(); - const int id = threadIdx.y*blockDim.x + threadIdx.x; + const int id = threadIdx.y * blockDim.x + threadIdx.x; - //One thread in the block writes block result to global scratch_memory - if(id == 0 ) { - pointer_type global = ((pointer_type) m_scratch_space) + blockIdx.x; - *global = value; + // One thread in the block writes block result to global scratch_memory + if (id == 0) { + pointer_type global = ((pointer_type)m_scratch_space) + blockIdx.x; + *global = value; } - //One warp of last block performs inter block reduction through loading the block values from global scratch_memory + // One warp of last block performs inter block reduction through loading the + // block values from global scratch_memory bool last_block = false; + __threadfence(); __syncthreads(); - if ( id < 32 ) { + if (id < 32) { Cuda::size_type count; - //Figure out whether this is the last block - if(id == 0) - count = Kokkos::atomic_fetch_add(m_scratch_flags,1); - count = Kokkos::shfl(count,0,32); + // Figure out whether this is the last block + if (id == 0) count = Kokkos::atomic_fetch_add(m_scratch_flags, 1); + count = Kokkos::shfl(count, 0, 32); - //Last block does the inter block reduction - if( count == gridDim.x - 1) { - //set flag back to zero - if(id == 0) - *m_scratch_flags = 0; + // Last block does the inter block reduction + if (count == gridDim.x - 1) { + // set flag back to zero + if (id == 0) *m_scratch_flags = 0; last_block = true; reducer.init(value); - pointer_type const volatile global = (pointer_type) m_scratch_space ; + pointer_type const volatile global = (pointer_type)m_scratch_space; - //Reduce all global values with splitting work over threads in one warp - const int step_size = blockDim.x*blockDim.y < 32 ? blockDim.x*blockDim.y : 32; - for(int i=id; i<(int)gridDim.x; i+=step_size) { + // Reduce all global values with splitting work over threads in one warp + const int step_size = + blockDim.x * blockDim.y < 32 ? blockDim.x * blockDim.y : 32; + for (int i = id; i < (int)gridDim.x; i += step_size) { value_type tmp = global[i]; reducer.join(value, tmp); } - //Perform shfl reductions within the warp only join if contribution is valid (allows gridDim.x non power of two and <32) - if (int(blockDim.x*blockDim.y) > 1) { - value_type tmp = Kokkos::shfl_down(value, 1,32); - if( id + 1 < int(gridDim.x) ) - reducer.join(value, tmp); + // Perform shfl reductions within the warp only join if contribution is + // valid (allows gridDim.x non power of two and <32) + if (int(blockDim.x * blockDim.y) > 1) { + value_type tmp = Kokkos::shfl_down(value, 1, 32); + if (id + 1 < int(gridDim.x)) reducer.join(value, tmp); } #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK unsigned int mask = KOKKOS_IMPL_CUDA_ACTIVEMASK; - int active = KOKKOS_IMPL_CUDA_BALLOT_MASK(mask,1); + int active = KOKKOS_IMPL_CUDA_BALLOT_MASK(mask, 1); #else int active = KOKKOS_IMPL_CUDA_BALLOT(1); #endif - if (int(blockDim.x*blockDim.y) > 2) { - value_type tmp = Kokkos::shfl_down(value, 2,32); - if( id + 2 < int(gridDim.x) ) - reducer.join(value, tmp); + if (int(blockDim.x * blockDim.y) > 2) { + value_type tmp = Kokkos::shfl_down(value, 2, 32); + if (id + 2 < int(gridDim.x)) reducer.join(value, tmp); } #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask,1); + active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask, 1); #else active += KOKKOS_IMPL_CUDA_BALLOT(1); #endif - if (int(blockDim.x*blockDim.y) > 4) { - value_type tmp = Kokkos::shfl_down(value, 4,32); - if( id + 4 < int(gridDim.x) ) - reducer.join(value, tmp); + if (int(blockDim.x * blockDim.y) > 4) { + value_type tmp = Kokkos::shfl_down(value, 4, 32); + if (id + 4 < int(gridDim.x)) reducer.join(value, tmp); } #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask,1); + active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask, 1); #else active += KOKKOS_IMPL_CUDA_BALLOT(1); #endif - if (int(blockDim.x*blockDim.y) > 8) { - value_type tmp = Kokkos::shfl_down(value, 8,32); - if( id + 8 < int(gridDim.x) ) - reducer.join(value, tmp); + if (int(blockDim.x * blockDim.y) > 8) { + value_type tmp = Kokkos::shfl_down(value, 8, 32); + if (id + 8 < int(gridDim.x)) reducer.join(value, tmp); } #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask,1); + active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask, 1); #else active += KOKKOS_IMPL_CUDA_BALLOT(1); #endif - if (int(blockDim.x*blockDim.y) > 16) { - value_type tmp = Kokkos::shfl_down(value, 16,32); - if( id + 16 < int(gridDim.x) ) - reducer.join(value, tmp); + if (int(blockDim.x * blockDim.y) > 16) { + value_type tmp = Kokkos::shfl_down(value, 16, 32); + if (id + 16 < int(gridDim.x)) reducer.join(value, tmp); } #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask,1); + active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask, 1); #else active += KOKKOS_IMPL_CUDA_BALLOT(1); #endif } } - //The last block has in its thread=0 the global reduction value through "value" + // The last block has in its thread=0 the global reduction value through + // "value" return last_block; #else return true; #endif } -template +template struct CudaReductionsFunctor; -template +template struct CudaReductionsFunctor { - typedef FunctorValueTraits< FunctorType , ArgTag > ValueTraits ; - typedef FunctorValueJoin< FunctorType , ArgTag > ValueJoin ; - typedef FunctorValueInit< FunctorType , ArgTag > ValueInit ; - typedef FunctorValueOps< FunctorType , ArgTag > ValueOps ; - typedef typename ValueTraits::pointer_type pointer_type ; + typedef FunctorValueTraits ValueTraits; + typedef FunctorValueJoin ValueJoin; + typedef FunctorValueInit ValueInit; + typedef FunctorValueOps ValueOps; + typedef typename ValueTraits::pointer_type pointer_type; typedef typename ValueTraits::value_type Scalar; - __device__ - static inline void scalar_intra_warp_reduction( + __device__ static inline void scalar_intra_warp_reduction( const FunctorType& functor, - Scalar value, // Contribution - const bool skip_vector, // Skip threads if Kokkos vector lanes are not part of the reduction - const int width, // How much of the warp participates - Scalar& result) - { - unsigned mask = width==32?0xffffffff:((1<=w && warp_id= w && warp_id < w + shared_elements) { + if ((threadIdx.y * blockDim.x + threadIdx.x) % 32 == 0) + ValueJoin::join(functor, my_shared_team_buffer_element, &value); } __syncthreads(); } - - if( warp_id == 0) { - ValueInit::init( functor , &value ); - for(unsigned int i=threadIdx.y*blockDim.x+threadIdx.x; i +template struct CudaReductionsFunctor { - typedef FunctorValueTraits< FunctorType , ArgTag > ValueTraits ; - typedef FunctorValueJoin< FunctorType , ArgTag > ValueJoin ; - typedef FunctorValueInit< FunctorType , ArgTag > ValueInit ; - typedef FunctorValueOps< FunctorType , ArgTag > ValueOps ; - typedef typename ValueTraits::pointer_type pointer_type ; + typedef FunctorValueTraits ValueTraits; + typedef FunctorValueJoin ValueJoin; + typedef FunctorValueInit ValueInit; + typedef FunctorValueOps ValueOps; + typedef typename ValueTraits::pointer_type pointer_type; typedef typename ValueTraits::value_type Scalar; - __device__ - static inline void scalar_intra_warp_reduction( + __device__ static inline void scalar_intra_warp_reduction( const FunctorType& functor, - Scalar* value, // Contribution - const bool skip_vector, // Skip threads if Kokkos vector lanes are not part of the reduction - const int width) // How much of the warp participates + Scalar* value, // Contribution + const bool skip_vector, // Skip threads if Kokkos vector lanes are not + // part of the reduction + const int width) // How much of the warp participates { #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - unsigned mask = width==32?0xffffffff:((1< { KOKKOS_IMPL_CUDA_SYNCWARP; #endif } - *value=*(value-lane_id); + *value = *(value - lane_id); } - - __device__ - static inline void scalar_intra_block_reduction( - const FunctorType& functor, - Scalar value, - const bool skip, - Scalar* result, - const int shared_elements, - Scalar* shared_team_buffer_element) { - - const int warp_id = (threadIdx.y*blockDim.x)/32; + __device__ static inline void scalar_intra_block_reduction( + const FunctorType& functor, Scalar value, const bool skip, Scalar* result, + const int shared_elements, Scalar* shared_team_buffer_element) { + const int warp_id = (threadIdx.y * blockDim.x) / 32; Scalar* const my_shared_team_buffer_element = - shared_team_buffer_element + threadIdx.y*blockDim.x+threadIdx.x; + shared_team_buffer_element + threadIdx.y * blockDim.x + threadIdx.x; *my_shared_team_buffer_element = value; // Warp Level Reduction, ignoring Kokkos vector entries - scalar_intra_warp_reduction(functor,my_shared_team_buffer_element,skip,32); - // Wait for every warp to be done before using one warp to do final cross warp reduction + scalar_intra_warp_reduction(functor, my_shared_team_buffer_element, skip, + 32); + // Wait for every warp to be done before using one warp to do final cross + // warp reduction __syncthreads(); - if( warp_id == 0) { - const unsigned int delta = (threadIdx.y*blockDim.x+threadIdx.x)*32; - if(delta { * (c) blockDim.x == blockDim.z == 1 */ -template< bool DoScan , class FunctorType , class ArgTag > -__device__ -void cuda_intra_block_reduce_scan( const FunctorType & functor , - const typename FunctorValueTraits< FunctorType , ArgTag >::pointer_type base_data ) -{ - typedef FunctorValueTraits< FunctorType , ArgTag > ValueTraits ; - typedef FunctorValueJoin< FunctorType , ArgTag > ValueJoin ; +template +__device__ void cuda_intra_block_reduce_scan( + const FunctorType& functor, + const typename FunctorValueTraits::pointer_type + base_data) { + typedef FunctorValueTraits ValueTraits; + typedef FunctorValueJoin ValueJoin; - typedef typename ValueTraits::pointer_type pointer_type ; + typedef typename ValueTraits::pointer_type pointer_type; - const unsigned value_count = ValueTraits::value_count( functor ); - const unsigned BlockSizeMask = blockDim.y - 1 ; + const unsigned value_count = ValueTraits::value_count(functor); + const unsigned BlockSizeMask = blockDim.y - 1; // Must have power of two thread count - if ( BlockSizeMask & blockDim.y ) { Kokkos::abort("Cuda::cuda_intra_block_scan requires power-of-two blockDim"); } + if (BlockSizeMask & blockDim.y) { + Kokkos::abort("Cuda::cuda_intra_block_scan requires power-of-two blockDim"); + } -#define BLOCK_REDUCE_STEP( R , TD , S ) \ - if ( ! ( R & ((1<<(S+1))-1) ) ) { ValueJoin::join( functor , TD , (TD - (value_count< -__device__ -bool cuda_single_inter_block_reduce_scan2( const FunctorType & functor , - const Cuda::size_type block_id , - const Cuda::size_type block_count , - Cuda::size_type * const shared_data , - Cuda::size_type * const global_data , - Cuda::size_type * const global_flags ) -{ - typedef Cuda::size_type size_type ; - typedef FunctorValueTraits< FunctorType , ArgTag > ValueTraits ; - typedef FunctorValueJoin< FunctorType , ArgTag > ValueJoin ; - typedef FunctorValueInit< FunctorType , ArgTag > ValueInit ; - typedef FunctorValueOps< FunctorType , ArgTag > ValueOps ; - - typedef typename ValueTraits::pointer_type pointer_type ; +template +__device__ bool cuda_single_inter_block_reduce_scan2( + const FunctorType& functor, const Cuda::size_type block_id, + const Cuda::size_type block_count, Cuda::size_type* const shared_data, + Cuda::size_type* const global_data, Cuda::size_type* const global_flags) { + typedef Cuda::size_type size_type; + typedef FunctorValueTraits ValueTraits; + typedef FunctorValueJoin ValueJoin; + typedef FunctorValueInit ValueInit; + typedef FunctorValueOps ValueOps; + + typedef typename ValueTraits::pointer_type pointer_type; // '__ffs' = position of the least significant bit set to 1. // 'blockDim.y' is guaranteed to be a power of two so this // is the integral shift value that can replace an integral divide. - const unsigned BlockSizeShift = __ffs( blockDim.y ) - 1 ; - const unsigned BlockSizeMask = blockDim.y - 1 ; + const unsigned BlockSizeShift = __ffs(blockDim.y) - 1; + const unsigned BlockSizeMask = blockDim.y - 1; // Must have power of two thread count - if ( BlockSizeMask & blockDim.y ) { Kokkos::abort("Cuda::cuda_single_inter_block_reduce_scan requires power-of-two blockDim"); } + if (BlockSizeMask & blockDim.y) { + Kokkos::abort( + "Cuda::cuda_single_inter_block_reduce_scan requires power-of-two " + "blockDim"); + } - const integral_nonzero_constant< size_type , ValueTraits::StaticValueSize / sizeof(size_type) > - word_count( ValueTraits::value_size( functor ) / sizeof(size_type) ); + const integral_nonzero_constant + word_count(ValueTraits::value_size(functor) / sizeof(size_type)); // Reduce the accumulation for the entire block. - cuda_intra_block_reduce_scan( functor , pointer_type(shared_data) ); + cuda_intra_block_reduce_scan( + functor, pointer_type(shared_data)); { // Write accumulation total to global scratch space. // Accumulation total is the last thread's data. - size_type * const shared = shared_data + word_count.value * BlockSizeMask ; - size_type * const global = global_data + word_count.value * block_id ; + size_type* const shared = shared_data + word_count.value * BlockSizeMask; + size_type* const global = global_data + word_count.value * block_id; - for ( int i = int(threadIdx.y) ; i < int(word_count.value) ; i += int(blockDim.y) ) { global[i] = shared[i] ; } + for (int i = int(threadIdx.y); i < int(word_count.value); + i += int(blockDim.y)) { + global[i] = shared[i]; + } } - - // Contributing blocks note that their contribution has been completed via an atomic-increment flag - // If this block is not the last block to contribute to this group then the block is done. - const bool is_last_block = - ! __syncthreads_or( threadIdx.y ? 0 : ( 1 + atomicInc( global_flags , block_count - 1 ) < block_count ) ); - - if ( is_last_block ) { - - const size_type b = ( long(block_count) * long(threadIdx.y) ) >> BlockSizeShift ; - const size_type e = ( long(block_count) * long( threadIdx.y + 1 ) ) >> BlockSizeShift ; + __threadfence(); + + // Contributing blocks note that their contribution has been completed via an + // atomic-increment flag If this block is not the last block to contribute to + // this group then the block is done. + const bool is_last_block = !__syncthreads_or( + threadIdx.y + ? 0 + : (1 + atomicInc(global_flags, block_count - 1) < block_count)); + + if (is_last_block) { + const size_type b = + (long(block_count) * long(threadIdx.y)) >> BlockSizeShift; + const size_type e = + (long(block_count) * long(threadIdx.y + 1)) >> BlockSizeShift; { - void * const shared_ptr = shared_data + word_count.value * threadIdx.y ; - /* reference_type shared_value = */ ValueInit::init( functor , shared_ptr ); + void* const shared_ptr = shared_data + word_count.value * threadIdx.y; + /* reference_type shared_value = */ ValueInit::init(functor, shared_ptr); - for ( size_type i = b ; i < e ; ++i ) { - ValueJoin::join( functor , shared_ptr , global_data + word_count.value * i ); + for (size_type i = b; i < e; ++i) { + ValueJoin::join(functor, shared_ptr, + global_data + word_count.value * i); } } - cuda_intra_block_reduce_scan( functor , pointer_type(shared_data) ); + cuda_intra_block_reduce_scan( + functor, pointer_type(shared_data)); - if ( DoScan ) { + if (DoScan) { + size_type* const shared_value = + shared_data + + word_count.value * (threadIdx.y ? threadIdx.y - 1 : blockDim.y); - size_type * const shared_value = shared_data + word_count.value * ( threadIdx.y ? threadIdx.y - 1 : blockDim.y ); - - if ( ! threadIdx.y ) { ValueInit::init( functor , shared_value ); } + if (!threadIdx.y) { + ValueInit::init(functor, shared_value); + } // Join previous inclusive scan value to each member - for ( size_type i = b ; i < e ; ++i ) { - size_type * const global_value = global_data + word_count.value * i ; - ValueJoin::join( functor , shared_value , global_value ); - ValueOps ::copy( functor , global_value , shared_value ); + for (size_type i = b; i < e; ++i) { + size_type* const global_value = global_data + word_count.value * i; + ValueJoin::join(functor, shared_value, global_value); + ValueOps ::copy(functor, global_value, shared_value); } } } - return is_last_block ; + return is_last_block; } -template< bool DoScan , class FunctorType , class ArgTag > -__device__ -bool cuda_single_inter_block_reduce_scan( const FunctorType & functor , - const Cuda::size_type block_id , - const Cuda::size_type block_count , - Cuda::size_type * const shared_data , - Cuda::size_type * const global_data , - Cuda::size_type * const global_flags ) -{ - typedef FunctorValueTraits< FunctorType , ArgTag > ValueTraits ; - if(!DoScan && ValueTraits::StaticValueSize) - return Kokkos::Impl::CudaReductionsFunctor16)>::scalar_inter_block_reduction(functor,block_id,block_count,shared_data,global_data,global_flags); +template +__device__ bool cuda_single_inter_block_reduce_scan( + const FunctorType& functor, const Cuda::size_type block_id, + const Cuda::size_type block_count, Cuda::size_type* const shared_data, + Cuda::size_type* const global_data, Cuda::size_type* const global_flags) { + typedef FunctorValueTraits ValueTraits; + if (!DoScan && ValueTraits::StaticValueSize) + return Kokkos::Impl::CudaReductionsFunctor< + FunctorType, ArgTag, false, (ValueTraits::StaticValueSize > 16)>:: + scalar_inter_block_reduction(functor, block_id, block_count, + shared_data, global_data, global_flags); else - return cuda_single_inter_block_reduce_scan2(functor, block_id, block_count, shared_data, global_data, global_flags); + return cuda_single_inter_block_reduce_scan2( + functor, block_id, block_count, shared_data, global_data, global_flags); } // Size in bytes required for inter block reduce or scan -template< bool DoScan , class FunctorType , class ArgTag > -inline -unsigned cuda_single_inter_block_reduce_scan_shmem( const FunctorType & functor , const unsigned BlockSize ) -{ - return ( BlockSize + 2 ) * Impl::FunctorValueTraits< FunctorType , ArgTag >::value_size( functor ); +template +inline unsigned cuda_single_inter_block_reduce_scan_shmem( + const FunctorType& functor, const unsigned BlockSize) { + return (BlockSize + 2) * + Impl::FunctorValueTraits::value_size(functor); } -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- #endif /* #if defined( __CUDACC__ ) */ #endif /* KOKKOS_CUDA_REDUCESCAN_HPP */ - diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.cpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.cpp index ac36cfd67e..777f57ced4 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.cpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,7 +43,7 @@ */ #include -#if defined( KOKKOS_ENABLE_CUDA ) && defined( KOKKOS_ENABLE_TASKDAG ) +#if defined(KOKKOS_ENABLE_CUDA) && defined(KOKKOS_ENABLE_TASKDAG) #include @@ -54,13 +55,18 @@ namespace Kokkos { namespace Impl { -template class TaskQueue< Kokkos::Cuda, Impl::default_tasking_memory_space_for_execution_space_t > ; -template class TaskQueueMultiple< Kokkos::Cuda, Impl::default_tasking_memory_space_for_execution_space_t > ; +template class TaskQueue< + Kokkos::Cuda, + Impl::default_tasking_memory_space_for_execution_space_t >; +template class TaskQueueMultiple< + Kokkos::Cuda, + Impl::default_tasking_memory_space_for_execution_space_t >; -}} /* namespace Kokkos::Impl */ +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- #else void KOKKOS_CORE_SRC_CUDA_KOKKOS_CUDA_TASK_PREVENT_LINK_ERROR() {} -#endif /* #if defined( KOKKOS_ENABLE_CUDA ) && defined( KOKKOS_ENABLE_TASKDAG ) */ - +#endif /* #if defined( KOKKOS_ENABLE_CUDA ) && defined( KOKKOS_ENABLE_TASKDAG \ + ) */ diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.hpp index c35987e49e..237d2430d6 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,7 +46,7 @@ #define KOKKOS_IMPL_CUDA_TASK_HPP #include -#if defined( KOKKOS_ENABLE_TASKDAG ) +#if defined(KOKKOS_ENABLE_TASKDAG) //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -53,7 +54,7 @@ #include #include -#include // CUDA_SAFE_CALL +#include // CUDA_SAFE_CALL #include //---------------------------------------------------------------------------- @@ -62,65 +63,57 @@ namespace Kokkos { namespace Impl { namespace { -template< typename TaskType > -__global__ -void set_cuda_task_base_apply_function_pointer - ( typename TaskType::function_type * ptr, typename TaskType::destroy_type* dtor ) -{ - *ptr = TaskType::apply; +template +__global__ void set_cuda_task_base_apply_function_pointer( + typename TaskType::function_type* ptr, + typename TaskType::destroy_type* dtor) { + *ptr = TaskType::apply; *dtor = TaskType::destroy; } -template< typename Scheduler > -__global__ -void cuda_task_queue_execute( Scheduler scheduler, int32_t shmem_size ) { - TaskQueueSpecialization< Scheduler >::driver( std::move(scheduler) , shmem_size ); +template +__global__ void cuda_task_queue_execute(Scheduler scheduler, + int32_t shmem_size) { + TaskQueueSpecialization::driver(std::move(scheduler), shmem_size); } -} - -template class TaskExec ; +} // namespace -template -class TaskQueueSpecialization< - SimpleTaskScheduler -> -{ -public: +template +class TaskExec; - using scheduler_type = SimpleTaskScheduler; +template +class TaskQueueSpecialization> { + public: + using scheduler_type = SimpleTaskScheduler; using execution_space = Kokkos::Cuda; - using memory_space = Kokkos::CudaUVMSpace; - using member_type = TaskExec ; + using memory_space = Kokkos::CudaUVMSpace; + using member_type = TaskExec; enum : long { max_league_size = 16 }; enum : int { warps_per_block = 4 }; KOKKOS_INLINE_FUNCTION - static - void iff_single_thread_recursive_execute( scheduler_type const& ) {} + static void iff_single_thread_recursive_execute(scheduler_type const&) {} - static int get_max_team_count( - execution_space const& - ) { + static int get_max_team_count(execution_space const&) { return Kokkos::Impl::cuda_internal_multiprocessor_count() * warps_per_block; } - __device__ - static void driver(scheduler_type scheduler, int32_t shmem_per_warp) - { - using queue_type = typename scheduler_type::task_queue_type; + __device__ static void driver(scheduler_type scheduler, + int32_t shmem_per_warp) { + using queue_type = typename scheduler_type::task_queue_type; using task_base_type = typename scheduler_type::task_base_type; - using runnable_task_base_type = typename scheduler_type::runnable_task_base_type; - using scheduling_info_storage_type = - SchedulingInfoStorage< + using runnable_task_base_type = + typename scheduler_type::runnable_task_base_type; + using scheduling_info_storage_type = SchedulingInfoStorage< runnable_task_base_type, - typename scheduler_type::task_scheduling_info_type - >; + typename scheduler_type::task_scheduling_info_type>; extern __shared__ int32_t shmem_all[]; - int32_t* const warp_shmem = shmem_all + (threadIdx.z * shmem_per_warp) / sizeof(int32_t); + int32_t* const warp_shmem = + shmem_all + (threadIdx.z * shmem_per_warp) / sizeof(int32_t); task_base_type* const shared_memory_task_copy = (task_base_type*)warp_shmem; @@ -129,44 +122,47 @@ public: member_type single_exec(scheduler, warp_shmem, 1); member_type team_exec(scheduler, warp_shmem, blockDim.y); - auto& queue = scheduler.queue(); + auto& queue = scheduler.queue(); auto& team_scheduler = team_exec.scheduler(); auto current_task = OptionalRef(); // Loop until all queues are empty and no tasks in flight - while(not queue.is_done()) { - - if(warp_lane == 0) { // should be (?) same as team_exec.team_rank() == 0 + while (not queue.is_done()) { + if (warp_lane == 0) { // should be (?) same as team_exec.team_rank() == 0 // pop off a task - current_task = queue.pop_ready_task(team_scheduler.team_scheduler_info()); + current_task = + queue.pop_ready_task(team_scheduler.team_scheduler_info()); } // Broadcast task pointer: // Sync before the broadcast KOKKOS_IMPL_CUDA_SYNCWARP; - - // pretend it's an int* for shuffle purposes - ((int*) ¤t_task)[0] = KOKKOS_IMPL_CUDA_SHFL(((int*) ¤t_task)[0], 0, 32); - ((int*) ¤t_task)[1] = KOKKOS_IMPL_CUDA_SHFL(((int*) ¤t_task)[1], 0, 32); - if(current_task) { + // pretend it's an int* for shuffle purposes + ((int*)¤t_task)[0] = + KOKKOS_IMPL_CUDA_SHFL(((int*)¤t_task)[0], 0, 32); + ((int*)¤t_task)[1] = + KOKKOS_IMPL_CUDA_SHFL(((int*)¤t_task)[1], 0, 32); + if (current_task) { KOKKOS_ASSERT(!current_task->as_runnable_task().get_respawn_flag()); int32_t b = sizeof(scheduling_info_storage_type) / sizeof(int32_t); static_assert( - sizeof(scheduling_info_storage_type) % sizeof(int32_t) == 0, - "bad task size" - ); + sizeof(scheduling_info_storage_type) % sizeof(int32_t) == 0, + "bad task size"); int32_t const e = current_task->get_allocation_size() / sizeof(int32_t); - KOKKOS_ASSERT(current_task->get_allocation_size() % sizeof(int32_t) == 0); + KOKKOS_ASSERT(current_task->get_allocation_size() % sizeof(int32_t) == + 0); - int32_t volatile* const task_mem = (int32_t volatile*)current_task.get(); + int32_t volatile* const task_mem = + (int32_t volatile*)current_task.get(); - // do a coordinated copy of the task closure from global to shared memory: - for(int32_t i = warp_lane; i < e; i += CudaTraits::WarpSize) { + // do a coordinated copy of the task closure from global to shared + // memory: + for (int32_t i = warp_lane; i < e; i += CudaTraits::WarpSize) { warp_shmem[i] = task_mem[i]; } @@ -174,13 +170,12 @@ public: // writes are visible to all threads in the warp. KOKKOS_IMPL_CUDA_SYNCWARP; - if(shared_memory_task_copy->is_team_runnable()) { + if (shared_memory_task_copy->is_team_runnable()) { // Thread Team Task shared_memory_task_copy->as_runnable_task().run(team_exec); - } - else if(threadIdx.y == 0) { - // TODO @tasking @optimization DSH Change this to warp_lane == 0 when we allow blockDim.x to be more than 1 - // Single Thread Task + } else if (threadIdx.y == 0) { + // TODO @tasking @optimization DSH Change this to warp_lane == 0 when + // we allow blockDim.x to be more than 1 Single Thread Task shared_memory_task_copy->as_runnable_task().run(single_exec); } @@ -189,8 +184,8 @@ public: KOKKOS_IMPL_CUDA_SYNCWARP; - //if(warp_lane < b % CudaTraits::WarpSize) b += CudaTraits::WarpSize; - //b -= b % CudaTraits::WarpSize; + // if(warp_lane < b % CudaTraits::WarpSize) b += CudaTraits::WarpSize; + // b -= b % CudaTraits::WarpSize; // copy task closure from shared to global memory: for (int32_t i = b + warp_lane; i < e; i += CudaTraits::WarpSize) { @@ -203,17 +198,15 @@ public: KOKKOS_IMPL_CUDA_SYNCWARP; - if (warp_lane == 0) { // If respawn requested copy respawn data back to main memory - if(shared_memory_task_copy->as_runnable_task().get_respawn_flag()) { - if(shared_memory_task_copy->as_runnable_task().has_predecessor()) { + if (shared_memory_task_copy->as_runnable_task().get_respawn_flag()) { + if (shared_memory_task_copy->as_runnable_task().has_predecessor()) { // It's not necessary to make this a volatile write because // the next read of the predecessor is on this thread in complete, // and the predecessor is cleared there (using a volatile write) current_task->as_runnable_task().acquire_predecessor_from( - shared_memory_task_copy->as_runnable_task() - ); + shared_memory_task_copy->as_runnable_task()); } // It may not necessary to make this a volatile write, since the @@ -224,39 +217,35 @@ public: // where else the priority would be read after it is scheduled // by this thread; for now, we leave it volatile, but we should // benchmark the cost of this.) - current_task.as_volatile()->set_priority(shared_memory_task_copy->get_priority()); + current_task.as_volatile()->set_priority( + shared_memory_task_copy->get_priority()); // It's not necessary to make this a volatile write, since the // next read of it (if true) will be by this thread in `complete()`, // which will unset the flag (using volatile) once it has handled // the respawn current_task->as_runnable_task().set_respawn_flag(); - } - queue.complete( - (*std::move(current_task)).as_runnable_task(), - team_scheduler.team_scheduler_info() - ); + queue.complete((*std::move(current_task)).as_runnable_task(), + team_scheduler.team_scheduler_info()); } - } } } - static - void execute(scheduler_type const& scheduler) - { - const int shared_per_warp = 2048 ; + static void execute(scheduler_type const& scheduler) { + const int shared_per_warp = 2048; const dim3 grid(Kokkos::Impl::cuda_internal_multiprocessor_count(), 1, 1); const dim3 block(1, Kokkos::Impl::CudaTraits::WarpSize, warps_per_block); - const int shared_total = shared_per_warp * warps_per_block; + const int shared_total = shared_per_warp * warps_per_block; const cudaStream_t stream = nullptr; KOKKOS_ASSERT( - static_cast(grid.x * grid.y * grid.z * block.x * block.y * block.z) - == static_cast(get_max_team_count(scheduler.get_execution_space()) * Kokkos::Impl::CudaTraits::WarpSize) - ); + static_cast(grid.x * grid.y * grid.z * block.x * block.y * + block.z) == + static_cast(get_max_team_count(scheduler.get_execution_space()) * + Kokkos::Impl::CudaTraits::WarpSize)); auto& queue = scheduler.queue(); @@ -265,7 +254,8 @@ public: // Query the stack size, in bytes: size_t previous_stack_size = 0; - CUDA_SAFE_CALL(cudaDeviceGetLimit(&previous_stack_size, cudaLimitStackSize)); + CUDA_SAFE_CALL( + cudaDeviceGetLimit(&previous_stack_size, cudaLimitStackSize)); // If not large enough then set the stack size, in bytes: @@ -275,45 +265,45 @@ public: CUDA_SAFE_CALL(cudaDeviceSetLimit(cudaLimitStackSize, larger_stack_size)); } - cuda_task_queue_execute<<>>(scheduler, shared_per_warp); + cuda_task_queue_execute<<>>( + scheduler, shared_per_warp); CUDA_SAFE_CALL(cudaGetLastError()); CUDA_SAFE_CALL(cudaDeviceSynchronize()); if (previous_stack_size < larger_stack_size) { - CUDA_SAFE_CALL(cudaDeviceSetLimit(cudaLimitStackSize, previous_stack_size)); + CUDA_SAFE_CALL( + cudaDeviceSetLimit(cudaLimitStackSize, previous_stack_size)); } } template static - // TODO @tasking @optimiazation DSH specialize this for trivially destructible types - void - get_function_pointer( - typename TaskType::function_type& ptr, - typename TaskType::destroy_type& dtor - ) - { + // TODO @tasking @optimiazation DSH specialize this for trivially + // destructible types + void + get_function_pointer(typename TaskType::function_type& ptr, + typename TaskType::destroy_type& dtor) { using function_type = typename TaskType::function_type; - using destroy_type = typename TaskType::destroy_type; + using destroy_type = typename TaskType::destroy_type; // TODO @tasking @minor DSH make sure there aren't any alignment concerns? - void* storage = cuda_internal_scratch_unified( - Kokkos::Cuda(), - sizeof(function_type) + sizeof(destroy_type) - ); + void* storage = cuda_internal_scratch_unified( + Kokkos::Cuda(), sizeof(function_type) + sizeof(destroy_type)); function_type* ptr_ptr = (function_type*)storage; - destroy_type* dtor_ptr = (destroy_type*)((char*)storage + sizeof(function_type)); + destroy_type* dtor_ptr = + (destroy_type*)((char*)storage + sizeof(function_type)); - CUDA_SAFE_CALL( cudaDeviceSynchronize() ); + CUDA_SAFE_CALL(cudaDeviceSynchronize()); - set_cuda_task_base_apply_function_pointer<<<1,1>>>(ptr_ptr, dtor_ptr); + set_cuda_task_base_apply_function_pointer + <<<1, 1>>>(ptr_ptr, dtor_ptr); - CUDA_SAFE_CALL( cudaGetLastError() ); - CUDA_SAFE_CALL( cudaDeviceSynchronize() ); + CUDA_SAFE_CALL(cudaGetLastError()); + CUDA_SAFE_CALL(cudaDeviceSynchronize()); - ptr = *ptr_ptr; + ptr = *ptr_ptr; dtor = *dtor_ptr; } }; @@ -321,144 +311,133 @@ public: //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- -template +template class TaskQueueSpecializationConstrained< - Scheduler, - typename std::enable_if< - std::is_same::value - >::type -> -{ -public: - - using scheduler_type = Scheduler; + Scheduler, + typename std::enable_if::value>::type> { + public: + using scheduler_type = Scheduler; using execution_space = Kokkos::Cuda; - using memory_space = Kokkos::CudaUVMSpace; - using member_type = TaskExec ; + using memory_space = Kokkos::CudaUVMSpace; + using member_type = TaskExec; enum : long { max_league_size = 16 }; KOKKOS_INLINE_FUNCTION - static - void iff_single_thread_recursive_execute( scheduler_type const& ) {} + static void iff_single_thread_recursive_execute(scheduler_type const&) {} - __device__ - static void driver(scheduler_type scheduler, int32_t shmem_per_warp) - { - using queue_type = typename scheduler_type::queue_type; + __device__ static void driver(scheduler_type scheduler, + int32_t shmem_per_warp) { + using queue_type = typename scheduler_type::queue_type; using task_root_type = TaskBase; extern __shared__ int32_t shmem_all[]; - task_root_type* const end = (task_root_type *) task_root_type::EndTag ; + task_root_type* const end = (task_root_type*)task_root_type::EndTag; task_root_type* const no_more_tasks_sentinel = nullptr; - int32_t * const warp_shmem = - shmem_all + ( threadIdx.z * shmem_per_warp ) / sizeof(int32_t); + int32_t* const warp_shmem = + shmem_all + (threadIdx.z * shmem_per_warp) / sizeof(int32_t); - task_root_type * const task_shmem = (task_root_type *) warp_shmem ; + task_root_type* const task_shmem = (task_root_type*)warp_shmem; - const int warp_lane = threadIdx.x + threadIdx.y * blockDim.x ; + const int warp_lane = threadIdx.x + threadIdx.y * blockDim.x; member_type single_exec(scheduler, warp_shmem, 1); member_type team_exec(scheduler, warp_shmem, blockDim.y); auto& team_queue = team_exec.scheduler().queue(); - task_root_type * task_ptr = no_more_tasks_sentinel; + task_root_type* task_ptr = no_more_tasks_sentinel; // Loop until all queues are empty and no tasks in flight do { - // Each team lead attempts to acquire either a thread team task // or collection of single thread tasks for the team. - if ( 0 == warp_lane ) { - - if( *((volatile int *) & team_queue.m_ready_count) > 0 ) { + if (0 == warp_lane) { + if (*((volatile int*)&team_queue.m_ready_count) > 0) { task_ptr = end; // Attempt to acquire a task // Loop by priority and then type - for ( int i = 0 ; i < queue_type::NumQueue && end == task_ptr ; ++i ) { - for ( int j = 0 ; j < 2 && end == task_ptr ; ++j ) { - task_ptr = queue_type::pop_ready_task( & team_queue.m_ready[i][j] ); + for (int i = 0; i < queue_type::NumQueue && end == task_ptr; ++i) { + for (int j = 0; j < 2 && end == task_ptr; ++j) { + task_ptr = queue_type::pop_ready_task(&team_queue.m_ready[i][j]); } } - } - else { + } else { // returns nullptr if and only if all other queues have a ready // count of 0 also. Otherwise, returns a task from another queue // or `end` if one couldn't be popped task_ptr = team_queue.attempt_to_steal_task(); - #if 0 +#if 0 if(task != no_more_tasks_sentinel && task != end) { std::printf("task stolen on rank %d\n", team_exec.league_rank()); } - #endif +#endif } - } // Synchronize warp with memory fence before broadcasting task pointer: // KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN( "A" ); - KOKKOS_IMPL_CUDA_SYNCWARP ; + KOKKOS_IMPL_CUDA_SYNCWARP; // Broadcast task pointer: - ((int*) & task_ptr )[0] = KOKKOS_IMPL_CUDA_SHFL( ((int*) & task_ptr )[0] , 0 , 32 ); - ((int*) & task_ptr )[1] = KOKKOS_IMPL_CUDA_SHFL( ((int*) & task_ptr )[1] , 0 , 32 ); - - #if defined( KOKKOS_DEBUG ) - KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN( "TaskQueue CUDA task_ptr" ); - #endif + ((int*)&task_ptr)[0] = KOKKOS_IMPL_CUDA_SHFL(((int*)&task_ptr)[0], 0, 32); + ((int*)&task_ptr)[1] = KOKKOS_IMPL_CUDA_SHFL(((int*)&task_ptr)[1], 0, 32); - if ( 0 == task_ptr ) break ; // 0 == queue->m_ready_count +#if defined(KOKKOS_DEBUG) + KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN("TaskQueue CUDA task_ptr"); +#endif - if ( end != task_ptr ) { + if (0 == task_ptr) break; // 0 == queue->m_ready_count + if (end != task_ptr) { // Whole warp copy task's closure to/from shared memory. // Use all threads of warp for coalesced read/write. int32_t const b = sizeof(task_root_type) / sizeof(int32_t); - int32_t const e = *((int32_t volatile *)( & task_ptr->m_alloc_size )) / sizeof(int32_t); + int32_t const e = + *((int32_t volatile*)(&task_ptr->m_alloc_size)) / sizeof(int32_t); - int32_t volatile * const task_mem = (int32_t volatile *) task_ptr ; + int32_t volatile* const task_mem = (int32_t volatile*)task_ptr; KOKKOS_ASSERT(e * sizeof(int32_t) < shmem_per_warp); // copy task closure from global to shared memory: - for ( int32_t i = warp_lane ; i < e ; i += CudaTraits::WarpSize ) { - warp_shmem[i] = task_mem[i] ; + for (int32_t i = warp_lane; i < e; i += CudaTraits::WarpSize) { + warp_shmem[i] = task_mem[i]; } // Synchronize threads of the warp and insure memory // writes are visible to all threads in the warp. // KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN( "B" ); - KOKKOS_IMPL_CUDA_SYNCWARP ; + KOKKOS_IMPL_CUDA_SYNCWARP; - if ( task_root_type::TaskTeam == task_shmem->m_task_type ) { + if (task_root_type::TaskTeam == task_shmem->m_task_type) { // Thread Team Task - (*task_shmem->m_apply)( task_shmem , & team_exec ); - } - else if ( 0 == threadIdx.y ) { + (*task_shmem->m_apply)(task_shmem, &team_exec); + } else if (0 == threadIdx.y) { // Single Thread Task - (*task_shmem->m_apply)( task_shmem , & single_exec ); + (*task_shmem->m_apply)(task_shmem, &single_exec); } // Synchronize threads of the warp and insure memory // writes are visible to all threads in the warp. // KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN( "C" ); - KOKKOS_IMPL_CUDA_SYNCWARP ; + KOKKOS_IMPL_CUDA_SYNCWARP; // copy task closure from shared to global memory: - for ( int32_t i = b + warp_lane ; i < e ; i += CudaTraits::WarpSize ) { - task_mem[i] = warp_shmem[i] ; + for (int32_t i = b + warp_lane; i < e; i += CudaTraits::WarpSize) { + task_mem[i] = warp_shmem[i]; } // Synchronize threads of the warp and insure memory @@ -466,99 +445,96 @@ public: // respawn or completion. // KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN( "D" ); - KOKKOS_IMPL_CUDA_SYNCWARP ; + KOKKOS_IMPL_CUDA_SYNCWARP; // If respawn requested copy respawn data back to main memory - if ( 0 == warp_lane ) { - - if ( ((task_root_type *) task_root_type::LockTag) != task_shmem->m_next ) { - ( (volatile task_root_type *) task_ptr )->m_next = task_shmem->m_next ; - ( (volatile task_root_type *) task_ptr )->m_priority = task_shmem->m_priority ; + if (0 == warp_lane) { + if (((task_root_type*)task_root_type::LockTag) != + task_shmem->m_next) { + ((volatile task_root_type*)task_ptr)->m_next = task_shmem->m_next; + ((volatile task_root_type*)task_ptr)->m_priority = + task_shmem->m_priority; } - team_queue.complete( task_ptr ); + team_queue.complete(task_ptr); } - } - } while(1); + } while (1); } - static - void execute(scheduler_type const& scheduler) - { - const int shared_per_warp = 2048 ; - const int warps_per_block = 4 ; - const dim3 grid( Kokkos::Impl::cuda_internal_multiprocessor_count() , 1 , 1 ); - //const dim3 grid( 1 , 1 , 1 ); - const dim3 block( 1 , Kokkos::Impl::CudaTraits::WarpSize , warps_per_block ); - const int shared_total = shared_per_warp * warps_per_block ; - const cudaStream_t stream = 0 ; + static void execute(scheduler_type const& scheduler) { + const int shared_per_warp = 2048; + const int warps_per_block = 4; + const dim3 grid(Kokkos::Impl::cuda_internal_multiprocessor_count(), 1, 1); + // const dim3 grid( 1 , 1 , 1 ); + const dim3 block(1, Kokkos::Impl::CudaTraits::WarpSize, warps_per_block); + const int shared_total = shared_per_warp * warps_per_block; + const cudaStream_t stream = 0; auto& queue = scheduler.queue(); queue.initialize_team_queues(warps_per_block * grid.x); - CUDA_SAFE_CALL( cudaDeviceSynchronize() ); + CUDA_SAFE_CALL(cudaDeviceSynchronize()); // Query the stack size, in bytes: - size_t previous_stack_size = 0 ; - CUDA_SAFE_CALL( cudaDeviceGetLimit( & previous_stack_size , cudaLimitStackSize ) ); + size_t previous_stack_size = 0; + CUDA_SAFE_CALL( + cudaDeviceGetLimit(&previous_stack_size, cudaLimitStackSize)); // If not large enough then set the stack size, in bytes: - const size_t larger_stack_size = 2048 ; + const size_t larger_stack_size = 2048; - if ( previous_stack_size < larger_stack_size ) { - CUDA_SAFE_CALL( cudaDeviceSetLimit( cudaLimitStackSize , larger_stack_size ) ); + if (previous_stack_size < larger_stack_size) { + CUDA_SAFE_CALL(cudaDeviceSetLimit(cudaLimitStackSize, larger_stack_size)); } - cuda_task_queue_execute<<< grid , block , shared_total , stream >>>( scheduler , shared_per_warp ); + cuda_task_queue_execute<<>>( + scheduler, shared_per_warp); - CUDA_SAFE_CALL( cudaGetLastError() ); + CUDA_SAFE_CALL(cudaGetLastError()); - CUDA_SAFE_CALL( cudaDeviceSynchronize() ); + CUDA_SAFE_CALL(cudaDeviceSynchronize()); - if ( previous_stack_size < larger_stack_size ) { - CUDA_SAFE_CALL( cudaDeviceSetLimit( cudaLimitStackSize , previous_stack_size ) ); + if (previous_stack_size < larger_stack_size) { + CUDA_SAFE_CALL( + cudaDeviceSetLimit(cudaLimitStackSize, previous_stack_size)); } - } - template< typename TaskType > - static - void - get_function_pointer( - typename TaskType::function_type& ptr, - typename TaskType::destroy_type& dtor - ) - { - using function_type = typename TaskType::function_type; - using destroy_type = typename TaskType::destroy_type; - - void* storage = cuda_internal_scratch_unified( - Kokkos::Cuda(), - sizeof(function_type) + sizeof(destroy_type) - ); - function_type* ptr_ptr = (function_type*)storage; - destroy_type* dtor_ptr = (destroy_type*)((char*)storage + sizeof(function_type)); + template + static void get_function_pointer(typename TaskType::function_type& ptr, + typename TaskType::destroy_type& dtor) { + using function_type = typename TaskType::function_type; + using destroy_type = typename TaskType::destroy_type; - CUDA_SAFE_CALL( cudaDeviceSynchronize() ); + void* storage = cuda_internal_scratch_unified( + Kokkos::Cuda(), sizeof(function_type) + sizeof(destroy_type)); + function_type* ptr_ptr = (function_type*)storage; + destroy_type* dtor_ptr = + (destroy_type*)((char*)storage + sizeof(function_type)); - set_cuda_task_base_apply_function_pointer<<<1,1>>>(ptr_ptr, dtor_ptr); + CUDA_SAFE_CALL(cudaDeviceSynchronize()); - CUDA_SAFE_CALL( cudaGetLastError() ); - CUDA_SAFE_CALL( cudaDeviceSynchronize() ); + set_cuda_task_base_apply_function_pointer + <<<1, 1>>>(ptr_ptr, dtor_ptr); - ptr = *ptr_ptr; - dtor = *dtor_ptr; + CUDA_SAFE_CALL(cudaGetLastError()); + CUDA_SAFE_CALL(cudaDeviceSynchronize()); - } + ptr = *ptr_ptr; + dtor = *dtor_ptr; + } }; -extern template class TaskQueue< Kokkos::Cuda, default_tasking_memory_space_for_execution_space_t > ; +extern template class TaskQueue< + Kokkos::Cuda, + default_tasking_memory_space_for_execution_space_t>; -}} /* namespace Kokkos::Impl */ +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -589,85 +565,82 @@ namespace Impl { * warp synchronizing functions must not be called. */ template -class TaskExec -{ -private: - +class TaskExec { + private: enum : int { WarpSize = Kokkos::Impl::CudaTraits::WarpSize }; - TaskExec( TaskExec && ) = delete ; - TaskExec( TaskExec const & ) = delete ; - TaskExec & operator = ( TaskExec && ) = delete ; - TaskExec & operator = ( TaskExec const & ) = delete ; + TaskExec(TaskExec&&) = delete; + TaskExec(TaskExec const&) = delete; + TaskExec& operator=(TaskExec&&) = delete; + TaskExec& operator=(TaskExec const&) = delete; - friend class Kokkos::Impl::TaskQueue< Kokkos::Cuda, default_tasking_memory_space_for_execution_space_t > ; + friend class Kokkos::Impl::TaskQueue< + Kokkos::Cuda, + default_tasking_memory_space_for_execution_space_t>; template friend class Kokkos::Impl::TaskQueueSpecializationConstrained; template friend class Kokkos::Impl::TaskQueueSpecialization; - int32_t * m_team_shmem ; - const int m_team_size ; + int32_t* m_team_shmem; + const int m_team_size; Scheduler m_scheduler; // If constructed with arg_team_size == 1 the object // can only be used by 0 == threadIdx.y. KOKKOS_INLINE_FUNCTION - TaskExec( - Scheduler const& parent_scheduler, - int32_t* arg_team_shmem, - int arg_team_size = blockDim.y - ) - : m_team_shmem(arg_team_shmem), - m_team_size(arg_team_size), - m_scheduler(parent_scheduler.get_team_scheduler(league_rank())) - { } - -public: + TaskExec(Scheduler const& parent_scheduler, int32_t* arg_team_shmem, + int arg_team_size = blockDim.y) + : m_team_shmem(arg_team_shmem), + m_team_size(arg_team_size), + m_scheduler(parent_scheduler.get_team_scheduler(league_rank())) {} + public: using thread_team_member = TaskExec; -#if defined( __CUDA_ARCH__ ) - __device__ int team_rank() const { return threadIdx.y ; } - __device__ int team_size() const { return m_team_size ; } +#if defined(__CUDA_ARCH__) + __device__ int team_rank() const { return threadIdx.y; } + __device__ int team_size() const { return m_team_size; } //__device__ int league_rank() const { return threadIdx.z; } - __device__ int league_rank() const { return blockIdx.x * blockDim.z + threadIdx.z; } + __device__ int league_rank() const { + return blockIdx.x * blockDim.z + threadIdx.z; + } __device__ int league_size() const { return blockDim.z * gridDim.x; } - __device__ void team_barrier() const - { - if ( 1 < m_team_size ) { - KOKKOS_IMPL_CUDA_SYNCWARP ; - } + __device__ void team_barrier() const { + if (1 < m_team_size) { + KOKKOS_IMPL_CUDA_SYNCWARP; } + } - template< class ValueType > - __device__ void team_broadcast( ValueType & val , const int thread_id ) const - { - if ( 1 < m_team_size ) { - // WarpSize = blockDim.X * blockDim.y - // thread_id < blockDim.y - ValueType tmp( val ); // input might not be register variable - cuda_shfl( val, tmp, blockDim.x * thread_id, WarpSize ); - } + template + __device__ void team_broadcast(ValueType& val, const int thread_id) const { + if (1 < m_team_size) { + // WarpSize = blockDim.X * blockDim.y + // thread_id < blockDim.y + ValueType tmp(val); // input might not be register variable + Impl::in_place_shfl(val, tmp, blockDim.x * thread_id, WarpSize); } + } #else - __host__ int team_rank() const { return 0 ; } - __host__ int team_size() const { return 0 ; } + __host__ int team_rank() const { return 0; } + __host__ int team_size() const { return 0; } __host__ int league_rank() const { return 0; } __host__ int league_size() const { return 0; } __host__ void team_barrier() const {} - template< class ValueType > - __host__ void team_broadcast( ValueType & , const int ) const {} + template + __host__ void team_broadcast(ValueType&, const int) const {} #endif - KOKKOS_INLINE_FUNCTION Scheduler const& scheduler() const noexcept { return m_scheduler; } + KOKKOS_INLINE_FUNCTION Scheduler const& scheduler() const noexcept { + return m_scheduler; + } KOKKOS_INLINE_FUNCTION Scheduler& scheduler() noexcept { return m_scheduler; } - }; -}} /* namespace Kokkos::Impl */ +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -675,144 +648,137 @@ public: namespace Kokkos { namespace Impl { -template -struct TeamThreadRangeBoundariesStruct> -{ - using index_type = iType; +template +struct TeamThreadRangeBoundariesStruct> { + using index_type = iType; using member_type = TaskExec; - const iType start ; - const iType end ; - const iType increment ; + const iType start; + const iType end; + const iType increment; member_type const& thread; -#if defined( __CUDA_ARCH__ ) - - __device__ inline - TeamThreadRangeBoundariesStruct - ( member_type const& arg_thread, const iType& arg_count) - : start( threadIdx.y ) - , end(arg_count) - , increment( blockDim.y ) - , thread(arg_thread) - {} - - __device__ inline - TeamThreadRangeBoundariesStruct - ( member_type const& arg_thread - , const iType & arg_start - , const iType & arg_end - ) - : start( arg_start + threadIdx.y ) - , end( arg_end) - , increment( blockDim.y ) - , thread( arg_thread ) - {} +#if defined(__CUDA_ARCH__) + + __device__ inline TeamThreadRangeBoundariesStruct( + member_type const& arg_thread, const iType& arg_count) + : start(threadIdx.y), + end(arg_count), + increment(blockDim.y), + thread(arg_thread) {} + + __device__ inline TeamThreadRangeBoundariesStruct( + member_type const& arg_thread, const iType& arg_start, + const iType& arg_end) + : start(arg_start + threadIdx.y), + end(arg_end), + increment(blockDim.y), + thread(arg_thread) {} #else - TeamThreadRangeBoundariesStruct - ( member_type const& arg_thread, const iType& arg_count); + TeamThreadRangeBoundariesStruct(member_type const& arg_thread, + const iType& arg_count); - TeamThreadRangeBoundariesStruct - ( member_type const& arg_thread - , const iType & arg_start - , const iType & arg_end - ); + TeamThreadRangeBoundariesStruct(member_type const& arg_thread, + const iType& arg_start, const iType& arg_end); #endif - }; //---------------------------------------------------------------------------- -template -struct ThreadVectorRangeBoundariesStruct > -{ - using index_type = iType; +template +struct ThreadVectorRangeBoundariesStruct> { + using index_type = iType; using member_type = TaskExec; - const index_type start ; - const index_type end ; - const index_type increment ; + const index_type start; + const index_type end; + const index_type increment; const member_type& thread; -#if defined( __CUDA_ARCH__ ) - - __device__ inline - ThreadVectorRangeBoundariesStruct - ( member_type const& arg_thread, const index_type& arg_count ) - : start( threadIdx.x ) - , end(arg_count) - , increment( blockDim.x ) - , thread(arg_thread) - {} - - __device__ inline - ThreadVectorRangeBoundariesStruct - ( member_type const& arg_thread, const index_type& arg_begin, const index_type& arg_end ) - : start( arg_begin + threadIdx.x ) - , end(arg_end) - , increment( blockDim.x ) - , thread(arg_thread) - {} +#if defined(__CUDA_ARCH__) + + __device__ inline ThreadVectorRangeBoundariesStruct( + member_type const& arg_thread, const index_type& arg_count) + : start(threadIdx.x), + end(arg_count), + increment(blockDim.x), + thread(arg_thread) {} + + __device__ inline ThreadVectorRangeBoundariesStruct( + member_type const& arg_thread, const index_type& arg_begin, + const index_type& arg_end) + : start(arg_begin + threadIdx.x), + end(arg_end), + increment(blockDim.x), + thread(arg_thread) {} #else - ThreadVectorRangeBoundariesStruct - ( member_type const& arg_thread, const index_type& arg_count ); + ThreadVectorRangeBoundariesStruct(member_type const& arg_thread, + const index_type& arg_count); - ThreadVectorRangeBoundariesStruct - ( member_type const& arg_thread, const index_type& arg_begin, const index_type& arg_end); + ThreadVectorRangeBoundariesStruct(member_type const& arg_thread, + const index_type& arg_begin, + const index_type& arg_end); #endif - }; -}} /* namespace Kokkos::Impl */ +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- namespace Kokkos { -//template -//KOKKOS_INLINE_FUNCTION -//Impl::TeamThreadRangeBoundariesStruct< iType, Impl::TaskExec< Kokkos::Cuda > > -//TeamThreadRange( const Impl::TaskExec< Kokkos::Cuda > & thread, const iType & count ) +// template +// KOKKOS_INLINE_FUNCTION +// Impl::TeamThreadRangeBoundariesStruct< iType, Impl::TaskExec< Kokkos::Cuda > +// > TeamThreadRange( const Impl::TaskExec< Kokkos::Cuda > & thread, const iType +// & count ) //{ -// return Impl::TeamThreadRangeBoundariesStruct< iType, Impl::TaskExec< Kokkos::Cuda > >( thread, count ); +// return Impl::TeamThreadRangeBoundariesStruct< iType, Impl::TaskExec< +// Kokkos::Cuda > >( thread, count ); //} // -//template -//KOKKOS_INLINE_FUNCTION -//Impl::TeamThreadRangeBoundariesStruct +// template +// KOKKOS_INLINE_FUNCTION +// Impl::TeamThreadRangeBoundariesStruct // < typename std::common_type::type // , Impl::TaskExec< Kokkos::Cuda > > -//TeamThreadRange( const Impl::TaskExec< Kokkos::Cuda > & thread +// TeamThreadRange( const Impl::TaskExec< Kokkos::Cuda > & thread // , const iType1 & begin, const iType2 & end ) //{ // typedef typename std::common_type< iType1, iType2 >::type iType; -// return Impl::TeamThreadRangeBoundariesStruct< iType, Impl::TaskExec< Kokkos::Cuda > >( +// return Impl::TeamThreadRangeBoundariesStruct< iType, Impl::TaskExec< +// Kokkos::Cuda > >( // thread, iType(begin), iType(end) ); //} // -//template -//KOKKOS_INLINE_FUNCTION -//Impl::ThreadVectorRangeBoundariesStruct > -//ThreadVectorRange( const Impl::TaskExec< Kokkos::Cuda > & thread +// template +// KOKKOS_INLINE_FUNCTION +// Impl::ThreadVectorRangeBoundariesStruct +// > ThreadVectorRange( const Impl::TaskExec< Kokkos::Cuda > & thread // , const iType & count ) //{ -// return Impl::ThreadVectorRangeBoundariesStruct >(thread,count); +// return Impl::ThreadVectorRangeBoundariesStruct >(thread,count); //} // -//template -//KOKKOS_INLINE_FUNCTION -//Impl::ThreadVectorRangeBoundariesStruct > -//ThreadVectorRange( const Impl::TaskExec< Kokkos::Cuda > & thread +// template +// KOKKOS_INLINE_FUNCTION +// Impl::ThreadVectorRangeBoundariesStruct +// > ThreadVectorRange( const Impl::TaskExec< Kokkos::Cuda > & thread // , const iType & arg_begin // , const iType & arg_end ) //{ -// return Impl::ThreadVectorRangeBoundariesStruct >(thread,arg_begin,arg_end); +// return Impl::ThreadVectorRangeBoundariesStruct >(thread,arg_begin,arg_end); //} // KOKKOS_INLINE_FUNCTION @@ -829,78 +795,70 @@ namespace Kokkos { // return Impl::VectorSingleStruct >(thread); // } -/** \brief Inter-thread parallel_for. Executes lambda(iType i) for each i=0..N-1. +/** \brief Inter-thread parallel_for. Executes lambda(iType i) for each + * i=0..N-1. * * The range i=0..N-1 is mapped to all threads of the the calling thread team. * This functionality requires C++11 support. -*/ -template -KOKKOS_INLINE_FUNCTION -void parallel_for - ( const Impl::TeamThreadRangeBoundariesStruct >& loop_boundaries - , const Lambda& lambda - ) -{ - for( iType i = loop_boundaries.start; i < loop_boundaries.end; i+=loop_boundaries.increment) { + */ +template +KOKKOS_INLINE_FUNCTION void parallel_for( + const Impl::TeamThreadRangeBoundariesStruct< + iType, Impl::TaskExec>& loop_boundaries, + const Lambda& lambda) { + for (iType i = loop_boundaries.start; i < loop_boundaries.end; + i += loop_boundaries.increment) { lambda(i); } } -template< typename iType, class Lambda, class Scheduler > -KOKKOS_INLINE_FUNCTION -void parallel_for - (const Impl::ThreadVectorRangeBoundariesStruct >& loop_boundaries, - const Lambda & lambda) { - for( iType i = loop_boundaries.start; i < loop_boundaries.end; i+=loop_boundaries.increment) { +template +KOKKOS_INLINE_FUNCTION void parallel_for( + const Impl::ThreadVectorRangeBoundariesStruct< + iType, Impl::TaskExec>& loop_boundaries, + const Lambda& lambda) { + for (iType i = loop_boundaries.start; i < loop_boundaries.end; + i += loop_boundaries.increment) { lambda(i); } } // reduce across corresponding lanes between team members within warp // assume stride*team_size == warp_size -template< typename ValueType, class JoinType > -KOKKOS_INLINE_FUNCTION -void strided_shfl_warp_reduction - (const JoinType& join, - ValueType& val, - int team_size, - int stride) -{ - for (int lane_delta=(team_size*stride)>>1; lane_delta>=stride; lane_delta>>=1) { - join(val, Kokkos::shfl_down(val, lane_delta, team_size*stride)); +template +KOKKOS_INLINE_FUNCTION void strided_shfl_warp_reduction(const JoinType& join, + ValueType& val, + int team_size, + int stride) { + for (int lane_delta = (team_size * stride) >> 1; lane_delta >= stride; + lane_delta >>= 1) { + join(val, Kokkos::shfl_down(val, lane_delta, team_size * stride)); } } // multiple within-warp non-strided reductions -template< typename ValueType, class JoinType > -KOKKOS_INLINE_FUNCTION -void multi_shfl_warp_reduction - (const JoinType& join, - ValueType& val, - int vec_length) -{ - for (int lane_delta=vec_length>>1; lane_delta; lane_delta>>=1) { +template +KOKKOS_INLINE_FUNCTION void multi_shfl_warp_reduction(const JoinType& join, + ValueType& val, + int vec_length) { + for (int lane_delta = vec_length >> 1; lane_delta; lane_delta >>= 1) { join(val, Kokkos::shfl_down(val, lane_delta, vec_length)); } } // broadcast within warp -template< class ValueType > -KOKKOS_INLINE_FUNCTION -ValueType shfl_warp_broadcast - (ValueType& val, - int src_lane, - int width) -{ - if ( 1 < width ) { +template +KOKKOS_INLINE_FUNCTION ValueType shfl_warp_broadcast(ValueType& val, + int src_lane, int width) { + if (1 < width) { return Kokkos::shfl(val, src_lane, width); - } - else { - return val ; + } else { + return val; } } -/*// all-reduce across corresponding vector lanes between team members within warp +/*// all-reduce across corresponding vector lanes between team members within +warp // assume vec_length*team_size == warp_size // blockDim.x == vec_length == stride // blockDim.y == team_size @@ -909,14 +867,13 @@ ValueType shfl_warp_broadcast template< typename iType, class Lambda, typename ValueType, class JoinType > KOKKOS_INLINE_FUNCTION void parallel_reduce - (const Impl::TeamThreadRangeBoundariesStruct >& loop_boundaries, - const Lambda & lambda, - const JoinType& join, + (const Impl::TeamThreadRangeBoundariesStruct >& loop_boundaries, const Lambda & lambda, const JoinType& join, ValueType& initialized_result) { ValueType result = initialized_result; - for( iType i = loop_boundaries.start; i < loop_boundaries.end; i+=loop_boundaries.increment) { - lambda(i,result); + for( iType i = loop_boundaries.start; i < loop_boundaries.end; +i+=loop_boundaries.increment) { lambda(i,result); } initialized_result = result; @@ -925,7 +882,8 @@ void parallel_reduce initialized_result, loop_boundaries.thread.team_size(), blockDim.x); - initialized_result = shfl_warp_broadcast( initialized_result, threadIdx.x, Impl::CudaTraits::WarpSize ); + initialized_result = shfl_warp_broadcast( initialized_result, +threadIdx.x, Impl::CudaTraits::WarpSize ); }*/ // all-reduce across corresponding vector lanes between team members within warp @@ -935,63 +893,55 @@ void parallel_reduce // blockDim.y == team_size // threadIdx.x == position in vec // threadIdx.y == member number -template< typename iType, class Lambda, typename ValueType, class Scheduler > -KOKKOS_INLINE_FUNCTION -void parallel_reduce - (const Impl::TeamThreadRangeBoundariesStruct >& loop_boundaries, - const Lambda & lambda, - ValueType& initialized_result) { - - //TODO @internal_documentation what is the point of creating this temporary? +template +KOKKOS_INLINE_FUNCTION void parallel_reduce( + const Impl::TeamThreadRangeBoundariesStruct< + iType, Impl::TaskExec>& loop_boundaries, + const Lambda& lambda, ValueType& initialized_result) { + // TODO @internal_documentation what is the point of creating this temporary? ValueType result = initialized_result; - for( iType i = loop_boundaries.start; i < loop_boundaries.end; i+=loop_boundaries.increment) { - lambda(i,result); + for (iType i = loop_boundaries.start; i < loop_boundaries.end; + i += loop_boundaries.increment) { + lambda(i, result); } initialized_result = result; - if ( 1 < loop_boundaries.thread.team_size() ) { - + if (1 < loop_boundaries.thread.team_size()) { strided_shfl_warp_reduction( - [&] (ValueType& val1, const ValueType& val2) { val1 += val2; }, - initialized_result, - loop_boundaries.thread.team_size(), - blockDim.x); + [&](ValueType& val1, const ValueType& val2) { val1 += val2; }, + initialized_result, loop_boundaries.thread.team_size(), blockDim.x); - initialized_result = - shfl_warp_broadcast( - initialized_result, threadIdx.x, Impl::CudaTraits::WarpSize ); + initialized_result = shfl_warp_broadcast( + initialized_result, threadIdx.x, Impl::CudaTraits::WarpSize); } } -template< typename iType, class Lambda, typename ReducerType, class Scheduler > -KOKKOS_INLINE_FUNCTION -void parallel_reduce - (const Impl::TeamThreadRangeBoundariesStruct >& loop_boundaries, - const Lambda & lambda, - const ReducerType& reducer) { - +template +KOKKOS_INLINE_FUNCTION void parallel_reduce( + const Impl::TeamThreadRangeBoundariesStruct< + iType, Impl::TaskExec>& loop_boundaries, + const Lambda& lambda, const ReducerType& reducer) { typedef typename ReducerType::value_type ValueType; - //TODO @internal_documentation what is the point of creating this temporary? + // TODO @internal_documentation what is the point of creating this temporary? ValueType result = ValueType(); reducer.init(result); - for( iType i = loop_boundaries.start; i < loop_boundaries.end; i+=loop_boundaries.increment) { - lambda(i,result); + for (iType i = loop_boundaries.start; i < loop_boundaries.end; + i += loop_boundaries.increment) { + lambda(i, result); } - if ( 1 < loop_boundaries.thread.team_size() ) { + if (1 < loop_boundaries.thread.team_size()) { strided_shfl_warp_reduction( - [&] (ValueType& val1, const ValueType& val2) { reducer.join(val1,val2); }, - result, - loop_boundaries.thread.team_size(), - blockDim.x); - - reducer.reference() = - shfl_warp_broadcast( - result, threadIdx.x, Impl::CudaTraits::WarpSize ); - } - else { - reducer.reference() = result ; + [&](ValueType& val1, const ValueType& val2) { + reducer.join(val1, val2); + }, + result, loop_boundaries.thread.team_size(), blockDim.x); + + reducer.reference() = shfl_warp_broadcast( + result, threadIdx.x, Impl::CudaTraits::WarpSize); + } else { + reducer.reference() = result; } } // all-reduce within team members within warp @@ -1003,19 +953,19 @@ void parallel_reduce /*template< typename iType, class Lambda, typename ValueType, class JoinType > KOKKOS_INLINE_FUNCTION void parallel_reduce - (const Impl::ThreadVectorRangeBoundariesStruct >& loop_boundaries, - const Lambda & lambda, - const JoinType& join, + (const Impl::ThreadVectorRangeBoundariesStruct >& loop_boundaries, const Lambda & lambda, const JoinType& join, ValueType& initialized_result) { ValueType result = initialized_result; - for( iType i = loop_boundaries.start; i < loop_boundaries.end; i+=loop_boundaries.increment) { - lambda(i,result); + for( iType i = loop_boundaries.start; i < loop_boundaries.end; +i+=loop_boundaries.increment) { lambda(i,result); } initialized_result = result; - multi_shfl_warp_reduction(join, initialized_result, blockDim.x); - initialized_result = shfl_warp_broadcast( initialized_result, 0, blockDim.x ); + multi_shfl_warp_reduction(join, initialized_result, +blockDim.x); initialized_result = shfl_warp_broadcast( +initialized_result, 0, blockDim.x ); }*/ // all-reduce within team members within warp @@ -1025,60 +975,56 @@ void parallel_reduce // blockDim.y == team_size // threadIdx.x == position in vec // threadIdx.y == member number -template< typename iType, class Lambda, typename ValueType, class Scheduler > -KOKKOS_INLINE_FUNCTION -void parallel_reduce - (const Impl::ThreadVectorRangeBoundariesStruct >& loop_boundaries, - const Lambda & lambda, - ValueType& initialized_result) { - +template +KOKKOS_INLINE_FUNCTION void parallel_reduce( + const Impl::ThreadVectorRangeBoundariesStruct< + iType, Impl::TaskExec>& loop_boundaries, + const Lambda& lambda, ValueType& initialized_result) { ValueType result = initialized_result; - for( iType i = loop_boundaries.start; i < loop_boundaries.end; i+=loop_boundaries.increment) { - lambda(i,result); + for (iType i = loop_boundaries.start; i < loop_boundaries.end; + i += loop_boundaries.increment) { + lambda(i, result); } initialized_result = result; - if ( 1 < loop_boundaries.thread.team_size() ) { - //initialized_result = multi_shfl_warp_reduction( + if (1 < loop_boundaries.thread.team_size()) { + // initialized_result = multi_shfl_warp_reduction( multi_shfl_warp_reduction( - [&] (ValueType& val1, const ValueType& val2) { val1 += val2; }, - initialized_result, - blockDim.x); + [&](ValueType& val1, const ValueType& val2) { val1 += val2; }, + initialized_result, blockDim.x); initialized_result = - shfl_warp_broadcast( initialized_result, 0, blockDim.x ); + shfl_warp_broadcast(initialized_result, 0, blockDim.x); } } -template< typename iType, class Lambda, typename ReducerType, class Scheduler > -KOKKOS_INLINE_FUNCTION -void parallel_reduce - (const Impl::ThreadVectorRangeBoundariesStruct >& loop_boundaries, - const Lambda & lambda, - const ReducerType& reducer) { - +template +KOKKOS_INLINE_FUNCTION void parallel_reduce( + const Impl::ThreadVectorRangeBoundariesStruct< + iType, Impl::TaskExec>& loop_boundaries, + const Lambda& lambda, const ReducerType& reducer) { typedef typename ReducerType::value_type ValueType; ValueType result = ValueType(); reducer.init(result); - for( iType i = loop_boundaries.start; i < loop_boundaries.end; i+=loop_boundaries.increment) { - lambda(i,result); + for (iType i = loop_boundaries.start; i < loop_boundaries.end; + i += loop_boundaries.increment) { + lambda(i, result); } - if ( 1 < loop_boundaries.thread.team_size() ) { + if (1 < loop_boundaries.thread.team_size()) { multi_shfl_warp_reduction( - [&] (ValueType& val1, const ValueType& val2) { reducer.join(val1,val2); }, - result, - blockDim.x); - - reducer.reference() = - shfl_warp_broadcast( result, 0, blockDim.x ); - } - else { - reducer.reference() = result ; + [&](ValueType& val1, const ValueType& val2) { + reducer.join(val1, val2); + }, + result, blockDim.x); + + reducer.reference() = shfl_warp_broadcast(result, 0, blockDim.x); + } else { + reducer.reference() = result; } } // scan across corresponding vector lanes between team members within warp @@ -1087,61 +1033,61 @@ void parallel_reduce // blockDim.y == team_size // threadIdx.x == position in vec // threadIdx.y == member number -template< typename iType, class Closure, class Scheduler > -KOKKOS_INLINE_FUNCTION -void parallel_scan - (const Impl::TeamThreadRangeBoundariesStruct >& loop_boundaries, - const Closure & closure ) -{ +template +KOKKOS_INLINE_FUNCTION void parallel_scan( + const Impl::TeamThreadRangeBoundariesStruct< + iType, Impl::TaskExec>& loop_boundaries, + const Closure& closure) { // Extract value_type from closure - using value_type = - typename Kokkos::Impl::FunctorAnalysis - < Kokkos::Impl::FunctorPatternInterface::SCAN - , void - , Closure >::value_type ; - - if ( 1 < loop_boundaries.thread.team_size() ) { + using value_type = typename Kokkos::Impl::FunctorAnalysis< + Kokkos::Impl::FunctorPatternInterface::SCAN, void, Closure>::value_type; + if (1 < loop_boundaries.thread.team_size()) { // make sure all threads perform all loop iterations - const iType bound = loop_boundaries.end + loop_boundaries.start ; - const int lane = threadIdx.y * blockDim.x ; + const iType bound = loop_boundaries.end + loop_boundaries.start; + const int lane = threadIdx.y * blockDim.x; - value_type accum = 0 ; + value_type accum = 0; value_type val, y, local_total; - for( iType i = loop_boundaries.start; i < bound; i+=loop_boundaries.increment) { + for (iType i = loop_boundaries.start; i < bound; + i += loop_boundaries.increment) { val = 0; - if ( i < loop_boundaries.end ) closure(i,val,false); + if (i < loop_boundaries.end) closure(i, val, false); // intra-blockDim.y exclusive scan on 'val' // accum = accumulated, sum in total for this iteration // INCLUSIVE scan - for( int offset = blockDim.x ; offset < Impl::CudaTraits::WarpSize ; offset <<= 1 ) { + for (int offset = blockDim.x; offset < Impl::CudaTraits::WarpSize; + offset <<= 1) { y = Kokkos::shfl_up(val, offset, Impl::CudaTraits::WarpSize); - if(lane >= offset) { val += y; } + if (lane >= offset) { + val += y; + } } // pass accum to all threads local_total = shfl_warp_broadcast( - val, - threadIdx.x+Impl::CudaTraits::WarpSize-blockDim.x, - Impl::CudaTraits::WarpSize); + val, threadIdx.x + Impl::CudaTraits::WarpSize - blockDim.x, + Impl::CudaTraits::WarpSize); // make EXCLUSIVE scan by shifting values over one val = Kokkos::shfl_up(val, blockDim.x, Impl::CudaTraits::WarpSize); - if ( threadIdx.y == 0 ) { val = 0 ; } + if (threadIdx.y == 0) { + val = 0; + } val += accum; - if ( i < loop_boundaries.end ) closure(i,val,true); + if (i < loop_boundaries.end) closure(i, val, true); accum += local_total; } - } - else { - value_type accum = 0 ; - for( iType i = loop_boundaries.start; i < loop_boundaries.end; i+=loop_boundaries.increment) { - closure(i,accum,true); + } else { + value_type accum = 0; + for (iType i = loop_boundaries.start; i < loop_boundaries.end; + i += loop_boundaries.increment) { + closure(i, accum, true); } } } @@ -1152,57 +1098,58 @@ void parallel_scan // blockDim.y == team_size // threadIdx.x == position in vec // threadIdx.y == member number -template< typename iType, class Closure, class Scheduler > -KOKKOS_INLINE_FUNCTION -void parallel_scan - (const Impl::ThreadVectorRangeBoundariesStruct >& loop_boundaries, - const Closure & closure ) -{ +template +KOKKOS_INLINE_FUNCTION void parallel_scan( + const Impl::ThreadVectorRangeBoundariesStruct< + iType, Impl::TaskExec>& loop_boundaries, + const Closure& closure) { // Extract value_type from closure - using value_type = - typename Kokkos::Impl::FunctorAnalysis - < Kokkos::Impl::FunctorPatternInterface::SCAN - , void - , Closure >::value_type ; - - if ( 1 < loop_boundaries.thread.team_size() ) { + using value_type = typename Kokkos::Impl::FunctorAnalysis< + Kokkos::Impl::FunctorPatternInterface::SCAN, void, Closure>::value_type; + if (1 < loop_boundaries.thread.team_size()) { // make sure all threads perform all loop iterations - const iType bound = loop_boundaries.end + loop_boundaries.start ; + const iType bound = loop_boundaries.end + loop_boundaries.start; - value_type accum = 0 ; + value_type accum = 0; value_type val, y, local_total; - for( iType i = loop_boundaries.start; i < bound; i+=loop_boundaries.increment) { + for (iType i = loop_boundaries.start; i < bound; + i += loop_boundaries.increment) { val = 0; - if ( i < loop_boundaries.end ) closure(i,val,false); + if (i < loop_boundaries.end) closure(i, val, false); // intra-blockDim.x exclusive scan on 'val' // accum = accumulated, sum in total for this iteration // INCLUSIVE scan - for( int offset = 1 ; offset < blockDim.x ; offset <<= 1 ) { + for (int offset = 1; offset < blockDim.x; offset <<= 1) { y = Kokkos::shfl_up(val, offset, blockDim.x); - if(threadIdx.x >= offset) { val += y; } + if (threadIdx.x >= offset) { + val += y; + } } // pass accum to all threads - local_total = shfl_warp_broadcast(val, blockDim.x-1, blockDim.x); + local_total = + shfl_warp_broadcast(val, blockDim.x - 1, blockDim.x); // make EXCLUSIVE scan by shifting values over one val = Kokkos::shfl_up(val, 1, blockDim.x); - if ( threadIdx.x == 0 ) { val = 0 ; } + if (threadIdx.x == 0) { + val = 0; + } val += accum; - if ( i < loop_boundaries.end ) closure(i,val,true); + if (i < loop_boundaries.end) closure(i, val, true); accum += local_total; } - } - else { - value_type accum = 0 ; - for( iType i = loop_boundaries.start; i < loop_boundaries.end; i+=loop_boundaries.increment) { - closure(i,accum,true); + } else { + value_type accum = 0; + for (iType i = loop_boundaries.start; i < loop_boundaries.end; + i += loop_boundaries.increment) { + closure(i, accum, true); } } } @@ -1211,49 +1158,53 @@ void parallel_scan namespace Kokkos { - template - KOKKOS_INLINE_FUNCTION - void single(const Impl::VectorSingleStruct >& , const FunctorType& lambda) { +template +KOKKOS_INLINE_FUNCTION void single( + const Impl::VectorSingleStruct>&, + const FunctorType& lambda) { #ifdef __CUDA_ARCH__ - if(threadIdx.x == 0) lambda(); + if (threadIdx.x == 0) lambda(); #endif - } - - template - KOKKOS_INLINE_FUNCTION - void single(const Impl::ThreadSingleStruct >& , const FunctorType& lambda) { +} + +template +KOKKOS_INLINE_FUNCTION void single( + const Impl::ThreadSingleStruct>&, + const FunctorType& lambda) { #ifdef __CUDA_ARCH__ - if(threadIdx.x == 0 && threadIdx.y == 0) lambda(); + if (threadIdx.x == 0 && threadIdx.y == 0) lambda(); #endif - } - - template - KOKKOS_INLINE_FUNCTION - void single(const Impl::VectorSingleStruct >& s , const FunctorType& lambda, ValueType& val) { +} + +template +KOKKOS_INLINE_FUNCTION void single( + const Impl::VectorSingleStruct>& s, + const FunctorType& lambda, ValueType& val) { #ifdef __CUDA_ARCH__ - if(threadIdx.x == 0) lambda(val); - if ( 1 < s.team_member.team_size() ) { - val = shfl(val,0,blockDim.x); - } -#endif + if (threadIdx.x == 0) lambda(val); + if (1 < s.team_member.team_size()) { + val = shfl(val, 0, blockDim.x); } - - template - KOKKOS_INLINE_FUNCTION - void single(const Impl::ThreadSingleStruct >& single_struct, const FunctorType& lambda, ValueType& val) { -#ifdef __CUDA_ARCH__ - if(threadIdx.x == 0 && threadIdx.y == 0) { - lambda(val); - } - single_struct.team_member.team_broadcast(val,0); #endif +} + +template +KOKKOS_INLINE_FUNCTION void single( + const Impl::ThreadSingleStruct>& + single_struct, + const FunctorType& lambda, ValueType& val) { +#ifdef __CUDA_ARCH__ + if (threadIdx.x == 0 && threadIdx.y == 0) { + lambda(val); } + single_struct.team_member.team_broadcast(val, 0); +#endif +} -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- #endif /* #if defined( KOKKOS_ENABLE_TASKDAG ) */ #endif /* #ifndef KOKKOS_IMPL_CUDA_TASK_HPP */ - diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Team.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Team.hpp index 587ad6001d..ac9ab9660c 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Team.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Team.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -51,7 +52,7 @@ #include /* only compile this file if CUDA is enabled for Kokkos */ -#if defined( __CUDACC__ ) && defined( KOKKOS_ENABLE_CUDA ) +#if defined(__CUDACC__) && defined(KOKKOS_ENABLE_CUDA) #include #include @@ -72,14 +73,15 @@ namespace Kokkos { namespace Impl { -template< typename Type > +template struct CudaJoinFunctor { - typedef Type value_type ; + typedef Type value_type; KOKKOS_INLINE_FUNCTION - static void join( volatile value_type & update , - volatile const value_type & input ) - { update += input ; } + static void join(volatile value_type& update, + volatile const value_type& input) { + update += input; + } }; /**\brief Team member_type passed to TeamPolicy or TeamTask closures. @@ -101,108 +103,105 @@ struct CudaJoinFunctor { * total available shared memory must be partitioned among teams. */ class CudaTeamMember { - -public: - typedef Kokkos::Cuda execution_space ; - typedef execution_space::scratch_memory_space scratch_memory_space ; - -private: - - mutable void * m_team_reduce ; - scratch_memory_space m_team_shared ; - int m_team_reduce_size ; - int m_league_rank ; - int m_league_size ; - -public: - + public: + typedef Kokkos::Cuda execution_space; + typedef execution_space::scratch_memory_space scratch_memory_space; + + private: + mutable void* m_team_reduce; + scratch_memory_space m_team_shared; + int m_team_reduce_size; + int m_league_rank; + int m_league_size; + + public: KOKKOS_INLINE_FUNCTION - const execution_space::scratch_memory_space & team_shmem() const - { return m_team_shared.set_team_thread_mode(0,1,0) ; } + const execution_space::scratch_memory_space& team_shmem() const { + return m_team_shared.set_team_thread_mode(0, 1, 0); + } KOKKOS_INLINE_FUNCTION - const execution_space::scratch_memory_space & - team_scratch(const int& level) const - { return m_team_shared.set_team_thread_mode(level,1,0) ; } + const execution_space::scratch_memory_space& team_scratch( + const int& level) const { + return m_team_shared.set_team_thread_mode(level, 1, 0); + } KOKKOS_INLINE_FUNCTION - const execution_space::scratch_memory_space & - thread_scratch(const int& level) const - { return m_team_shared.set_team_thread_mode(level,team_size(),team_rank()) ; } - - KOKKOS_INLINE_FUNCTION int league_rank() const { return m_league_rank ; } - KOKKOS_INLINE_FUNCTION int league_size() const { return m_league_size ; } - KOKKOS_INLINE_FUNCTION int team_rank() const - { - #ifdef __CUDA_ARCH__ - return threadIdx.y ; - #else - return 0; - #endif - } + const execution_space::scratch_memory_space& thread_scratch( + const int& level) const { + return m_team_shared.set_team_thread_mode(level, team_size(), team_rank()); + } - KOKKOS_INLINE_FUNCTION int team_size() const - { - #ifdef __CUDA_ARCH__ - return blockDim.y ; - #else - return 1; - #endif - } + KOKKOS_INLINE_FUNCTION int league_rank() const { return m_league_rank; } + KOKKOS_INLINE_FUNCTION int league_size() const { return m_league_size; } + KOKKOS_INLINE_FUNCTION int team_rank() const { +#ifdef __CUDA_ARCH__ + return threadIdx.y; +#else + return 0; +#endif + } - KOKKOS_INLINE_FUNCTION void team_barrier() const - { - #ifdef __CUDA_ARCH__ - if ( 1 == blockDim.z ) __syncthreads(); // team == block - else __threadfence_block(); // team <= warp - #endif - } + KOKKOS_INLINE_FUNCTION int team_size() const { +#ifdef __CUDA_ARCH__ + return blockDim.y; +#else + return 1; +#endif + } + + KOKKOS_INLINE_FUNCTION void team_barrier() const { +#ifdef __CUDA_ARCH__ + if (1 == blockDim.z) + __syncthreads(); // team == block + else + __threadfence_block(); // team <= warp +#endif + } //-------------------------------------------------------------------------- - template - KOKKOS_INLINE_FUNCTION - void team_broadcast( ValueType & val, const int& thread_id ) const - { - #ifdef __CUDA_ARCH__ - if ( 1 == blockDim.z ) { // team == block - __syncthreads(); - // Wait for shared data write until all threads arrive here - if ( threadIdx.x == 0u && threadIdx.y == (uint32_t)thread_id ) { - *((ValueType*) m_team_reduce) = val ; - } - __syncthreads(); // Wait for shared data read until root thread writes - val = *((ValueType*) m_team_reduce); - } - else { // team <= warp - ValueType tmp( val ); // input might not be a register variable - cuda_shfl( val, tmp, blockDim.x * thread_id, blockDim.x * blockDim.y ); + template + KOKKOS_INLINE_FUNCTION void team_broadcast(ValueType& val, + const int& thread_id) const { +#ifdef __CUDA_ARCH__ + if (1 == blockDim.z) { // team == block + __syncthreads(); + // Wait for shared data write until all threads arrive here + if (threadIdx.x == 0u && threadIdx.y == (uint32_t)thread_id) { + *((ValueType*)m_team_reduce) = val; } - #endif + __syncthreads(); // Wait for shared data read until root thread writes + val = *((ValueType*)m_team_reduce); + } else { // team <= warp + ValueType tmp(val); // input might not be a register variable + Impl::in_place_shfl(val, tmp, blockDim.x * thread_id, + blockDim.x * blockDim.y); } - - template - KOKKOS_INLINE_FUNCTION - void team_broadcast( Closure const & f, ValueType & val, const int& thread_id ) const - { - #ifdef __CUDA_ARCH__ - f( val ); - - if ( 1 == blockDim.z ) { // team == block - __syncthreads(); - // Wait for shared data write until all threads arrive here - if ( threadIdx.x == 0u && threadIdx.y == (uint32_t)thread_id ) { - *((ValueType*) m_team_reduce) = val ; - } - __syncthreads(); // Wait for shared data read until root thread writes - val = *((ValueType*) m_team_reduce); - } - else { // team <= warp - ValueType tmp( val ); // input might not be a register variable - cuda_shfl( val, tmp, blockDim.x * thread_id, blockDim.x * blockDim.y ); +#endif + } + + template + KOKKOS_INLINE_FUNCTION void team_broadcast(Closure const& f, ValueType& val, + const int& thread_id) const { +#ifdef __CUDA_ARCH__ + f(val); + + if (1 == blockDim.z) { // team == block + __syncthreads(); + // Wait for shared data write until all threads arrive here + if (threadIdx.x == 0u && threadIdx.y == (uint32_t)thread_id) { + *((ValueType*)m_team_reduce) = val; } - #endif + __syncthreads(); // Wait for shared data read until root thread writes + val = *((ValueType*)m_team_reduce); + } else { // team <= warp + ValueType tmp(val); // input might not be a register variable + Impl::in_place_shfl(val, tmp, blockDim.x * thread_id, + blockDim.x * blockDim.y); } +#endif + } //-------------------------------------------------------------------------- /**\brief Reduction across a team @@ -219,24 +218,22 @@ public: * OR * ( 1 == blockDim.z ) */ - template< typename ReducerType > + template KOKKOS_INLINE_FUNCTION - typename std::enable_if< is_reducer< ReducerType >::value >::type - team_reduce( ReducerType const & reducer ) const noexcept - { - team_reduce(reducer,reducer.reference()); - } - - template< typename ReducerType > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< is_reducer< ReducerType >::value >::type - team_reduce( ReducerType const & reducer, typename ReducerType::value_type& value ) const noexcept - { - #ifdef __CUDA_ARCH__ - cuda_intra_block_reduction(reducer,value,blockDim.y); - #endif /* #ifdef __CUDA_ARCH__ */ - } + typename std::enable_if::value>::type + team_reduce(ReducerType const& reducer) const noexcept { + team_reduce(reducer, reducer.reference()); + } + template + KOKKOS_INLINE_FUNCTION + typename std::enable_if::value>::type + team_reduce(ReducerType const& reducer, + typename ReducerType::value_type& value) const noexcept { +#ifdef __CUDA_ARCH__ + cuda_intra_block_reduction(reducer, value, blockDim.y); +#endif /* #ifdef __CUDA_ARCH__ */ + } //-------------------------------------------------------------------------- /** \brief Intra-team exclusive prefix sum with team_rank() ordering @@ -248,307 +245,299 @@ public: * As such the base value for each team's scan operation is similarly * non-deterministic. */ - template< typename Type > - KOKKOS_INLINE_FUNCTION - Type team_scan( const Type & value , Type * const global_accum ) const - { - #ifdef __CUDA_ARCH__ - Type * const base_data = (Type *) m_team_reduce ; + template + KOKKOS_INLINE_FUNCTION Type team_scan(const Type& value, + Type* const global_accum) const { +#ifdef __CUDA_ARCH__ + Type* const base_data = (Type*)m_team_reduce; - __syncthreads(); // Don't write in to shared data until all threads have entered this function + __syncthreads(); // Don't write in to shared data until all threads have + // entered this function - if ( 0 == threadIdx.y ) { base_data[0] = 0 ; } + if (0 == threadIdx.y) { + base_data[0] = 0; + } - base_data[ threadIdx.y + 1 ] = value ; + base_data[threadIdx.y + 1] = value; - Impl::cuda_intra_block_reduce_scan,void>( Impl::CudaJoinFunctor() , base_data + 1 ); + Impl::cuda_intra_block_reduce_scan, void>( + Impl::CudaJoinFunctor(), base_data + 1); - if ( global_accum ) { - if ( blockDim.y == threadIdx.y + 1 ) { - base_data[ blockDim.y ] = atomic_fetch_add( global_accum , base_data[ blockDim.y ] ); - } - __syncthreads(); // Wait for atomic - base_data[ threadIdx.y ] += base_data[ blockDim.y ] ; + if (global_accum) { + if (blockDim.y == threadIdx.y + 1) { + base_data[blockDim.y] = + atomic_fetch_add(global_accum, base_data[blockDim.y]); } - - return base_data[ threadIdx.y ]; - #else - return Type(); - #endif + __syncthreads(); // Wait for atomic + base_data[threadIdx.y] += base_data[blockDim.y]; } + return base_data[threadIdx.y]; +#else + return Type(); +#endif + } + /** \brief Intra-team exclusive prefix sum with team_rank() ordering. * * The highest rank thread can compute the reduction total as * reduction_total = dev.team_scan( value ) + value ; */ - template< typename Type > - KOKKOS_INLINE_FUNCTION Type team_scan( const Type & value ) const { - return this->template team_scan( value , 0 ); + template + KOKKOS_INLINE_FUNCTION Type team_scan(const Type& value) const { + return this->template team_scan(value, 0); } //---------------------------------------- - template< typename ReducerType > + template KOKKOS_INLINE_FUNCTION static - typename std::enable_if< is_reducer< ReducerType >::value >::type - vector_reduce( ReducerType const & reducer ) { - vector_reduce(reducer,reducer.reference()); + typename std::enable_if::value>::type + vector_reduce(ReducerType const& reducer) { + vector_reduce(reducer, reducer.reference()); } - template< typename ReducerType > + template KOKKOS_INLINE_FUNCTION static - typename std::enable_if< is_reducer< ReducerType >::value >::type - vector_reduce( ReducerType const & reducer, typename ReducerType::value_type& value ) - { - - #ifdef __CUDA_ARCH__ - if(blockDim.x == 1) return; - - // Intra vector lane shuffle reduction: - typename ReducerType::value_type tmp ( value ); - typename ReducerType::value_type tmp2 = tmp; - - unsigned mask = blockDim.x==32?0xffffffff:((1<>= 1 ) ; ) { - cuda_shfl_down( tmp2 , tmp , i , blockDim.x , mask ); - if ( (int)threadIdx.x < i ) { reducer.join( tmp , tmp2 ); } + typename std::enable_if::value>::type + vector_reduce(ReducerType const& reducer, + typename ReducerType::value_type& value) { +#ifdef __CUDA_ARCH__ + if (blockDim.x == 1) return; + + // Intra vector lane shuffle reduction: + typename ReducerType::value_type tmp(value); + typename ReducerType::value_type tmp2 = tmp; + + unsigned mask = + blockDim.x == 32 + ? 0xffffffff + : ((1 << blockDim.x) - 1) + << ((threadIdx.y % (32 / blockDim.x)) * blockDim.x); + + for (int i = blockDim.x; (i >>= 1);) { + Impl::in_place_shfl_down(tmp2, tmp, i, blockDim.x, mask); + if ((int)threadIdx.x < i) { + reducer.join(tmp, tmp2); } + } - // Broadcast from root lane to all other lanes. - // Cannot use "butterfly" algorithm to avoid the broadcast - // because floating point summation is not associative - // and thus different threads could have different results. + // Broadcast from root lane to all other lanes. + // Cannot use "butterfly" algorithm to avoid the broadcast + // because floating point summation is not associative + // and thus different threads could have different results. - cuda_shfl( tmp2 , tmp , 0 , blockDim.x , mask ); - value = tmp2; - reducer.reference() = tmp2; - #endif - } + Impl::in_place_shfl(tmp2, tmp, 0, blockDim.x, mask); + value = tmp2; + reducer.reference() = tmp2; +#endif + } //-------------------------------------------------------------------------- /**\brief Global reduction across all blocks * * Return !0 if reducer contains the final value */ - template< typename ReducerType > + template KOKKOS_INLINE_FUNCTION static - typename std::enable_if< is_reducer< ReducerType >::value , int >::type - global_reduce( ReducerType const & reducer - , int * const global_scratch_flags - , void * const global_scratch_space - , void * const shmem - , int const shmem_size - ) - { - #ifdef __CUDA_ARCH__ - - typedef typename ReducerType::value_type value_type ; - typedef value_type volatile * pointer_type ; + typename std::enable_if::value, int>::type + global_reduce(ReducerType const& reducer, int* const global_scratch_flags, + void* const global_scratch_space, void* const shmem, + int const shmem_size) { +#ifdef __CUDA_ARCH__ - // Number of shared memory entries for the reduction: - const int nsh = shmem_size / sizeof(value_type); + typedef typename ReducerType::value_type value_type; + typedef value_type volatile* pointer_type; - // Number of CUDA threads in the block, rank within the block - const int nid = blockDim.x * blockDim.y * blockDim.z ; - const int tid = threadIdx.x + blockDim.x * ( - threadIdx.y + blockDim.y * threadIdx.z ); + // Number of shared memory entries for the reduction: + const int nsh = shmem_size / sizeof(value_type); - // Reduces within block using all available shared memory - // Contributes if it is the root "vector lane" + // Number of CUDA threads in the block, rank within the block + const int nid = blockDim.x * blockDim.y * blockDim.z; + const int tid = + threadIdx.x + blockDim.x * (threadIdx.y + blockDim.y * threadIdx.z); - // wn == number of warps in the block - // wx == which lane within the warp - // wy == which warp within the block + // Reduces within block using all available shared memory + // Contributes if it is the root "vector lane" - const int wn = ( nid + CudaTraits::WarpIndexMask ) >> CudaTraits::WarpIndexShift ; - const int wx = tid & CudaTraits::WarpIndexMask ; - const int wy = tid >> CudaTraits::WarpIndexShift ; + // wn == number of warps in the block + // wx == which lane within the warp + // wy == which warp within the block - //------------------------ - { // Intra warp shuffle reduction from contributing CUDA threads + const int wn = + (nid + CudaTraits::WarpIndexMask) >> CudaTraits::WarpIndexShift; + const int wx = tid & CudaTraits::WarpIndexMask; + const int wy = tid >> CudaTraits::WarpIndexShift; - value_type tmp( reducer.reference() ); + //------------------------ + { // Intra warp shuffle reduction from contributing CUDA threads - for ( int i = CudaTraits::WarpSize ; (int)blockDim.x <= ( i >>= 1 ) ; ) { + value_type tmp(reducer.reference()); - cuda_shfl_down( reducer.reference(), tmp, i, CudaTraits::WarpSize ); + for (int i = CudaTraits::WarpSize; (int)blockDim.x <= (i >>= 1);) { + Impl::in_place_shfl_down(reducer.reference(), tmp, i, + CudaTraits::WarpSize); - // Root of each vector lane reduces "thread" contribution - if ( 0 == threadIdx.x && wx < i ) { - reducer.join( & tmp , reducer.data() ); - } + // Root of each vector lane reduces "thread" contribution + if (0 == threadIdx.x && wx < i) { + reducer.join(&tmp, reducer.data()); } + } - // Reduce across warps using shared memory. - // Number of warps may not be power of two. + // Reduce across warps using shared memory. + // Number of warps may not be power of two. - __syncthreads(); // Wait before shared data write + __syncthreads(); // Wait before shared data write - // Number of shared memory entries for the reduction - // is at most one per warp - const int nentry = wn < nsh ? wn : nsh ; + // Number of shared memory entries for the reduction + // is at most one per warp + const int nentry = wn < nsh ? wn : nsh; - if ( 0 == wx && wy < nentry ) { - // Root thread of warp 'wy' has warp's value to contribute - ((value_type*) shmem)[wy] = tmp ; - } - - __syncthreads(); // Wait for write to be visible to block - - // When more warps than shared entries - // then warps must take turns joining their contribution - // to the designated shared memory entry. - for ( int i = nentry ; i < wn ; i += nentry ) { + if (0 == wx && wy < nentry) { + // Root thread of warp 'wy' has warp's value to contribute + ((value_type*)shmem)[wy] = tmp; + } - const int k = wy - i ; + __syncthreads(); // Wait for write to be visible to block - if ( 0 == wx && i <= wy && k < nentry ) { - // Root thread of warp 'wy' has warp's value to contribute - reducer.join( ((value_type*) shmem) + k , & tmp ); - } + // When more warps than shared entries + // then warps must take turns joining their contribution + // to the designated shared memory entry. + for (int i = nentry; i < wn; i += nentry) { + const int k = wy - i; - __syncthreads(); // Wait for write to be visible to block + if (0 == wx && i <= wy && k < nentry) { + // Root thread of warp 'wy' has warp's value to contribute + reducer.join(((value_type*)shmem) + k, &tmp); } - // One warp performs the inter-warp reduction: + __syncthreads(); // Wait for write to be visible to block + } - if ( 0 == wy ) { + // One warp performs the inter-warp reduction: - // Start fan-in at power of two covering nentry + if (0 == wy) { + // Start fan-in at power of two covering nentry - for ( int i = ( 1 << ( 32 - __clz(nentry-1) ) ) ; ( i >>= 1 ) ; ) { - const int k = wx + i ; - if ( wx < i && k < nentry ) { - reducer.join( ((pointer_type)shmem) + wx - , ((pointer_type)shmem) + k ); - __threadfence_block(); // Wait for write to be visible to warp - } + for (int i = (1 << (32 - __clz(nentry - 1))); (i >>= 1);) { + const int k = wx + i; + if (wx < i && k < nentry) { + reducer.join(((pointer_type)shmem) + wx, ((pointer_type)shmem) + k); + __threadfence_block(); // Wait for write to be visible to warp } } } - //------------------------ - { // Write block's value to global_scratch_memory - - int last_block = 0 ; - - if ( 0 == wx ) { - reducer.copy( ((pointer_type)global_scratch_space) - + blockIdx.x * reducer.length() - , reducer.data() ); + } + //------------------------ + { // Write block's value to global_scratch_memory - __threadfence(); // Wait until global write is visible. + int last_block = 0; - last_block = (int)gridDim.x == - 1 + Kokkos::atomic_fetch_add(global_scratch_flags,1); + if (0 == wx) { + reducer.copy(((pointer_type)global_scratch_space) + + blockIdx.x * reducer.length(), + reducer.data()); - // If last block then reset count - if ( last_block ) *global_scratch_flags = 0 ; - } + __threadfence(); // Wait until global write is visible. - last_block = __syncthreads_or( last_block ); - - if ( ! last_block ) return 0 ; + last_block = (int)gridDim.x == + 1 + Kokkos::atomic_fetch_add(global_scratch_flags, 1); + // If last block then reset count + if (last_block) *global_scratch_flags = 0; } - //------------------------ - // Last block reads global_scratch_memory into shared memory. - const int nentry = nid < gridDim.x ? - ( nid < nsh ? nid : nsh ) : - ( gridDim.x < nsh ? gridDim.x : nsh ) ; + last_block = __syncthreads_or(last_block); - // nentry = min( nid , nsh , gridDim.x ) + if (!last_block) return 0; + } + //------------------------ + // Last block reads global_scratch_memory into shared memory. - // whole block reads global memory into shared memory: + const int nentry = nid < gridDim.x ? (nid < nsh ? nid : nsh) + : (gridDim.x < nsh ? gridDim.x : nsh); - if ( tid < nentry ) { + // nentry = min( nid , nsh , gridDim.x ) - const int offset = tid * reducer.length(); + // whole block reads global memory into shared memory: - reducer.copy( ((pointer_type)shmem) + offset - , ((pointer_type)global_scratch_space) + offset ); + if (tid < nentry) { + const int offset = tid * reducer.length(); - for ( int i = nentry + tid ; i < (int)gridDim.x ; i += nentry ) { - reducer.join( ((pointer_type)shmem) + offset - , ((pointer_type)global_scratch_space) - + i * reducer.length() ); - } - } + reducer.copy(((pointer_type)shmem) + offset, + ((pointer_type)global_scratch_space) + offset); - __syncthreads(); // Wait for writes to be visible to block + for (int i = nentry + tid; i < (int)gridDim.x; i += nentry) { + reducer.join( + ((pointer_type)shmem) + offset, + ((pointer_type)global_scratch_space) + i * reducer.length()); + } + } - if ( 0 == wy ) { + __syncthreads(); // Wait for writes to be visible to block - // Iterate to reduce shared memory to single warp fan-in size + if (0 == wy) { + // Iterate to reduce shared memory to single warp fan-in size - const int nreduce = CudaTraits::WarpSize < nentry - ? CudaTraits::WarpSize : nentry ; + const int nreduce = + CudaTraits::WarpSize < nentry ? CudaTraits::WarpSize : nentry; - // nreduce = min( CudaTraits::WarpSize , nsh , gridDim.x ) + // nreduce = min( CudaTraits::WarpSize , nsh , gridDim.x ) - if ( wx < nreduce && nreduce < nentry ) { - for ( int i = nreduce + wx ; i < nentry ; i += nreduce ) { - reducer.join( ((pointer_type)shmem) + wx - , ((pointer_type)shmem) + i ); - } - __threadfence_block(); // Wait for writes to be visible to warp + if (wx < nreduce && nreduce < nentry) { + for (int i = nreduce + wx; i < nentry; i += nreduce) { + reducer.join(((pointer_type)shmem) + wx, ((pointer_type)shmem) + i); } + __threadfence_block(); // Wait for writes to be visible to warp + } - // Start fan-in at power of two covering nentry - - for ( int i = ( 1 << ( 32 - __clz(nreduce-1) ) ) ; ( i >>= 1 ) ; ) { - const int k = wx + i ; - if ( wx < i && k < nreduce ) { - reducer.join( ((pointer_type)shmem) + wx - , ((pointer_type)shmem) + k ); - __threadfence_block(); // Wait for writes to be visible to warp - } - } + // Start fan-in at power of two covering nentry - if ( 0 == wx ) { - reducer.copy( reducer.data() , (pointer_type)shmem ); - return 1 ; + for (int i = (1 << (32 - __clz(nreduce - 1))); (i >>= 1);) { + const int k = wx + i; + if (wx < i && k < nreduce) { + reducer.join(((pointer_type)shmem) + wx, ((pointer_type)shmem) + k); + __threadfence_block(); // Wait for writes to be visible to warp } } - return 0 ; - #else - return 0 ; - #endif + if (0 == wx) { + reducer.copy(reducer.data(), (pointer_type)shmem); + return 1; + } } + return 0; + +#else + return 0; +#endif + } //---------------------------------------- // Private for the driver KOKKOS_INLINE_FUNCTION - CudaTeamMember( void * shared - , const int shared_begin - , const int shared_size - , void* scratch_level_1_ptr - , const int scratch_level_1_size - , const int arg_league_rank - , const int arg_league_size ) - : m_team_reduce( shared ) - , m_team_shared( ((char *)shared) + shared_begin , shared_size, scratch_level_1_ptr, scratch_level_1_size) - , m_team_reduce_size( shared_begin ) - , m_league_rank( arg_league_rank ) - , m_league_size( arg_league_size ) - {} - -public: + CudaTeamMember(void* shared, const int shared_begin, const int shared_size, + void* scratch_level_1_ptr, const int scratch_level_1_size, + const int arg_league_rank, const int arg_league_size) + : m_team_reduce(shared), + m_team_shared(((char*)shared) + shared_begin, shared_size, + scratch_level_1_ptr, scratch_level_1_size), + m_team_reduce_size(shared_begin), + m_league_rank(arg_league_rank), + m_league_size(arg_league_size) {} + + public: // Declare to avoid unused private member warnings which are trigger // when SFINAE excludes the member function which uses these variables // Making another class a friend also surpresses these warnings - bool impl_avoid_sfinae_warning() const noexcept - { + bool impl_avoid_sfinae_warning() const noexcept { return m_team_reduce_size > 0 && m_team_reduce != nullptr; } }; -} // namspace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -556,124 +545,128 @@ public: namespace Kokkos { namespace Impl { -template -struct TeamThreadRangeBoundariesStruct { +template +struct TeamThreadRangeBoundariesStruct { typedef iType index_type; const CudaTeamMember& member; const iType start; const iType end; KOKKOS_INLINE_FUNCTION - TeamThreadRangeBoundariesStruct (const CudaTeamMember& thread_, iType count) - : member(thread_) - , start( 0 ) - , end( count ) {} + TeamThreadRangeBoundariesStruct(const CudaTeamMember& thread_, iType count) + : member(thread_), start(0), end(count) {} KOKKOS_INLINE_FUNCTION - TeamThreadRangeBoundariesStruct (const CudaTeamMember& thread_, iType begin_, iType end_) - : member(thread_) - , start( begin_ ) - , end( end_ ) {} + TeamThreadRangeBoundariesStruct(const CudaTeamMember& thread_, iType begin_, + iType end_) + : member(thread_), start(begin_), end(end_) {} }; -template -struct TeamVectorRangeBoundariesStruct { +template +struct TeamVectorRangeBoundariesStruct { typedef iType index_type; const CudaTeamMember& member; const iType start; const iType end; KOKKOS_INLINE_FUNCTION - TeamVectorRangeBoundariesStruct (const CudaTeamMember& thread_, const iType& count) - : member(thread_) - , start( 0 ) - , end( count ) {} + TeamVectorRangeBoundariesStruct(const CudaTeamMember& thread_, + const iType& count) + : member(thread_), start(0), end(count) {} KOKKOS_INLINE_FUNCTION - TeamVectorRangeBoundariesStruct (const CudaTeamMember& thread_, const iType& begin_, const iType& end_) - : member(thread_) - , start( begin_ ) - , end( end_ ) {} + TeamVectorRangeBoundariesStruct(const CudaTeamMember& thread_, + const iType& begin_, const iType& end_) + : member(thread_), start(begin_), end(end_) {} }; -template -struct ThreadVectorRangeBoundariesStruct { +template +struct ThreadVectorRangeBoundariesStruct { typedef iType index_type; const index_type start; const index_type end; KOKKOS_INLINE_FUNCTION - ThreadVectorRangeBoundariesStruct (const CudaTeamMember, index_type count) - : start( static_cast(0) ), end( count ) {} + ThreadVectorRangeBoundariesStruct(const CudaTeamMember, index_type count) + : start(static_cast(0)), end(count) {} KOKKOS_INLINE_FUNCTION - ThreadVectorRangeBoundariesStruct (index_type count) - : start( static_cast(0) ), end( count ) {} + ThreadVectorRangeBoundariesStruct(index_type count) + : start(static_cast(0)), end(count) {} KOKKOS_INLINE_FUNCTION - ThreadVectorRangeBoundariesStruct (const CudaTeamMember, index_type arg_begin, index_type arg_end) - : start( arg_begin ), end( arg_end ) {} + ThreadVectorRangeBoundariesStruct(const CudaTeamMember, index_type arg_begin, + index_type arg_end) + : start(arg_begin), end(arg_end) {} KOKKOS_INLINE_FUNCTION - ThreadVectorRangeBoundariesStruct (index_type arg_begin, index_type arg_end) - : start( arg_begin ), end( arg_end ) {} + ThreadVectorRangeBoundariesStruct(index_type arg_begin, index_type arg_end) + : start(arg_begin), end(arg_end) {} }; -} // namespace Impl +} // namespace Impl -template +template KOKKOS_INLINE_FUNCTION -Impl::TeamThreadRangeBoundariesStruct< iType, Impl::CudaTeamMember > -TeamThreadRange( const Impl::CudaTeamMember & thread, iType count ) { - return Impl::TeamThreadRangeBoundariesStruct< iType, Impl::CudaTeamMember >( thread, count ); + Impl::TeamThreadRangeBoundariesStruct + TeamThreadRange(const Impl::CudaTeamMember& thread, iType count) { + return Impl::TeamThreadRangeBoundariesStruct( + thread, count); } -template< typename iType1, typename iType2 > -KOKKOS_INLINE_FUNCTION -Impl::TeamThreadRangeBoundariesStruct< typename std::common_type< iType1, iType2 >::type, - Impl::CudaTeamMember > -TeamThreadRange( const Impl::CudaTeamMember & thread, iType1 begin, iType2 end ) { - typedef typename std::common_type< iType1, iType2 >::type iType; - return Impl::TeamThreadRangeBoundariesStruct< iType, Impl::CudaTeamMember >( thread, iType(begin), iType(end) ); +template +KOKKOS_INLINE_FUNCTION Impl::TeamThreadRangeBoundariesStruct< + typename std::common_type::type, Impl::CudaTeamMember> +TeamThreadRange(const Impl::CudaTeamMember& thread, iType1 begin, iType2 end) { + typedef typename std::common_type::type iType; + return Impl::TeamThreadRangeBoundariesStruct( + thread, iType(begin), iType(end)); } -template +template KOKKOS_INLINE_FUNCTION -Impl::TeamVectorRangeBoundariesStruct< iType, Impl::CudaTeamMember > -TeamVectorRange( const Impl::CudaTeamMember & thread, const iType & count ) { - return Impl::TeamVectorRangeBoundariesStruct< iType, Impl::CudaTeamMember >( thread, count ); + Impl::TeamVectorRangeBoundariesStruct + TeamVectorRange(const Impl::CudaTeamMember& thread, const iType& count) { + return Impl::TeamVectorRangeBoundariesStruct( + thread, count); } -template< typename iType1, typename iType2 > -KOKKOS_INLINE_FUNCTION -Impl::TeamVectorRangeBoundariesStruct< typename std::common_type< iType1, iType2 >::type, - Impl::CudaTeamMember > -TeamVectorRange( const Impl::CudaTeamMember & thread, const iType1 & begin, const iType2 & end ) { - typedef typename std::common_type< iType1, iType2 >::type iType; - return Impl::TeamVectorRangeBoundariesStruct< iType, Impl::CudaTeamMember >( thread, iType(begin), iType(end) ); +template +KOKKOS_INLINE_FUNCTION Impl::TeamVectorRangeBoundariesStruct< + typename std::common_type::type, Impl::CudaTeamMember> +TeamVectorRange(const Impl::CudaTeamMember& thread, const iType1& begin, + const iType2& end) { + typedef typename std::common_type::type iType; + return Impl::TeamVectorRangeBoundariesStruct( + thread, iType(begin), iType(end)); } -template +template KOKKOS_INLINE_FUNCTION -Impl::ThreadVectorRangeBoundariesStruct -ThreadVectorRange(const Impl::CudaTeamMember& thread, iType count) { - return Impl::ThreadVectorRangeBoundariesStruct(thread,count); + Impl::ThreadVectorRangeBoundariesStruct + ThreadVectorRange(const Impl::CudaTeamMember& thread, iType count) { + return Impl::ThreadVectorRangeBoundariesStruct( + thread, count); } -template +template KOKKOS_INLINE_FUNCTION -Impl::ThreadVectorRangeBoundariesStruct -ThreadVectorRange(const Impl::CudaTeamMember& thread, iType arg_begin, iType arg_end) { - return Impl::ThreadVectorRangeBoundariesStruct(thread,arg_begin,arg_end); + Impl::ThreadVectorRangeBoundariesStruct + ThreadVectorRange(const Impl::CudaTeamMember& thread, iType arg_begin, + iType arg_end) { + return Impl::ThreadVectorRangeBoundariesStruct( + thread, arg_begin, arg_end); } KOKKOS_INLINE_FUNCTION -Impl::ThreadSingleStruct PerTeam(const Impl::CudaTeamMember& thread) { +Impl::ThreadSingleStruct PerTeam( + const Impl::CudaTeamMember& thread) { return Impl::ThreadSingleStruct(thread); } KOKKOS_INLINE_FUNCTION -Impl::VectorSingleStruct PerThread(const Impl::CudaTeamMember& thread) { +Impl::VectorSingleStruct PerThread( + const Impl::CudaTeamMember& thread) { return Impl::VectorSingleStruct(thread); } @@ -685,20 +678,16 @@ Impl::VectorSingleStruct PerThread(const Impl::CudaTeamMem * * The range [0..N) is mapped to all threads of the the calling thread team. */ -template -KOKKOS_INLINE_FUNCTION -void parallel_for - ( const Impl::TeamThreadRangeBoundariesStruct& - loop_boundaries - , const Closure & closure - ) -{ - #ifdef __CUDA_ARCH__ - for( iType i = loop_boundaries.start + threadIdx.y - ; i < loop_boundaries.end - ; i += blockDim.y ) +template +KOKKOS_INLINE_FUNCTION void parallel_for( + const Impl::TeamThreadRangeBoundariesStruct& + loop_boundaries, + const Closure& closure) { +#ifdef __CUDA_ARCH__ + for (iType i = loop_boundaries.start + threadIdx.y; i < loop_boundaries.end; + i += blockDim.y) closure(i); - #endif +#endif } //---------------------------------------------------------------------------- @@ -711,32 +700,26 @@ void parallel_for * calling thread team and a summation of val is * performed and put into result. */ -template< typename iType, class Closure, class ReducerType > +template KOKKOS_INLINE_FUNCTION -typename std::enable_if< Kokkos::is_reducer< ReducerType >::value >::type -parallel_reduce - ( const Impl::TeamThreadRangeBoundariesStruct & - loop_boundaries - , const Closure & closure - , const ReducerType & reducer - ) -{ + typename std::enable_if::value>::type + parallel_reduce(const Impl::TeamThreadRangeBoundariesStruct< + iType, Impl::CudaTeamMember>& loop_boundaries, + const Closure& closure, const ReducerType& reducer) { #ifdef __CUDA_ARCH__ typename ReducerType::value_type value; - reducer.init( value ); + reducer.init(value); - for( iType i = loop_boundaries.start + threadIdx.y - ; i < loop_boundaries.end - ; i += blockDim.y ) { - closure(i,value); + for (iType i = loop_boundaries.start + threadIdx.y; i < loop_boundaries.end; + i += blockDim.y) { + closure(i, value); } - loop_boundaries.member.team_reduce( reducer, value ); + loop_boundaries.member.team_reduce(reducer, value); #endif } - /** \brief Inter-thread parallel_reduce assuming summation. * * Executes closure(iType i, ValueType & val) for each i=[0..N) @@ -745,98 +728,79 @@ parallel_reduce * calling thread team and a summation of val is * performed and put into result. */ -template< typename iType, class Closure, typename ValueType > +template KOKKOS_INLINE_FUNCTION -typename std::enable_if< ! Kokkos::is_reducer< ValueType >::value >::type -parallel_reduce - ( const Impl::TeamThreadRangeBoundariesStruct & - loop_boundaries - , const Closure & closure - , ValueType & result - ) -{ + typename std::enable_if::value>::type + parallel_reduce(const Impl::TeamThreadRangeBoundariesStruct< + iType, Impl::CudaTeamMember>& loop_boundaries, + const Closure& closure, ValueType& result) { #ifdef __CUDA_ARCH__ ValueType val; Kokkos::Sum reducer(val); - reducer.init( reducer.reference() ); + reducer.init(reducer.reference()); - for( iType i = loop_boundaries.start + threadIdx.y - ; i < loop_boundaries.end - ; i += blockDim.y ) { - closure(i,val); + for (iType i = loop_boundaries.start + threadIdx.y; i < loop_boundaries.end; + i += blockDim.y) { + closure(i, val); } - loop_boundaries.member.team_reduce( reducer , val); + loop_boundaries.member.team_reduce(reducer, val); result = reducer.reference(); #endif } -template -KOKKOS_INLINE_FUNCTION -void parallel_for - ( const Impl::TeamVectorRangeBoundariesStruct& - loop_boundaries - , const Closure & closure - ) -{ - #ifdef __CUDA_ARCH__ - for( iType i = loop_boundaries.start + threadIdx.y * blockDim.x + threadIdx.x - ; i < loop_boundaries.end - ; i += blockDim.y*blockDim.x ) +template +KOKKOS_INLINE_FUNCTION void parallel_for( + const Impl::TeamVectorRangeBoundariesStruct& + loop_boundaries, + const Closure& closure) { +#ifdef __CUDA_ARCH__ + for (iType i = loop_boundaries.start + threadIdx.y * blockDim.x + threadIdx.x; + i < loop_boundaries.end; i += blockDim.y * blockDim.x) closure(i); - #endif +#endif } -template< typename iType, class Closure, class ReducerType > +template KOKKOS_INLINE_FUNCTION -typename std::enable_if< Kokkos::is_reducer< ReducerType >::value >::type -parallel_reduce - ( const Impl::TeamVectorRangeBoundariesStruct & - loop_boundaries - , const Closure & closure - , const ReducerType & reducer - ) -{ + typename std::enable_if::value>::type + parallel_reduce(const Impl::TeamVectorRangeBoundariesStruct< + iType, Impl::CudaTeamMember>& loop_boundaries, + const Closure& closure, const ReducerType& reducer) { #ifdef __CUDA_ARCH__ typename ReducerType::value_type value; - reducer.init( value ); + reducer.init(value); - for( iType i = loop_boundaries.start + threadIdx.y * blockDim.x + threadIdx.x - ; i < loop_boundaries.end - ; i += blockDim.y * blockDim.x ) { - closure(i,value); + for (iType i = loop_boundaries.start + threadIdx.y * blockDim.x + threadIdx.x; + i < loop_boundaries.end; i += blockDim.y * blockDim.x) { + closure(i, value); } - loop_boundaries.member.vector_reduce( reducer, value ); - loop_boundaries.member.team_reduce( reducer, value ); + loop_boundaries.member.vector_reduce(reducer, value); + loop_boundaries.member.team_reduce(reducer, value); #endif } -template< typename iType, class Closure, typename ValueType > +template KOKKOS_INLINE_FUNCTION -typename std::enable_if< ! Kokkos::is_reducer< ValueType >::value >::type -parallel_reduce - ( const Impl::TeamVectorRangeBoundariesStruct & - loop_boundaries - , const Closure & closure - , ValueType & result - ) -{ + typename std::enable_if::value>::type + parallel_reduce(const Impl::TeamVectorRangeBoundariesStruct< + iType, Impl::CudaTeamMember>& loop_boundaries, + const Closure& closure, ValueType& result) { #ifdef __CUDA_ARCH__ ValueType val; Kokkos::Sum reducer(val); - reducer.init( reducer.reference() ); + reducer.init(reducer.reference()); - for( iType i = loop_boundaries.start + threadIdx.y * blockDim.x + threadIdx.x - ; i < loop_boundaries.end - ; i += blockDim.y * blockDim.x ) { - closure(i,val); + for (iType i = loop_boundaries.start + threadIdx.y * blockDim.x + threadIdx.x; + i < loop_boundaries.end; i += blockDim.y * blockDim.x) { + closure(i, val); } - loop_boundaries.member.vector_reduce( reducer ); - loop_boundaries.member.team_reduce( reducer ); + loop_boundaries.member.vector_reduce(reducer); + loop_boundaries.member.team_reduce(reducer); result = reducer.reference(); #endif } @@ -849,25 +813,24 @@ parallel_reduce * * The range [0..N) is mapped to all vector lanes of the the calling thread. */ -template -KOKKOS_INLINE_FUNCTION -void parallel_for - ( const Impl::ThreadVectorRangeBoundariesStruct& - loop_boundaries - , const Closure & closure - ) -{ +template +KOKKOS_INLINE_FUNCTION void parallel_for( + const Impl::ThreadVectorRangeBoundariesStruct& + loop_boundaries, + const Closure& closure) { #ifdef __CUDA_ARCH__ - for ( iType i = loop_boundaries.start + threadIdx.x - ; i < loop_boundaries.end - ; i += blockDim.x ) { + for (iType i = loop_boundaries.start + threadIdx.x; i < loop_boundaries.end; + i += blockDim.x) { closure(i); } - #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - KOKKOS_IMPL_CUDA_SYNCWARP_MASK(blockDim.x==32?0xffffffff:((1< +template KOKKOS_INLINE_FUNCTION -typename std::enable_if< is_reducer< ReducerType >::value >::type -parallel_reduce - ( Impl::ThreadVectorRangeBoundariesStruct - const & loop_boundaries - , Closure const & closure - , ReducerType const & reducer ) -{ + typename std::enable_if::value>::type + parallel_reduce(Impl::ThreadVectorRangeBoundariesStruct< + iType, Impl::CudaTeamMember> const& loop_boundaries, + Closure const& closure, ReducerType const& reducer) { #ifdef __CUDA_ARCH__ - reducer.init( reducer.reference() ); + reducer.init(reducer.reference()); - for ( iType i = loop_boundaries.start + threadIdx.x - ; i < loop_boundaries.end - ; i += blockDim.x ) { - closure(i,reducer.reference()); + for (iType i = loop_boundaries.start + threadIdx.x; i < loop_boundaries.end; + i += blockDim.x) { + closure(i, reducer.reference()); } - Impl::CudaTeamMember::vector_reduce( reducer ); + Impl::CudaTeamMember::vector_reduce(reducer); #endif } @@ -919,26 +878,21 @@ parallel_reduce * The identity value for the += operator is assumed to be the default * constructed value. */ -template< typename iType, class Closure, typename ValueType > +template KOKKOS_INLINE_FUNCTION -typename std::enable_if< ! is_reducer< ValueType >::value >::type -parallel_reduce - ( Impl::ThreadVectorRangeBoundariesStruct - const & loop_boundaries - , Closure const & closure - , ValueType & result ) -{ + typename std::enable_if::value>::type + parallel_reduce(Impl::ThreadVectorRangeBoundariesStruct< + iType, Impl::CudaTeamMember> const& loop_boundaries, + Closure const& closure, ValueType& result) { #ifdef __CUDA_ARCH__ result = ValueType(); - for ( iType i = loop_boundaries.start + threadIdx.x - ; i < loop_boundaries.end - ; i += blockDim.x ) { - closure(i,result); + for (iType i = loop_boundaries.start + threadIdx.x; i < loop_boundaries.end; + i += blockDim.x) { + closure(i, result); } - Impl::CudaTeamMember::vector_reduce( - Kokkos::Sum(result ) ); + Impl::CudaTeamMember::vector_reduce(Kokkos::Sum(result)); #endif } @@ -953,29 +907,22 @@ parallel_reduce * thread and a scan operation is performed. * The last call to closure has final == true. */ -template< typename iType, class Closure > -KOKKOS_INLINE_FUNCTION -void parallel_scan - ( const Impl::ThreadVectorRangeBoundariesStruct& - loop_boundaries - , const Closure & closure - ) -{ - +template +KOKKOS_INLINE_FUNCTION void parallel_scan( + const Impl::ThreadVectorRangeBoundariesStruct& + loop_boundaries, + const Closure& closure) { #ifdef __CUDA_ARCH__ // Extract value_type from closure - using value_type = - typename Kokkos::Impl::FunctorAnalysis - < Kokkos::Impl::FunctorPatternInterface::SCAN - , void - , Closure >::value_type ; + using value_type = typename Kokkos::Impl::FunctorAnalysis< + Kokkos::Impl::FunctorPatternInterface::SCAN, void, Closure>::value_type; // Loop through boundaries by vector-length chunks // must scan at each iteration - value_type accum = 0 ; + value_type accum = 0; // All thread "lanes" must loop the same number of times. // Determine an loop end for all thread "lanes." @@ -984,19 +931,21 @@ void parallel_scan // ( end % blockDim.x ) == ( end & ( blockDim.x - 1 ) ) // 1 <= blockDim.x <= CudaTraits::WarpSize - const int mask = blockDim.x - 1 ; - const unsigned active_mask = blockDim.x==32?0xffffffff:((1<= 4 // ... - for ( int j = 1 ; j < (int)blockDim.x ; j <<= 1 ) { - value_type tmp = 0 ; - Impl::cuda_shfl_up(tmp, sval , j , blockDim.x, active_mask ); - if ( j <= (int)threadIdx.x ) { sval += tmp ; } + for (int j = 1; j < (int)blockDim.x; j <<= 1) { + value_type tmp = 0; + Impl::in_place_shfl_up(tmp, sval, j, blockDim.x, active_mask); + if (j <= (int)threadIdx.x) { + sval += tmp; + } } // Include accumulation and remove value for exclusive scan: - val = accum + sval - val ; + val = accum + sval - val; // Provide exclusive scan value: - if ( i < loop_boundaries.end ) closure( i , val , true ); + if (i < loop_boundaries.end) closure(i, val, true); // Accumulate the last value in the inclusive scan: - Impl::cuda_shfl( sval , sval , mask , blockDim.x, active_mask ); + Impl::in_place_shfl(sval, sval, mask, blockDim.x, active_mask); - accum += sval ; + accum += sval; } #endif } -} +} // namespace Kokkos namespace Kokkos { -template -KOKKOS_INLINE_FUNCTION -void single(const Impl::VectorSingleStruct& , const FunctorType& lambda) { +template +KOKKOS_INLINE_FUNCTION void single( + const Impl::VectorSingleStruct&, + const FunctorType& lambda) { #ifdef __CUDA_ARCH__ - if(threadIdx.x == 0) lambda(); - #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - KOKKOS_IMPL_CUDA_SYNCWARP_MASK(blockDim.x==32?0xffffffff:((1< -KOKKOS_INLINE_FUNCTION -void single(const Impl::ThreadSingleStruct& , const FunctorType& lambda) { +template +KOKKOS_INLINE_FUNCTION void single( + const Impl::ThreadSingleStruct&, + const FunctorType& lambda) { #ifdef __CUDA_ARCH__ - if(threadIdx.x == 0 && threadIdx.y == 0) lambda(); - #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - KOKKOS_IMPL_CUDA_SYNCWARP_MASK(blockDim.x==32?0xffffffff:((1< -KOKKOS_INLINE_FUNCTION -void single(const Impl::VectorSingleStruct& , const FunctorType& lambda, ValueType& val) { +template +KOKKOS_INLINE_FUNCTION void single( + const Impl::VectorSingleStruct&, + const FunctorType& lambda, ValueType& val) { #ifdef __CUDA_ARCH__ - if(threadIdx.x == 0) lambda(val); - unsigned mask = blockDim.x==32?0xffffffff:((1< -KOKKOS_INLINE_FUNCTION -void single(const Impl::ThreadSingleStruct& single_struct, const FunctorType& lambda, ValueType& val) { +template +KOKKOS_INLINE_FUNCTION void single( + const Impl::ThreadSingleStruct& single_struct, + const FunctorType& lambda, ValueType& val) { #ifdef __CUDA_ARCH__ - if(threadIdx.x == 0 && threadIdx.y == 0) { + if (threadIdx.x == 0 && threadIdx.y == 0) { lambda(val); } - single_struct.team_member.team_broadcast(val,0); + single_struct.team_member.team_broadcast(val, 0); #endif } -} // namespace Kokkos +} // namespace Kokkos #endif /* defined( __CUDACC__ ) */ #endif /* #ifndef KOKKOS_CUDA_TEAM_HPP */ - diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_UniqueToken.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_UniqueToken.hpp index c4140750da..a0de4eaa7f 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_UniqueToken.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_UniqueToken.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -52,92 +53,79 @@ #include #include -namespace Kokkos { namespace Experimental { +namespace Kokkos { +namespace Experimental { // both global and instance Unique Tokens are implemented in the same way -template<> -class UniqueToken< Cuda, UniqueTokenScope::Global > -{ -private: - - uint32_t volatile * m_buffer ; - uint32_t m_count ; - -public: +template <> +class UniqueToken { + private: + uint32_t volatile* m_buffer; + uint32_t m_count; + public: using execution_space = Cuda; - using size_type = int32_t; + using size_type = int32_t; -#if defined( KOKKOS_ENABLE_DEPRECATED_CODE ) - explicit - UniqueToken( execution_space const& ); +#if defined(KOKKOS_ENABLE_DEPRECATED_CODE) + explicit UniqueToken(execution_space const&); KOKKOS_INLINE_FUNCTION UniqueToken() : m_buffer(0), m_count(0) {} #else - explicit - UniqueToken( execution_space const& = execution_space() ); + explicit UniqueToken(execution_space const& = execution_space()); #endif #ifdef KOKKOS_CUDA_9_DEFAULTED_BUG_WORKAROUND KOKKOS_INLINE_FUNCTION - UniqueToken( const UniqueToken & rhs ) - : m_buffer(rhs.m_buffer) - , m_count(rhs.m_count) - { - } + UniqueToken(const UniqueToken& rhs) + : m_buffer(rhs.m_buffer), m_count(rhs.m_count) {} KOKKOS_INLINE_FUNCTION - UniqueToken( UniqueToken && rhs ) - : m_buffer(std::move(rhs.m_buffer)) - , m_count(std::move(rhs.m_count)) - { - } + UniqueToken(UniqueToken&& rhs) + : m_buffer(std::move(rhs.m_buffer)), m_count(std::move(rhs.m_count)) {} KOKKOS_INLINE_FUNCTION - UniqueToken & operator=( const UniqueToken & rhs ) { + UniqueToken& operator=(const UniqueToken& rhs) { m_buffer = rhs.m_buffer; - m_count = rhs.m_count; + m_count = rhs.m_count; return *this; } KOKKOS_INLINE_FUNCTION - UniqueToken & operator=( UniqueToken && rhs ) { + UniqueToken& operator=(UniqueToken&& rhs) { m_buffer = std::move(rhs.m_buffer); - m_count = std::move(rhs.m_count); + m_count = std::move(rhs.m_count); return *this; } #else KOKKOS_INLINE_FUNCTION - UniqueToken( const UniqueToken & ) = default; + UniqueToken(const UniqueToken&) = default; KOKKOS_INLINE_FUNCTION - UniqueToken( UniqueToken && ) = default; + UniqueToken(UniqueToken&&) = default; KOKKOS_INLINE_FUNCTION - UniqueToken & operator=( const UniqueToken & ) = default ; + UniqueToken& operator=(const UniqueToken&) = default; KOKKOS_INLINE_FUNCTION - UniqueToken & operator=( UniqueToken && ) = default ; + UniqueToken& operator=(UniqueToken&&) = default; #endif /// \brief upper bound for acquired values, i.e. 0 <= value < size() KOKKOS_INLINE_FUNCTION - size_type size() const noexcept { return m_count ; } + size_type size() const noexcept { return m_count; } /// \brief acquire value such that 0 <= value < size() KOKKOS_INLINE_FUNCTION - size_type acquire() const - { - const Kokkos::pair result = - Kokkos::Impl::concurrent_bitset:: - acquire_bounded( m_buffer - , m_count - , Kokkos::Impl::clock_tic() % m_count - ); - - if ( result.first < 0 ) { - Kokkos::abort("UniqueToken failure to release tokens, no tokens available" ); + size_type acquire() const { + const Kokkos::pair result = + Kokkos::Impl::concurrent_bitset::acquire_bounded( + m_buffer, m_count, Kokkos::Impl::clock_tic() % m_count); + + if (result.first < 0) { + Kokkos::abort( + "UniqueToken failure to release tokens, no tokens available"); } return result.first; @@ -145,31 +133,26 @@ public: /// \brief release an acquired value KOKKOS_INLINE_FUNCTION - void release( size_type i ) const noexcept - { - Kokkos::Impl::concurrent_bitset::release( m_buffer, i ); + void release(size_type i) const noexcept { + Kokkos::Impl::concurrent_bitset::release(m_buffer, i); } }; -template<> -class UniqueToken< Cuda, UniqueTokenScope::Instance > - : public UniqueToken< Cuda, UniqueTokenScope::Global > -{ -public: - +template <> +class UniqueToken + : public UniqueToken { + public: #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - explicit - UniqueToken( execution_space const& arg ) - : UniqueToken< Cuda, UniqueTokenScope::Global >( arg ) {} + explicit UniqueToken(execution_space const& arg) + : UniqueToken(arg) {} #else - explicit - UniqueToken( execution_space const& arg = execution_space() ) - : UniqueToken< Cuda, UniqueTokenScope::Global >( arg ) {} + explicit UniqueToken(execution_space const& arg = execution_space()) + : UniqueToken(arg) {} #endif }; -}} // namespace Kokkos::Experimental - -#endif // KOKKOS_ENABLE_CUDA -#endif // KOKKOS_CUDA_UNIQUE_TOKEN_HPP +} // namespace Experimental +} // namespace Kokkos +#endif // KOKKOS_ENABLE_CUDA +#endif // KOKKOS_CUDA_UNIQUE_TOKEN_HPP diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Vectorization.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Vectorization.hpp index fc369191bd..085262b804 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Vectorization.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Vectorization.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,342 +49,163 @@ #include #include -namespace Kokkos { +namespace Kokkos { -// Shuffle only makes sense on >= Kepler GPUs; it doesn't work on CPUs -// or other GPUs. We provide a generic definition (which is trivial -// and doesn't do what it claims to do) because we don't actually use -// this function unless we are on a suitable GPU, with a suitable -// Scalar type. (For example, in the mat-vec, the "ThreadsPerRow" -// internal parameter depends both on the ExecutionSpace and the Scalar type, -// and it controls whether shfl_down() gets called.) namespace Impl { - template< typename Scalar > - struct shfl_union { - enum {n = sizeof(Scalar)/4}; - float fval[n]; - KOKKOS_INLINE_FUNCTION - Scalar value() { - return *(Scalar*) fval; - } - KOKKOS_INLINE_FUNCTION - void operator= (Scalar& value_) { - float* const val_ptr = (float*) &value_; - for(int i=0; i +struct in_place_shfl_op { + // CRTP boilerplate + __device__ KOKKOS_IMPL_FORCEINLINE const Derived& self() const noexcept { + return *static_cast(this); + } + + // sizeof(Scalar) == sizeof(int) case + template + // requires _assignable_from_bits + __device__ inline typename std::enable_if::type + operator()(Scalar& out, Scalar const& in, int lane_or_delta, int width, + unsigned mask = shfl_all_mask) const noexcept { + //------------------------------------------------ + reinterpret_cast(out) = self().do_shfl_op( + mask, reinterpret_cast(in), lane_or_delta, width); + //------------------------------------------------ + } + +// TODO: figure out why 64-bit shfl fails in Clang +#if (CUDA_VERSION >= 9000) && (!defined(KOKKOS_COMPILER_CLANG)) + // sizeof(Scalar) == sizeof(double) case + // requires _assignable_from_bits + template + __device__ inline + typename std::enable_if::type + operator()(Scalar& out, Scalar const& in, int lane_or_delta, int width, + unsigned mask = shfl_all_mask) const noexcept { + //------------------------------------------------ + reinterpret_cast(out) = self().do_shfl_op( + mask, *reinterpret_cast(&in), lane_or_delta, width); + //------------------------------------------------ + } +#else + // sizeof(Scalar) == sizeof(double) case + // requires _assignable_from_bits + template + __device__ inline + typename std::enable_if::type + operator()(Scalar& out, const Scalar& val, int lane_or_delta, int width, + unsigned mask = shfl_all_mask) const noexcept { + //------------------------------------------------ + int lo = __double2loint(*reinterpret_cast(&val)); + int hi = __double2hiint(*reinterpret_cast(&val)); + lo = self().do_shfl_op(mask, lo, lane_or_delta, width); + hi = self().do_shfl_op(mask, hi, lane_or_delta, width); + auto tmp = __hiloint2double(hi, lo); + out = reinterpret_cast(tmp); + //------------------------------------------------ + } +#endif + + // sizeof(Scalar) > sizeof(double) case + template + __device__ inline + typename std::enable_if<(sizeof(Scalar) > sizeof(double))>::type + operator()(Scalar& out, const Scalar& val, int lane_or_delta, int width, + unsigned mask = shfl_all_mask) const noexcept { + // TODO DSH shouldn't this be KOKKOS_IMPL_CUDA_MAX_SHFL_SIZEOF instead of + // sizeof(int)? (Need benchmarks to decide which is faster) + using shuffle_as_t = int; + enum : int { N = sizeof(Scalar) / sizeof(shuffle_as_t) }; + + for (int i = 0; i < N; ++i) { + reinterpret_cast(&out)[i] = self().do_shfl_op( + mask, reinterpret_cast(&val)[i], lane_or_delta, + width); + } + } +}; + +struct in_place_shfl_fn : in_place_shfl_op { + template + __device__ KOKKOS_IMPL_FORCEINLINE T do_shfl_op(unsigned mask, T& val, + int lane, int width) const + noexcept { + return KOKKOS_IMPL_CUDA_SHFL_MASK(mask, val, lane, width); + } +}; +template +__device__ KOKKOS_IMPL_FORCEINLINE void in_place_shfl(Args&&... args) noexcept { + in_place_shfl_fn{}((Args &&) args...); } -#ifdef __CUDA_ARCH__ -#if (__CUDA_ARCH__ >= 300) - - KOKKOS_INLINE_FUNCTION - int shfl(const int &val, const int& srcLane, const int& width ) { - return KOKKOS_IMPL_CUDA_SHFL(val,srcLane,width); - } - - KOKKOS_INLINE_FUNCTION - float shfl(const float &val, const int& srcLane, const int& width ) { - return KOKKOS_IMPL_CUDA_SHFL(val,srcLane,width); - } - -// TODO: figure out why 64-bit shfl fails with Clang -#if ( CUDA_VERSION >= 9000 ) && (!defined(KOKKOS_COMPILER_CLANG)) - - KOKKOS_INLINE_FUNCTION - long shfl(const long &val, const int& srcLane, const int& width ) { - return KOKKOS_IMPL_CUDA_SHFL(val,srcLane,width); - } - - KOKKOS_INLINE_FUNCTION - long long shfl(const long long &val, const int& srcLane, const int& width ) { - return KOKKOS_IMPL_CUDA_SHFL(val,srcLane,width); - } - - KOKKOS_INLINE_FUNCTION - double shfl(const double &val, const int& srcLane, const int& width ) { - return KOKKOS_IMPL_CUDA_SHFL(val,srcLane,width); - } - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl(const Scalar &val, const int& srcLane, const typename Impl::enable_if< (sizeof(Scalar) == 8) , int >::type& width - ) { - Scalar tmp1 = val; - double tmp = *reinterpret_cast(&tmp1); - tmp = KOKKOS_IMPL_CUDA_SHFL(tmp,srcLane,width); - return *reinterpret_cast(&tmp); - } - -#else // ( CUDA_VERSION < 9000 ) - - KOKKOS_INLINE_FUNCTION - double shfl(const double &val, const int& srcLane, const int& width) { - int lo = __double2loint(val); - int hi = __double2hiint(val); - lo = KOKKOS_IMPL_CUDA_SHFL(lo,srcLane,width); - hi = KOKKOS_IMPL_CUDA_SHFL(hi,srcLane,width); - return __hiloint2double(hi,lo); - } - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl(const Scalar &val, const int& srcLane, const typename Impl::enable_if< (sizeof(Scalar) == 8) ,int>::type& width) { - int lo = __double2loint(*reinterpret_cast(&val)); - int hi = __double2hiint(*reinterpret_cast(&val)); - lo = KOKKOS_IMPL_CUDA_SHFL(lo,srcLane,width); - hi = KOKKOS_IMPL_CUDA_SHFL(hi,srcLane,width); - const double tmp = __hiloint2double(hi,lo); - return *(reinterpret_cast(&tmp)); - } - -#endif // ( CUDA_VERSION < 9000 ) - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl(const Scalar &val, const int& srcLane, const typename Impl::enable_if< (sizeof(Scalar) == 4) , int >::type& width - ) { - Scalar tmp1 = val; - float tmp = *reinterpret_cast(&tmp1); - tmp = KOKKOS_IMPL_CUDA_SHFL(tmp,srcLane,width); - return *reinterpret_cast(&tmp); - } - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl(const Scalar &val, const int& srcLane, const typename Impl::enable_if< (sizeof(Scalar) > 8) ,int>::type& width) { - Impl::shfl_union s_val; - Impl::shfl_union r_val; - s_val = val; - - for(int i = 0; i= 9000 ) && (!defined(KOKKOS_COMPILER_CLANG)) - - KOKKOS_INLINE_FUNCTION - long shfl_down(const long &val, const int& delta, const int& width) { - return KOKKOS_IMPL_CUDA_SHFL_DOWN(val,delta,width); - } - - KOKKOS_INLINE_FUNCTION - long long shfl_down(const long long &val, const int& delta, const int& width) { - return KOKKOS_IMPL_CUDA_SHFL_DOWN(val,delta,width); - } - - KOKKOS_INLINE_FUNCTION - double shfl_down(const double &val, const int& delta, const int& width) { - return KOKKOS_IMPL_CUDA_SHFL_DOWN(val,delta,width); - } - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl_down(const Scalar &val, const int& delta, const typename Impl::enable_if< (sizeof(Scalar) == 8) , int >::type & width) { - Scalar tmp1 = val; - double tmp = *reinterpret_cast(&tmp1); - tmp = KOKKOS_IMPL_CUDA_SHFL_DOWN(tmp,delta,width); - return *reinterpret_cast(&tmp); - } - -#else // ( CUDA_VERSION < 9000 ) - - KOKKOS_INLINE_FUNCTION - double shfl_down(const double &val, const int& delta, const int& width) { - int lo = __double2loint(val); - int hi = __double2hiint(val); - lo = KOKKOS_IMPL_CUDA_SHFL_DOWN(lo,delta,width); - hi = KOKKOS_IMPL_CUDA_SHFL_DOWN(hi,delta,width); - return __hiloint2double(hi,lo); - } - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl_down(const Scalar &val, const int& delta, const typename Impl::enable_if< (sizeof(Scalar) == 8) , int >::type & width) { - int lo = __double2loint(*reinterpret_cast(&val)); - int hi = __double2hiint(*reinterpret_cast(&val)); - lo = KOKKOS_IMPL_CUDA_SHFL_DOWN(lo,delta,width); - hi = KOKKOS_IMPL_CUDA_SHFL_DOWN(hi,delta,width); - const double tmp = __hiloint2double(hi,lo); - return *(reinterpret_cast(&tmp)); - } - -#endif // ( CUDA_VERSION < 9000 ) - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl_down(const Scalar &val, const int& delta, const typename Impl::enable_if< (sizeof(Scalar) == 4) , int >::type & width) { - Scalar tmp1 = val; - float tmp = *reinterpret_cast(&tmp1); - tmp = KOKKOS_IMPL_CUDA_SHFL_DOWN(tmp,delta,width); - return *reinterpret_cast(&tmp); - } - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl_down(const Scalar &val, const int& delta, const typename Impl::enable_if< (sizeof(Scalar) > 8) , int >::type & width) { - Impl::shfl_union s_val; - Impl::shfl_union r_val; - s_val = val; - - for(int i = 0; i= 9000 ) && (!defined(KOKKOS_COMPILER_CLANG)) - - KOKKOS_INLINE_FUNCTION - long shfl_up(const long &val, const int& delta, const int& width ) { - return KOKKOS_IMPL_CUDA_SHFL_UP(val,delta,width); - } - - KOKKOS_INLINE_FUNCTION - long long shfl_up(const long long &val, const int& delta, const int& width ) { - return KOKKOS_IMPL_CUDA_SHFL_UP(val,delta,width); - } - - KOKKOS_INLINE_FUNCTION - double shfl_up(const double &val, const int& delta, const int& width ) { - return KOKKOS_IMPL_CUDA_SHFL_UP(val,delta,width); - } - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl_up(const Scalar &val, const int& delta, const typename Impl::enable_if< (sizeof(Scalar) == 8) , int >::type & width) { - Scalar tmp1 = val; - double tmp = *reinterpret_cast(&tmp1); - tmp = KOKKOS_IMPL_CUDA_SHFL_UP(tmp,delta,width); - return *reinterpret_cast(&tmp); - } - -#else // ( CUDA_VERSION < 9000 ) - - KOKKOS_INLINE_FUNCTION - double shfl_up(const double &val, const int& delta, const int& width ) { - int lo = __double2loint(val); - int hi = __double2hiint(val); - lo = KOKKOS_IMPL_CUDA_SHFL_UP(lo,delta,width); - hi = KOKKOS_IMPL_CUDA_SHFL_UP(hi,delta,width); - return __hiloint2double(hi,lo); - } - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl_up(const Scalar &val, const int& delta, const typename Impl::enable_if< (sizeof(Scalar) == 8) , int >::type & width) { - int lo = __double2loint(*reinterpret_cast(&val)); - int hi = __double2hiint(*reinterpret_cast(&val)); - lo = KOKKOS_IMPL_CUDA_SHFL_UP(lo,delta,width); - hi = KOKKOS_IMPL_CUDA_SHFL_UP(hi,delta,width); - const double tmp = __hiloint2double(hi,lo); - return *(reinterpret_cast(&tmp)); - } - -#endif // ( CUDA_VERSION < 9000 ) - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl_up(const Scalar &val, const int& delta, const typename Impl::enable_if< (sizeof(Scalar) == 4) , int >::type & width) { - Scalar tmp1 = val; - float tmp = *reinterpret_cast(&tmp1); - tmp = KOKKOS_IMPL_CUDA_SHFL_UP(tmp,delta,width); - return *reinterpret_cast(&tmp); - } - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl_up(const Scalar &val, const int& delta, const typename Impl::enable_if< (sizeof(Scalar) > 8) , int >::type & width) { - Impl::shfl_union s_val; - Impl::shfl_union r_val; - s_val = val; - - for(int i = 0; i - KOKKOS_INLINE_FUNCTION - Scalar shfl(const Scalar &val, const int& srcLane, const int& width) { - if(width > 1) Kokkos::abort("Error: calling shfl from a device with CC<3.0."); - return val; - } +struct in_place_shfl_up_fn : in_place_shfl_op { + template + __device__ KOKKOS_IMPL_FORCEINLINE T do_shfl_op(unsigned mask, T& val, + int lane, int width) const + noexcept { + return KOKKOS_IMPL_CUDA_SHFL_UP_MASK(mask, val, lane, width); + } +}; +template +__device__ KOKKOS_IMPL_FORCEINLINE void in_place_shfl_up( + Args&&... args) noexcept { + in_place_shfl_up_fn{}((Args &&) args...); +} - template - KOKKOS_INLINE_FUNCTION - Scalar shfl_down(const Scalar &val, const int& delta, const int& width) { - if(width > 1) Kokkos::abort("Error: calling shfl_down from a device with CC<3.0."); - return val; - } +struct in_place_shfl_down_fn : in_place_shfl_op { + template + __device__ KOKKOS_IMPL_FORCEINLINE T do_shfl_op(unsigned mask, T& val, + int lane, int width) const + noexcept { + return KOKKOS_IMPL_CUDA_SHFL_DOWN_MASK(mask, val, lane, width); + } +}; +template +__device__ KOKKOS_IMPL_FORCEINLINE void in_place_shfl_down( + Args&&... args) noexcept { + in_place_shfl_down_fn{}((Args &&) args...); +} - template - KOKKOS_INLINE_FUNCTION - Scalar shfl_up(const Scalar &val, const int& delta, const int& width) { - if(width > 1) Kokkos::abort("Error: calling shfl_down from a device with CC<3.0."); - return val; - } -#endif // (__CUDA_ARCH__ < 300) -#else // !defined( __CUDA_ARCH__ ) - template - inline - Scalar shfl(const Scalar &val, const int& srcLane, const int& width) { - if(width > 1) Kokkos::abort("Error: calling shfl outside __CUDA_ARCH__."); - return val; - } +} // namespace Impl - template - inline - Scalar shfl_down(const Scalar &val, const int& delta, const int& width) { - if(width > 1) Kokkos::abort("Error: calling shfl_down outside __CUDA_ARCH__."); - return val; - } +template +// requires default_constructible && _assignable_from_bits +__device__ inline T shfl(const T& val, const int& srcLane, const int& width, + unsigned mask = Impl::shfl_all_mask) { + T rv = {}; + Impl::in_place_shfl(rv, val, srcLane, width, mask); + return rv; +} - template - inline - Scalar shfl_up(const Scalar &val, const int& delta, const int& width) { - if(width > 1) Kokkos::abort("Error: calling shfl_down outside __CUDA_ARCH__."); - return val; - } -#endif // !defined( __CUDA_ARCH__ ) +template +// requires default_constructible && _assignable_from_bits +__device__ inline T shfl_down(const T& val, int delta, int width, + unsigned mask = Impl::shfl_all_mask) { + T rv = {}; + Impl::in_place_shfl_down(rv, val, delta, width, mask); + return rv; +} -} // end namespace Kokkos +template +// requires default_constructible && _assignable_from_bits +__device__ inline T shfl_up(const T& val, int delta, int width, + unsigned mask = Impl::shfl_all_mask) { + T rv = {}; + Impl::in_place_shfl_up(rv, val, delta, width, mask); + return rv; +} -#endif // defined( KOKKOS_ENABLE_CUDA ) -#endif // !defined( KOKKOS_CUDA_VECTORIZATION_HPP ) +} // end namespace Kokkos +#endif // defined( KOKKOS_ENABLE_CUDA ) +#endif // !defined( KOKKOS_CUDA_VECTORIZATION_HPP ) diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Version_9_8_Compatibility.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Version_9_8_Compatibility.hpp index 8aa8b8f459..66231e55f9 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Version_9_8_Compatibility.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Version_9_8_Compatibility.hpp @@ -1,86 +1,77 @@ -#include +#include -#if defined( __CUDA_ARCH__ ) -#if ( CUDA_VERSION < 9000 ) +#if defined(__CUDA_ARCH__) +#if (CUDA_VERSION < 9000) #define KOKKOS_IMPL_CUDA_ACTIVEMASK 0 #define KOKKOS_IMPL_CUDA_SYNCWARP __threadfence_block() -#define KOKKOS_IMPL_CUDA_SYNCWARP_MASK(m) if(m)__threadfence_block() +#define KOKKOS_IMPL_CUDA_SYNCWARP_MASK(m) \ + if (m) __threadfence_block() #define KOKKOS_IMPL_CUDA_BALLOT(x) __ballot(x) -#define KOKKOS_IMPL_CUDA_BALLOT_MASK(m,x) __ballot(x) -#define KOKKOS_IMPL_CUDA_SHFL(x,y,z) __shfl(x,y,z) -#define KOKKOS_IMPL_CUDA_SHFL_MASK(m,x,y,z) __shfl(x,y,z) -#define KOKKOS_IMPL_CUDA_SHFL_UP(x,y,z) __shfl_up(x,y,z) -#define KOKKOS_IMPL_CUDA_SHFL_UP_MASK(m,x,y,z) __shfl_up(x,y,z) -#define KOKKOS_IMPL_CUDA_SHFL_DOWN(x,y,z) __shfl_down(x,y,z) -#define KOKKOS_IMPL_CUDA_SHFL_DOWN_MASK(m,x,y,z) __shfl_down(x,y,z) +#define KOKKOS_IMPL_CUDA_BALLOT_MASK(m, x) __ballot(x) +#define KOKKOS_IMPL_CUDA_SHFL(x, y, z) __shfl(x, y, z) +#define KOKKOS_IMPL_CUDA_SHFL_MASK(m, x, y, z) __shfl(x, y, z) +#define KOKKOS_IMPL_CUDA_SHFL_UP(x, y, z) __shfl_up(x, y, z) +#define KOKKOS_IMPL_CUDA_SHFL_UP_MASK(m, x, y, z) __shfl_up(x, y, z) +#define KOKKOS_IMPL_CUDA_SHFL_DOWN(x, y, z) __shfl_down(x, y, z) +#define KOKKOS_IMPL_CUDA_SHFL_DOWN_MASK(m, x, y, z) __shfl_down(x, y, z) #else #define KOKKOS_IMPL_CUDA_ACTIVEMASK __activemask() #define KOKKOS_IMPL_CUDA_SYNCWARP __syncwarp(0xffffffff) #define KOKKOS_IMPL_CUDA_SYNCWARP_MASK(m) __syncwarp(m) -#define KOKKOS_IMPL_CUDA_BALLOT(x) __ballot_sync(__activemask(),x) -#define KOKKOS_IMPL_CUDA_BALLOT_MASK(m,x) __ballot_sync(m,x) -#define KOKKOS_IMPL_CUDA_SHFL(x,y,z) __shfl_sync(0xffffffff,x,y,z) -#define KOKKOS_IMPL_CUDA_SHFL_MASK(m,x,y,z) __shfl_sync(m,x,y,z) -#define KOKKOS_IMPL_CUDA_SHFL_UP(x,y,z) __shfl_up_sync(0xffffffff,x,y,z) -#define KOKKOS_IMPL_CUDA_SHFL_UP_MASK(m,x,y,z) __shfl_up_sync(m,x,y,z) -#define KOKKOS_IMPL_CUDA_SHFL_DOWN(x,y,z) __shfl_down_sync(0xffffffff,x,y,z) -#define KOKKOS_IMPL_CUDA_SHFL_DOWN_MASK(m,x,y,z) __shfl_down_sync(m,x,y,z) -#endif +#define KOKKOS_IMPL_CUDA_BALLOT(x) __ballot_sync(__activemask(), x) +#define KOKKOS_IMPL_CUDA_BALLOT_MASK(m, x) __ballot_sync(m, x) +#define KOKKOS_IMPL_CUDA_SHFL(x, y, z) __shfl_sync(0xffffffff, x, y, z) +#define KOKKOS_IMPL_CUDA_SHFL_MASK(m, x, y, z) __shfl_sync(m, x, y, z) +#define KOKKOS_IMPL_CUDA_SHFL_UP(x, y, z) __shfl_up_sync(0xffffffff, x, y, z) +#define KOKKOS_IMPL_CUDA_SHFL_UP_MASK(m, x, y, z) __shfl_up_sync(m, x, y, z) +#define KOKKOS_IMPL_CUDA_SHFL_DOWN(x, y, z) \ + __shfl_down_sync(0xffffffff, x, y, z) +#define KOKKOS_IMPL_CUDA_SHFL_DOWN_MASK(m, x, y, z) __shfl_down_sync(m, x, y, z) +#endif #else #define KOKKOS_IMPL_CUDA_ACTIVEMASK 0 -#define KOKKOS_IMPL_CUDA_SYNCWARP +#define KOKKOS_IMPL_CUDA_SYNCWARP #define KOKKOS_IMPL_CUDA_SYNCWARP_MASK(m) (void)m #define KOKKOS_IMPL_CUDA_BALLOT(x) 0 -#define KOKKOS_IMPL_CUDA_BALLOT_MASK(m,x) 0 -#define KOKKOS_IMPL_CUDA_SHFL(x,y,z) 0 -#define KOKKOS_IMPL_CUDA_SHFL_MASK(m,x,y,z) 0 -#define KOKKOS_IMPL_CUDA_SHFL_UP(x,y,z) 0 -#define KOKKOS_IMPL_CUDA_SHFL_DOWN(x,y,z) 0 -#define KOKKOS_IMPL_CUDA_SHFL_DOWN_MASK(m,x,y,z) 0 -#endif +#define KOKKOS_IMPL_CUDA_BALLOT_MASK(m, x) 0 +#define KOKKOS_IMPL_CUDA_SHFL(x, y, z) 0 +#define KOKKOS_IMPL_CUDA_SHFL_MASK(m, x, y, z) 0 +#define KOKKOS_IMPL_CUDA_SHFL_UP(x, y, z) 0 +#define KOKKOS_IMPL_CUDA_SHFL_DOWN(x, y, z) 0 +#define KOKKOS_IMPL_CUDA_SHFL_DOWN_MASK(m, x, y, z) 0 +#endif -#if ( CUDA_VERSION >= 9000 ) && (!defined(KOKKOS_COMPILER_CLANG)) +#if (CUDA_VERSION >= 9000) && (!defined(KOKKOS_COMPILER_CLANG)) #define KOKKOS_IMPL_CUDA_MAX_SHFL_SIZEOF sizeof(long long) #else #define KOKKOS_IMPL_CUDA_MAX_SHFL_SIZEOF sizeof(int) #endif -#if defined( __CUDA_ARCH__ ) -#if ( CUDA_VERSION < 9000 ) -#define KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN( MSG ) { \ - const unsigned b = __ballot(1); \ - if ( b != 0xffffffff ) { \ - printf(" SYNCWARP AT %s (%d,%d,%d) (%d,%d,%d) failed %x\n" \ - , MSG \ - , blockIdx.x \ - , blockIdx.y \ - , blockIdx.z \ - , threadIdx.x \ - , threadIdx.y \ - , threadIdx.z \ - , b ); \ - return ; \ - } \ -} +#if defined(__CUDA_ARCH__) +#if (CUDA_VERSION < 9000) +#define KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN(MSG) \ + { \ + const unsigned b = __ballot(1); \ + if (b != 0xffffffff) { \ + printf(" SYNCWARP AT %s (%d,%d,%d) (%d,%d,%d) failed %x\n", MSG, \ + blockIdx.x, blockIdx.y, blockIdx.z, threadIdx.x, threadIdx.y, \ + threadIdx.z, b); \ + return; \ + } \ + } #else -#define KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN( MSG ) { \ - __syncwarp(); \ - const unsigned b = __activemask(); \ - if ( b != 0xffffffff ) { \ - printf(" SYNCWARP AT %s (%d,%d,%d) (%d,%d,%d) failed %x\n" \ - , MSG \ - , blockIdx.x \ - , blockIdx.y \ - , blockIdx.z \ - , threadIdx.x \ - , threadIdx.y \ - , threadIdx.z \ - , b ); \ - return ; \ - } \ -} -#endif +#define KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN(MSG) \ + { \ + __syncwarp(); \ + const unsigned b = __activemask(); \ + if (b != 0xffffffff) { \ + printf(" SYNCWARP AT %s (%d,%d,%d) (%d,%d,%d) failed %x\n", MSG, \ + blockIdx.x, blockIdx.y, blockIdx.z, threadIdx.x, threadIdx.y, \ + threadIdx.z, b); \ + return; \ + } \ + } +#endif #else -#define KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN( MSG ) -#endif - +#define KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN(MSG) +#endif diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_View.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_View.hpp index 2fe9d8ccf7..08fdbea387 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_View.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_View.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,7 +46,7 @@ #define KOKKOS_EXPERIMENTAL_CUDA_VIEW_HPP #include -#if defined( KOKKOS_ENABLE_CUDA ) +#if defined(KOKKOS_ENABLE_CUDA) //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -53,117 +54,101 @@ namespace Kokkos { namespace Impl { -// Cuda Texture fetches can be performed for 4, 8 and 16 byte objects (int,int2,int4) -// Via reinterpret_case this can be used to support all scalar types of those sizes. -// Any other scalar type falls back to either normal reads out of global memory, -// or using the __ldg intrinsic on Kepler GPUs or newer (Compute Capability >= 3.0) +// Cuda Texture fetches can be performed for 4, 8 and 16 byte objects +// (int,int2,int4) Via reinterpret_case this can be used to support all scalar +// types of those sizes. Any other scalar type falls back to either normal reads +// out of global memory, or using the __ldg intrinsic on Kepler GPUs or newer +// (Compute Capability >= 3.0) -template< typename ValueType , typename AliasType > +template struct CudaTextureFetch { - - ::cudaTextureObject_t m_obj ; - const ValueType * m_ptr ; - int m_offset ; + ::cudaTextureObject_t m_obj; + const ValueType* m_ptr; + int m_offset; // Deference operator pulls through texture object and returns by value - template< typename iType > - KOKKOS_INLINE_FUNCTION - ValueType operator[]( const iType & i ) const - { -#if defined( __CUDA_ARCH__ ) && ( 300 <= __CUDA_ARCH__ ) - AliasType v = tex1Dfetch( m_obj , i + m_offset ); - return *(reinterpret_cast (&v)); + template + KOKKOS_INLINE_FUNCTION ValueType operator[](const iType& i) const { +#if defined(__CUDA_ARCH__) && (300 <= __CUDA_ARCH__) + AliasType v = tex1Dfetch(m_obj, i + m_offset); + return *(reinterpret_cast(&v)); #else - return m_ptr[ i ]; + return m_ptr[i]; #endif - } + } // Pointer to referenced memory KOKKOS_INLINE_FUNCTION - operator const ValueType * () const { return m_ptr ; } - + operator const ValueType*() const { return m_ptr; } KOKKOS_INLINE_FUNCTION - CudaTextureFetch() : m_obj() , m_ptr() , m_offset() {} + CudaTextureFetch() : m_obj(), m_ptr(), m_offset() {} KOKKOS_INLINE_FUNCTION ~CudaTextureFetch() {} KOKKOS_INLINE_FUNCTION - CudaTextureFetch( const CudaTextureFetch & rhs ) - : m_obj( rhs.m_obj ) - , m_ptr( rhs.m_ptr ) - , m_offset( rhs.m_offset ) - {} + CudaTextureFetch(const CudaTextureFetch& rhs) + : m_obj(rhs.m_obj), m_ptr(rhs.m_ptr), m_offset(rhs.m_offset) {} KOKKOS_INLINE_FUNCTION - CudaTextureFetch( CudaTextureFetch && rhs ) - : m_obj( rhs.m_obj ) - , m_ptr( rhs.m_ptr ) - , m_offset( rhs.m_offset ) - {} + CudaTextureFetch(CudaTextureFetch&& rhs) + : m_obj(rhs.m_obj), m_ptr(rhs.m_ptr), m_offset(rhs.m_offset) {} KOKKOS_INLINE_FUNCTION - CudaTextureFetch & operator = ( const CudaTextureFetch & rhs ) - { - m_obj = rhs.m_obj ; - m_ptr = rhs.m_ptr ; - m_offset = rhs.m_offset ; - return *this ; - } + CudaTextureFetch& operator=(const CudaTextureFetch& rhs) { + m_obj = rhs.m_obj; + m_ptr = rhs.m_ptr; + m_offset = rhs.m_offset; + return *this; + } KOKKOS_INLINE_FUNCTION - CudaTextureFetch & operator = ( CudaTextureFetch && rhs ) - { - m_obj = rhs.m_obj ; - m_ptr = rhs.m_ptr ; - m_offset = rhs.m_offset ; - return *this ; - } + CudaTextureFetch& operator=(CudaTextureFetch&& rhs) { + m_obj = rhs.m_obj; + m_ptr = rhs.m_ptr; + m_offset = rhs.m_offset; + return *this; + } // Texture object spans the entire allocation. // This handle may view a subset of the allocation, so an offset is required. - template< class CudaMemorySpace > - inline explicit - CudaTextureFetch( const ValueType * const arg_ptr - , Kokkos::Impl::SharedAllocationRecord< CudaMemorySpace , void > * record - ) - : m_obj( record->template attach_texture_object< AliasType >() ) - , m_ptr( arg_ptr ) - , m_offset( record->attach_texture_object_offset( reinterpret_cast( arg_ptr ) ) ) - {} + template + inline explicit CudaTextureFetch( + const ValueType* const arg_ptr, + Kokkos::Impl::SharedAllocationRecord* record) + : m_obj(record->template attach_texture_object()), + m_ptr(arg_ptr), + m_offset(record->attach_texture_object_offset( + reinterpret_cast(arg_ptr))) {} // Texture object spans the entire allocation. // This handle may view a subset of the allocation, so an offset is required. KOKKOS_INLINE_FUNCTION - CudaTextureFetch( const CudaTextureFetch & rhs , size_t offset ) - : m_obj( rhs.m_obj ) - , m_ptr( rhs.m_ptr + offset) - , m_offset( offset + rhs.m_offset ) - {} + CudaTextureFetch(const CudaTextureFetch& rhs, size_t offset) + : m_obj(rhs.m_obj), + m_ptr(rhs.m_ptr + offset), + m_offset(offset + rhs.m_offset) {} }; -#if defined( KOKKOS_ENABLE_CUDA_LDG_INTRINSIC ) +#if defined(KOKKOS_ENABLE_CUDA_LDG_INTRINSIC) -template< typename ValueType , typename AliasType > +template struct CudaLDGFetch { + const ValueType* m_ptr; - const ValueType * m_ptr ; - - template< typename iType > - KOKKOS_INLINE_FUNCTION - ValueType operator[]( const iType & i ) const - { - #ifdef __CUDA_ARCH__ - AliasType v = __ldg(reinterpret_cast(&m_ptr[i])); - return *(reinterpret_cast (&v)); - #else - return m_ptr[i]; - #endif - } + template + KOKKOS_INLINE_FUNCTION ValueType operator[](const iType& i) const { +#ifdef __CUDA_ARCH__ + AliasType v = __ldg(reinterpret_cast(&m_ptr[i])); + return *(reinterpret_cast(&v)); +#else + return m_ptr[i]; +#endif + } KOKKOS_INLINE_FUNCTION - operator const ValueType * () const { return m_ptr ; } + operator const ValueType*() const { return m_ptr; } KOKKOS_INLINE_FUNCTION CudaLDGFetch() : m_ptr() {} @@ -172,48 +157,38 @@ struct CudaLDGFetch { ~CudaLDGFetch() {} KOKKOS_INLINE_FUNCTION - CudaLDGFetch( const CudaLDGFetch & rhs ) - : m_ptr( rhs.m_ptr ) - {} + CudaLDGFetch(const CudaLDGFetch& rhs) : m_ptr(rhs.m_ptr) {} KOKKOS_INLINE_FUNCTION - CudaLDGFetch( CudaLDGFetch && rhs ) - : m_ptr( rhs.m_ptr ) - {} + CudaLDGFetch(CudaLDGFetch&& rhs) : m_ptr(rhs.m_ptr) {} KOKKOS_INLINE_FUNCTION - CudaLDGFetch & operator = ( const CudaLDGFetch & rhs ) - { - m_ptr = rhs.m_ptr ; - return *this ; - } + CudaLDGFetch& operator=(const CudaLDGFetch& rhs) { + m_ptr = rhs.m_ptr; + return *this; + } KOKKOS_INLINE_FUNCTION - CudaLDGFetch & operator = ( CudaLDGFetch && rhs ) - { - m_ptr = rhs.m_ptr ; - return *this ; - } + CudaLDGFetch& operator=(CudaLDGFetch&& rhs) { + m_ptr = rhs.m_ptr; + return *this; + } - template< class CudaMemorySpace > - inline explicit - CudaLDGFetch( const ValueType * const arg_ptr - , Kokkos::Impl::SharedAllocationRecord* - ) - : m_ptr( arg_ptr ) - {} + template + inline explicit CudaLDGFetch( + const ValueType* const arg_ptr, + Kokkos::Impl::SharedAllocationRecord*) + : m_ptr(arg_ptr) {} KOKKOS_INLINE_FUNCTION - CudaLDGFetch( CudaLDGFetch const rhs ,size_t offset) - : m_ptr( rhs.m_ptr + offset ) - {} - + CudaLDGFetch(CudaLDGFetch const rhs, size_t offset) + : m_ptr(rhs.m_ptr + offset) {} }; #endif -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -221,98 +196,95 @@ struct CudaLDGFetch { namespace Kokkos { namespace Impl { -/** \brief Replace Default ViewDataHandle with Cuda texture fetch specialization - * if 'const' value type, CudaSpace and random access. +/** \brief Replace Default ViewDataHandle with Cuda texture fetch + * specialization if 'const' value type, CudaSpace and random access. */ -template< class Traits > -class ViewDataHandle< Traits , - typename std::enable_if<( - // Is Cuda memory space - ( std::is_same< typename Traits::memory_space,Kokkos::CudaSpace>::value || - std::is_same< typename Traits::memory_space,Kokkos::CudaUVMSpace>::value ) - && - // Is a trivial const value of 4, 8, or 16 bytes - std::is_trivial::value - && - std::is_same::value - && - ( sizeof(typename Traits::const_value_type) == 4 || - sizeof(typename Traits::const_value_type) == 8 || - sizeof(typename Traits::const_value_type) == 16 ) - && - // Random access trait - ( Traits::memory_traits::is_random_access != 0 ) - )>::type > -{ -public: - - using track_type = Kokkos::Impl::SharedAllocationTracker ; - - using value_type = typename Traits::const_value_type ; - using return_type = typename Traits::const_value_type ; // NOT a reference - - using alias_type = typename std::conditional< ( sizeof(value_type) == 4 ) , int , - typename std::conditional< ( sizeof(value_type) == 8 ) , ::int2 , - typename std::conditional< ( sizeof(value_type) == 16 ) , ::int4 , void - >::type - >::type - >::type ; - -#if defined( KOKKOS_ENABLE_CUDA_LDG_INTRINSIC ) - using handle_type = Kokkos::Impl::CudaLDGFetch< value_type , alias_type > ; +template +class ViewDataHandle< + Traits, typename std::enable_if<( + // Is Cuda memory space + (std::is_same::value || + std::is_same::value) && + // Is a trivial const value of 4, 8, or 16 bytes + std::is_trivial::value && + std::is_same::value && + (sizeof(typename Traits::const_value_type) == 4 || + sizeof(typename Traits::const_value_type) == 8 || + sizeof(typename Traits::const_value_type) == 16) && + // Random access trait + (Traits::memory_traits::is_random_access != 0))>::type> { + public: + using track_type = Kokkos::Impl::SharedAllocationTracker; + + using value_type = typename Traits::const_value_type; + using return_type = typename Traits::const_value_type; // NOT a reference + + using alias_type = typename std::conditional< + (sizeof(value_type) == 4), int, + typename std::conditional< + (sizeof(value_type) == 8), ::int2, + typename std::conditional<(sizeof(value_type) == 16), ::int4, + void>::type>::type>::type; + +#if defined(KOKKOS_ENABLE_CUDA_LDG_INTRINSIC) + using handle_type = Kokkos::Impl::CudaLDGFetch; #else - using handle_type = Kokkos::Impl::CudaTextureFetch< value_type , alias_type > ; + using handle_type = Kokkos::Impl::CudaTextureFetch; #endif KOKKOS_INLINE_FUNCTION - static handle_type const & assign( handle_type const & arg_handle , track_type const & /* arg_tracker */ ) - { - return arg_handle ; - } + static handle_type const& assign(handle_type const& arg_handle, + track_type const& /* arg_tracker */) { + return arg_handle; + } KOKKOS_INLINE_FUNCTION - static handle_type const assign( handle_type const & arg_handle , size_t offset ) - { - return handle_type(arg_handle,offset) ; - } + static handle_type const assign(handle_type const& arg_handle, + size_t offset) { + return handle_type(arg_handle, offset); + } KOKKOS_INLINE_FUNCTION - static handle_type assign( value_type * arg_data_ptr, track_type const & arg_tracker ) - { - if(arg_data_ptr == NULL) return handle_type(); - -#if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) - // Assignment of texture = non-texture requires creation of a texture object - // which can only occur on the host. In addition, 'get_record' is only valid - // if called in a host execution space + static handle_type assign(value_type* arg_data_ptr, + track_type const& arg_tracker) { + if (arg_data_ptr == NULL) return handle_type(); +#if defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST) + // Assignment of texture = non-texture requires creation of a texture object + // which can only occur on the host. In addition, 'get_record' is only + // valid if called in a host execution space - typedef typename Traits::memory_space memory_space ; - typedef typename Impl::SharedAllocationRecord record ; + typedef typename Traits::memory_space memory_space; + typedef typename Impl::SharedAllocationRecord record; - record * const r = arg_tracker.template get_record< memory_space >(); + record* const r = arg_tracker.template get_record(); -#if ! defined( KOKKOS_ENABLE_CUDA_LDG_INTRINSIC ) - if ( 0 == r ) { - Kokkos::abort("Cuda const random access View using Cuda texture memory requires Kokkos to allocate the View's memory"); - } +#if !defined(KOKKOS_ENABLE_CUDA_LDG_INTRINSIC) + if (0 == r) { + Kokkos::abort( + "Cuda const random access View using Cuda texture memory requires " + "Kokkos to allocate the View's memory"); + } #endif - return handle_type( arg_data_ptr , r ); + return handle_type(arg_data_ptr, r); #else - Kokkos::Impl::cuda_abort("Cannot create Cuda texture object from within a Cuda kernel"); - return handle_type(); + Kokkos::Impl::cuda_abort( + "Cannot create Cuda texture object from within a Cuda kernel"); + return handle_type(); #endif - } + } }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- #endif /* #if defined( KOKKOS_ENABLE_CUDA ) */ #endif /* #ifndef KOKKOS_CUDA_VIEW_HPP */ - diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ViewCopyETIAvail.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ViewCopyETIAvail.hpp index 33615f3f9f..2fbfb67277 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ViewCopyETIAvail.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ViewCopyETIAvail.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,10 +49,9 @@ namespace Kokkos { namespace Impl { #define KOKKOS_IMPL_VIEWCOPY_ETI_AVAIL_EXECSPACE Kokkos::Cuda -#include +#include #undef KOKKOS_IMPL_VIEWCOPY_ETI_AVAIL_EXECSPACE -} -} +} // namespace Impl +} // namespace Kokkos #endif - diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ViewCopyETIDecl.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ViewCopyETIDecl.hpp index befff1a865..18e56aa32d 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ViewCopyETIDecl.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ViewCopyETIDecl.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,10 +49,9 @@ namespace Kokkos { namespace Impl { #define KOKKOS_IMPL_VIEWCOPY_ETI_AVAIL_EXECSPACE Kokkos::Cuda -#include +#include #undef KOKKOS_IMPL_VIEWCOPY_ETI_AVAIL_EXECSPACE -} -} +} // namespace Impl +} // namespace Kokkos #endif - diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_WorkGraphPolicy.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_WorkGraphPolicy.hpp index 9c0ac470c8..0753e383a1 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_WorkGraphPolicy.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_WorkGraphPolicy.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -47,74 +48,64 @@ namespace Kokkos { namespace Impl { -template< class FunctorType , class ... Traits > -class ParallelFor< FunctorType - , Kokkos::WorkGraphPolicy< Traits ... > - , Kokkos::Cuda - > -{ -public: +template +class ParallelFor, + Kokkos::Cuda> { + public: + typedef Kokkos::WorkGraphPolicy Policy; + typedef ParallelFor Self; - typedef Kokkos::WorkGraphPolicy< Traits ... > Policy ; - typedef ParallelFor Self ; + private: + Policy m_policy; + FunctorType m_functor; -private: - - Policy m_policy ; - FunctorType m_functor ; - - template< class TagType > + template __device__ inline - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec_one( const std::int32_t w ) const noexcept - { m_functor( w ); } - - template< class TagType > - __device__ inline - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec_one( const std::int32_t w ) const noexcept - { const TagType t{} ; m_functor( t , w ); } - -public: + typename std::enable_if::value>::type + exec_one(const std::int32_t w) const noexcept { + m_functor(w); + } + template __device__ inline - void operator()() const noexcept - { - if ( 0 == ( threadIdx.y % 16 ) ) { - - // Spin until COMPLETED_TOKEN. - // END_TOKEN indicates no work is currently available. + typename std::enable_if::value>::type + exec_one(const std::int32_t w) const noexcept { + const TagType t{}; + m_functor(t, w); + } - for ( std::int32_t w = Policy::END_TOKEN ; - Policy::COMPLETED_TOKEN != ( w = m_policy.pop_work() ) ; ) { - if ( Policy::END_TOKEN != w ) { - exec_one< typename Policy::work_tag >( w ); - m_policy.completed_work(w); - } + public: + __device__ inline void operator()() const noexcept { + if (0 == (threadIdx.y % 16)) { + // Spin until COMPLETED_TOKEN. + // END_TOKEN indicates no work is currently available. + + for (std::int32_t w = Policy::END_TOKEN; + Policy::COMPLETED_TOKEN != (w = m_policy.pop_work());) { + if (Policy::END_TOKEN != w) { + exec_one(w); + m_policy.completed_work(w); } } } + } - inline - void execute() - { - const int warps_per_block = 4 ; - const dim3 grid( Kokkos::Impl::cuda_internal_multiprocessor_count() , 1 , 1 ); - const dim3 block( 1 , Kokkos::Impl::CudaTraits::WarpSize , warps_per_block ); - const int shared = 0 ; + inline void execute() { + const int warps_per_block = 4; + const dim3 grid(Kokkos::Impl::cuda_internal_multiprocessor_count(), 1, 1); + const dim3 block(1, Kokkos::Impl::CudaTraits::WarpSize, warps_per_block); + const int shared = 0; - Kokkos::Impl::CudaParallelLaunch(*this, grid, block, shared, Cuda().impl_internal_space_instance() , false ); + Kokkos::Impl::CudaParallelLaunch( + *this, grid, block, shared, Cuda().impl_internal_space_instance(), + false); } - inline - ParallelFor( const FunctorType & arg_functor - , const Policy & arg_policy ) - : m_policy( arg_policy ) - , m_functor( arg_functor ) - {} + inline ParallelFor(const FunctorType& arg_functor, const Policy& arg_policy) + : m_policy(arg_policy), m_functor(arg_functor) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos #endif /* #define KOKKOS_CUDA_WORKGRAPHPOLICY_HPP */ diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_abort.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_abort.hpp index 9f5415b511..698695dbdb 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_abort.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_abort.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -47,7 +48,7 @@ //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- #include -#if defined( __CUDACC__ ) && defined( KOKKOS_ENABLE_CUDA ) +#if defined(__CUDACC__) && defined(KOKKOS_ENABLE_CUDA) #include @@ -55,35 +56,26 @@ extern "C" { /* Cuda runtime function, declared in * Requires capability 2.x or better. */ -extern __device__ void __assertfail( - const void *message, - const void *file, - unsigned int line, - const void *function, - size_t charsize); +extern __device__ void __assertfail(const void *message, const void *file, + unsigned int line, const void *function, + size_t charsize); } namespace Kokkos { namespace Impl { -__device__ inline -void cuda_abort( const char * const message ) -{ +__device__ inline void cuda_abort(const char *const message) { #ifndef __APPLE__ - const char empty[] = "" ; + const char empty[] = ""; - __assertfail( (const void *) message , - (const void *) empty , - (unsigned int) 0 , - (const void *) empty , - sizeof(char) ); + __assertfail((const void *)message, (const void *)empty, (unsigned int)0, + (const void *)empty, sizeof(char)); #endif } -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos #else void KOKKOS_CORE_SRC_CUDA_ABORT_PREVENT_LINK_ERROR() {} #endif /* #if defined(__CUDACC__) && defined( KOKKOS_ENABLE_CUDA ) */ #endif /* #ifndef KOKKOS_CUDA_ABORT_HPP */ - diff --git a/lib/kokkos/core/src/HPX/Kokkos_HPX.cpp b/lib/kokkos/core/src/HPX/Kokkos_HPX.cpp index da9783467c..0c4cca70f8 100644 --- a/lib/kokkos/core/src/HPX/Kokkos_HPX.cpp +++ b/lib/kokkos/core/src/HPX/Kokkos_HPX.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,7 +42,6 @@ //@HEADER */ - #include #ifdef KOKKOS_ENABLE_HPX @@ -80,8 +80,8 @@ void HPX::impl_initialize(int thread_count) { "--hpx:attach-debugger=exception", #endif }; - int argc_hpx = 1; - char name[] = "kokkos_hpx"; + int argc_hpx = 1; + char name[] = "kokkos_hpx"; char *argv_hpx[] = {name, nullptr}; hpx::start(nullptr, argc_hpx, argv_hpx, config); @@ -107,8 +107,8 @@ void HPX::impl_initialize() { "--hpx:attach-debugger=exception", #endif }; - int argc_hpx = 1; - char name[] = "kokkos_hpx"; + int argc_hpx = 1; + char name[] = "kokkos_hpx"; char *argv_hpx[] = {name, nullptr}; hpx::start(nullptr, argc_hpx, argv_hpx, config); @@ -138,15 +138,16 @@ void HPX::impl_finalize() { hpx::apply([]() { hpx::finalize(); }); hpx::stop(); } else { - Kokkos::abort("Kokkos::Experimental::HPX::impl_finalize: Kokkos started " - "HPX but something else already stopped HPX\n"); + Kokkos::abort( + "Kokkos::Experimental::HPX::impl_finalize: Kokkos started " + "HPX but something else already stopped HPX\n"); } } } -} // namespace Experimental -} // namespace Kokkos +} // namespace Experimental +} // namespace Kokkos #else void KOKKOS_CORE_SRC_IMPL_HPX_PREVENT_LINK_ERROR() {} -#endif //#ifdef KOKKOS_ENABLE_HPX +#endif //#ifdef KOKKOS_ENABLE_HPX diff --git a/lib/kokkos/core/src/HPX/Kokkos_HPX_ChunkedRoundRobinExecutor.hpp b/lib/kokkos/core/src/HPX/Kokkos_HPX_ChunkedRoundRobinExecutor.hpp new file mode 100644 index 0000000000..b364b4a6eb --- /dev/null +++ b/lib/kokkos/core/src/HPX/Kokkos_HPX_ChunkedRoundRobinExecutor.hpp @@ -0,0 +1,208 @@ +/* +//@HEADER +// ************************************************************************ +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the Corporation nor the names of the +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact Christian R. Trott (crtrott@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#ifndef KOKKOS_HPX_CHUNKEDROUNDROBINEXECUTOR_HPP +#define KOKKOS_HPX_CHUNKEDROUNDROBINEXECUTOR_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace Kokkos { +namespace Impl { + +/////////////////////////////////////////////////////////////////////////// +/// A \a ChunkedRoundRobinExecutor creates groups of parallel execution +/// agents which execute in threads implicitly created by the executor. This +/// executor uses the scheduling hint to spawn threads with the first grouped on +/// the first core, the second group getting the next consecutive threads, etc. +/// For example, if 10 tasks are spawned (num_tasks is set to 10) and num_cores +/// is set to 2 the executor will schedule the tasks in the following order: +/// +/// worker thread | 1 | 2 +/// --------------+---+--- +/// tasks | 1 | 6 +/// | 2 | 7 +/// | 3 | 8 +/// | 4 | 9 +/// | 5 | 10 +/// +/// rather than the typical round robin: +/// +/// worker thread | 1 | 2 +/// --------------+---+--- +/// tasks | 1 | 2 +/// | 3 | 4 +/// | 5 | 6 +/// | 7 | 8 +/// | 9 | 10 +struct ChunkedRoundRobinExecutor { + using execution_category = hpx::parallel::execution::parallel_execution_tag; + + HPX_CONSTEXPR explicit ChunkedRoundRobinExecutor( + std::size_t num_tasks = std::size_t(-1), std::size_t core_offset = 0, + std::size_t num_cores = hpx::get_os_thread_count()) + : num_tasks_(num_tasks), + core_offset_(core_offset), + num_cores_(num_cores), + num_tasks_per_core_(double(num_tasks_) / num_cores_), + num_tasks_spawned_(0) {} + + bool operator==(ChunkedRoundRobinExecutor const &rhs) const noexcept { + return num_cores_ == rhs.num_cores_ && num_tasks_ == rhs.num_tasks_; + } + + bool operator!=(ChunkedRoundRobinExecutor const &rhs) const noexcept { + return !(*this == rhs); + } + + ChunkedRoundRobinExecutor const &context() const noexcept { return *this; } + + template + hpx::future< + typename hpx::util::detail::invoke_deferred_result::type> + async_execute(F &&f, Ts &&... ts) const { + return hpx::detail::async_launch_policy_dispatch::call( + hpx::launch::async_policy{}, std::forward(f), + std::forward(ts)...); + } + + template + void post(F &&f, Ts &&... ts) const { + hpx::util::thread_description const desc( + f, "Kokkos::Impl::ChunkedRoundRobinExecutor::async_execute"); + hpx::threads::thread_schedule_hint const hint( + hpx::threads::thread_schedule_hint_mode_thread, + core_offset_ + std::floor(double(num_tasks_spawned_ % num_tasks_) / + num_tasks_per_core_)); + + hpx::threads::register_thread_nullary( + hpx::util::deferred_call(std::forward(f), std::forward(ts)...), + desc, hpx::threads::pending, false, + hpx::threads::thread_priority_normal, hint, + hpx::threads::thread_stacksize_default); + + ++num_tasks_spawned_; + } + + template + std::vector::type>> + bulk_async_execute(F &&f, Shape const &shape, Ts &&... ts) { + hpx::util::thread_description desc( + f, "Kokkos::Impl::ChunkedRoundRobinExecutor::bulk_sync_execute"); + + hpx::lcos::local::latch l(hpx::util::size(shape)); + // Keep a separate counter for bulk launch + std::size_t num_tasks_spawned = 0; + + for (auto const &s : shape) { + hpx::threads::thread_schedule_hint const hint( + hpx::threads::thread_schedule_hint_mode_thread, + core_offset_ + std::floor(double(num_tasks_spawned % num_tasks_) / + num_tasks_per_core_)); + + hpx::threads::register_thread_nullary( + [&, s]() { + hpx::util::invoke(f, s, ts...); + l.count_down(1); + }, + desc, hpx::threads::pending, false, + hpx::threads::thread_priority_normal, hint, + hpx::threads::thread_stacksize_default); + + ++num_tasks_spawned; + } + + // NOTE: We block here to avoid extra synchronization. Since this executor + // is only used in the HPX backend we get away with this. + l.wait(); + + return {}; + } + + private: + std::size_t num_tasks_; + std::size_t core_offset_; + std::size_t num_cores_; + double num_tasks_per_core_; + mutable std::size_t num_tasks_spawned_; +}; + +} // namespace Impl +} // namespace Kokkos + +namespace hpx { +namespace parallel { +namespace execution { + +template <> +struct is_one_way_executor + : std::true_type {}; + +template <> +struct is_two_way_executor + : std::true_type {}; + +template <> +struct is_bulk_two_way_executor + : std::true_type {}; + +} // namespace execution +} // namespace parallel +} // namespace hpx + +#endif diff --git a/lib/kokkos/core/src/HPX/Kokkos_HPX_Task.cpp b/lib/kokkos/core/src/HPX/Kokkos_HPX_Task.cpp index df7c403685..8d42589bdf 100644 --- a/lib/kokkos/core/src/HPX/Kokkos_HPX_Task.cpp +++ b/lib/kokkos/core/src/HPX/Kokkos_HPX_Task.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -57,9 +58,9 @@ namespace Impl { template class TaskQueue; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos #else void KOKKOS_CORE_SRC_IMPL_HPX_TASK_PREVENT_LINK_ERROR() {} -#endif // #if defined( KOKKOS_ENABLE_HPX ) && defined( KOKKOS_ENABLE_TASKDAG ) +#endif // #if defined( KOKKOS_ENABLE_HPX ) && defined( KOKKOS_ENABLE_TASKDAG ) diff --git a/lib/kokkos/core/src/HPX/Kokkos_HPX_Task.hpp b/lib/kokkos/core/src/HPX/Kokkos_HPX_Task.hpp index c3a14efee6..803d955914 100644 --- a/lib/kokkos/core/src/HPX/Kokkos_HPX_Task.hpp +++ b/lib/kokkos/core/src/HPX/Kokkos_HPX_Task.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -49,10 +50,11 @@ #include +#include #include #include -#include +#include #include @@ -65,7 +67,7 @@ namespace Impl { template class TaskQueueSpecialization< SimpleTaskScheduler> { -public: + public: using execution_space = Kokkos::Experimental::HPX; using scheduler_type = SimpleTaskScheduler; @@ -85,7 +87,7 @@ public: // Must provide task queue execution function void execute_task() const { using hpx::apply; - using hpx::lcos::local::counting_semaphore; + using hpx::lcos::local::latch; using task_base_type = typename scheduler_type::task_base_type; const int num_worker_threads = Kokkos::Experimental::HPX::concurrency(); @@ -95,25 +97,28 @@ public: auto &queue = scheduler->queue(); - counting_semaphore sem(0); + latch num_tasks_remaining(num_worker_threads); + ChunkedRoundRobinExecutor exec(num_worker_threads); for (int thread = 0; thread < num_worker_threads; ++thread) { - apply([this, &sem, &queue, &buffer, num_worker_threads, thread]() { + apply(exec, [this, &num_tasks_remaining, &queue, &buffer, + num_worker_threads]() { // NOTE: This implementation has been simplified based on the // assumption that team_size = 1. The HPX backend currently only // supports a team size of 1. std::size_t t = Kokkos::Experimental::HPX::impl_hardware_thread_id(); buffer.get(Kokkos::Experimental::HPX::impl_hardware_thread_id()); - HPXTeamMember member(TeamPolicyInternal( - Kokkos::Experimental::HPX(), num_worker_threads, 1), - 0, t, buffer.get(t), 512); + HPXTeamMember member( + TeamPolicyInternal( + Kokkos::Experimental::HPX(), num_worker_threads, 1), + 0, t, buffer.get(t), 512); member_type single_exec(*scheduler, member); member_type &team_exec = single_exec; auto &team_scheduler = team_exec.scheduler(); - auto current_task = OptionalRef(nullptr); + auto current_task = OptionalRef(nullptr); while (!queue.is_done()) { current_task = @@ -128,11 +133,11 @@ public: } } - sem.signal(1); + num_tasks_remaining.count_down(1); }); } - sem.wait(num_worker_threads); + num_tasks_remaining.wait(); } static uint32_t get_max_team_count(execution_space const &espace) { @@ -142,11 +147,11 @@ public: template static void get_function_pointer(typename TaskType::function_type &ptr, typename TaskType::destroy_type &dtor) { - ptr = TaskType::apply; + ptr = TaskType::apply; dtor = TaskType::destroy; } -private: + private: const scheduler_type *scheduler; }; @@ -155,21 +160,21 @@ class TaskQueueSpecializationConstrained< Scheduler, typename std::enable_if< std::is_same::value>::type> { -public: + public: using execution_space = Kokkos::Experimental::HPX; - using scheduler_type = Scheduler; + using scheduler_type = Scheduler; using member_type = TaskTeamMemberAdapter; using memory_space = Kokkos::HostSpace; - static void - iff_single_thread_recursive_execute(scheduler_type const &scheduler) { + static void iff_single_thread_recursive_execute( + scheduler_type const &scheduler) { using task_base_type = typename scheduler_type::task_base; - using queue_type = typename scheduler_type::queue_type; + using queue_type = typename scheduler_type::queue_type; if (1 == Kokkos::Experimental::HPX::concurrency()) { task_base_type *const end = (task_base_type *)task_base_type::EndTag; - task_base_type *task = end; + task_base_type *task = end; HPXTeamMember member(TeamPolicyInternal( Kokkos::Experimental::HPX(), 1, 1), @@ -187,8 +192,7 @@ public: } } - if (end == task) - break; + if (end == task) break; (*task->m_apply)(task, &single_exec); @@ -210,11 +214,11 @@ public: // Must provide task queue execution function void execute_task() const { using hpx::apply; - using hpx::lcos::local::counting_semaphore; + using hpx::lcos::local::latch; using task_base_type = typename scheduler_type::task_base; - using queue_type = typename scheduler_type::queue_type; + using queue_type = typename scheduler_type::queue_type; - const int num_worker_threads = Kokkos::Experimental::HPX::concurrency(); + const int num_worker_threads = Kokkos::Experimental::HPX::concurrency(); static task_base_type *const end = (task_base_type *)task_base_type::EndTag; constexpr task_base_type *no_more_tasks_sentinel = nullptr; @@ -224,10 +228,11 @@ public: auto &queue = scheduler->queue(); queue.initialize_team_queues(num_worker_threads); - counting_semaphore sem(0); + latch num_tasks_remaining(num_worker_threads); + ChunkedRoundRobinExecutor exec(num_worker_threads); for (int thread = 0; thread < num_worker_threads; ++thread) { - apply([this, &sem, &buffer, num_worker_threads, thread]() { + apply(exec, [this, &num_tasks_remaining, &buffer, num_worker_threads]() { // NOTE: This implementation has been simplified based on the assumption // that team_size = 1. The HPX backend currently only supports a team // size of 1. @@ -242,7 +247,7 @@ public: member_type single_exec(*scheduler, member); member_type &team_exec = single_exec; - auto &team_queue = team_exec.scheduler().queue(); + auto &team_queue = team_exec.scheduler().queue(); task_base_type *task = no_more_tasks_sentinel; do { @@ -266,21 +271,21 @@ public: } } while (task != no_more_tasks_sentinel); - sem.signal(1); + num_tasks_remaining.count_down(1); }); } - sem.wait(num_worker_threads); + num_tasks_remaining.wait(); } template static void get_function_pointer(typename TaskType::function_type &ptr, typename TaskType::destroy_type &dtor) { - ptr = TaskType::apply; + ptr = TaskType::apply; dtor = TaskType::destroy; } -private: + private: const scheduler_type *scheduler; }; @@ -288,8 +293,8 @@ extern template class TaskQueue< Kokkos::Experimental::HPX, typename Kokkos::Experimental::HPX::memory_space>; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- diff --git a/lib/kokkos/core/src/HPX/Kokkos_HPX_ViewCopyETIAvail.hpp b/lib/kokkos/core/src/HPX/Kokkos_HPX_ViewCopyETIAvail.hpp index bbc1b33bf9..99020a3e0d 100644 --- a/lib/kokkos/core/src/HPX/Kokkos_HPX_ViewCopyETIAvail.hpp +++ b/lib/kokkos/core/src/HPX/Kokkos_HPX_ViewCopyETIAvail.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,10 +49,9 @@ namespace Kokkos { namespace Impl { #define KOKKOS_IMPL_VIEWCOPY_ETI_AVAIL_EXECSPACE Kokkos::Experimental::HPX -#include +#include #undef KOKKOS_IMPL_VIEWCOPY_ETI_AVAIL_EXECSPACE -} -} +} // namespace Impl +} // namespace Kokkos #endif - diff --git a/lib/kokkos/core/src/HPX/Kokkos_HPX_ViewCopyETIDecl.hpp b/lib/kokkos/core/src/HPX/Kokkos_HPX_ViewCopyETIDecl.hpp index aa1c2f1518..fae486f4b0 100644 --- a/lib/kokkos/core/src/HPX/Kokkos_HPX_ViewCopyETIDecl.hpp +++ b/lib/kokkos/core/src/HPX/Kokkos_HPX_ViewCopyETIDecl.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,10 +49,9 @@ namespace Kokkos { namespace Impl { #define KOKKOS_IMPL_VIEWCOPY_ETI_AVAIL_EXECSPACE Kokkos::Experimental::HPX -#include +#include #undef KOKKOS_IMPL_VIEWCOPY_ETI_AVAIL_EXECSPACE -} -} +} // namespace Impl +} // namespace Kokkos #endif - diff --git a/lib/kokkos/core/src/HPX/Kokkos_HPX_WorkGraphPolicy.hpp b/lib/kokkos/core/src/HPX/Kokkos_HPX_WorkGraphPolicy.hpp index 4dd28dd994..6705005c1b 100644 --- a/lib/kokkos/core/src/HPX/Kokkos_HPX_WorkGraphPolicy.hpp +++ b/lib/kokkos/core/src/HPX/Kokkos_HPX_WorkGraphPolicy.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,8 +45,10 @@ #ifndef KOKKOS_HPX_WORKGRAPHPOLICY_HPP #define KOKKOS_HPX_WORKGRAPHPOLICY_HPP +#include + #include -#include +#include namespace Kokkos { namespace Impl { @@ -53,8 +56,8 @@ namespace Impl { template class ParallelFor, Kokkos::Experimental::HPX> { -private: - using Policy = Kokkos::WorkGraphPolicy; + private: + using Policy = Kokkos::WorkGraphPolicy; using WorkTag = typename Policy::work_tag; Policy m_policy; @@ -73,7 +76,7 @@ private: m_functor(t, w); } -public: + public: void execute() const { dispatch_execute_task(this); Kokkos::Experimental::HPX().fence(); @@ -83,12 +86,13 @@ public: const int num_worker_threads = Kokkos::Experimental::HPX::concurrency(); using hpx::apply; - using hpx::lcos::local::counting_semaphore; + using hpx::lcos::local::latch; - counting_semaphore sem(0); + latch num_tasks_remaining(num_worker_threads); + ChunkedRoundRobinExecutor exec(num_worker_threads); for (int thread = 0; thread < num_worker_threads; ++thread) { - apply([this, &sem]() { + apply(exec, [this, &num_tasks_remaining]() { std::int32_t w = m_policy.pop_work(); while (w != Policy::COMPLETED_TOKEN) { if (w != Policy::END_TOKEN) { @@ -99,18 +103,18 @@ public: w = m_policy.pop_work(); } - sem.signal(1); + num_tasks_remaining.count_down(1); }); } - sem.wait(num_worker_threads); + num_tasks_remaining.wait(); } inline ParallelFor(const FunctorType &arg_functor, const Policy &arg_policy) : m_policy(arg_policy), m_functor(arg_functor) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos #endif /* #define KOKKOS_HPX_WORKGRAPHPOLICY_HPP */ diff --git a/lib/kokkos/core/src/KokkosExp_MDRangePolicy.hpp b/lib/kokkos/core/src/KokkosExp_MDRangePolicy.hpp index 1972aa485b..7981c04b4f 100644 --- a/lib/kokkos/core/src/KokkosExp_MDRangePolicy.hpp +++ b/lib/kokkos/core/src/KokkosExp_MDRangePolicy.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,16 +49,16 @@ #include -#include +#include #include #include -#if defined( __CUDACC__ ) && defined( KOKKOS_ENABLE_CUDA ) -#include +#if defined(__CUDACC__) && defined(KOKKOS_ENABLE_CUDA) +#include #include #endif -#if defined( __HCC__ ) && defined( KOKKOS_ENABLE_ROCM ) +#if defined(__HCC__) && defined(KOKKOS_ENABLE_ROCM) //#include #include #endif @@ -76,583 +77,613 @@ enum class Iterate */ template -struct default_outer_direction -{ +struct default_outer_direction { using type = Iterate; - #if defined( KOKKOS_ENABLE_CUDA)||defined( KOKKOS_ENABLE_ROCM) +#if defined(KOKKOS_ENABLE_CUDA) || defined(KOKKOS_ENABLE_ROCM) static constexpr Iterate value = Iterate::Left; - #else +#else static constexpr Iterate value = Iterate::Right; - #endif +#endif }; template -struct default_inner_direction -{ +struct default_inner_direction { using type = Iterate; - #if defined( KOKKOS_ENABLE_CUDA)||defined( KOKKOS_ENABLE_ROCM) +#if defined(KOKKOS_ENABLE_CUDA) || defined(KOKKOS_ENABLE_ROCM) static constexpr Iterate value = Iterate::Left; - #else +#else static constexpr Iterate value = Iterate::Right; - #endif +#endif }; - // Iteration Pattern -template < unsigned N - , Iterate OuterDir = Iterate::Default - , Iterate InnerDir = Iterate::Default - > -struct Rank -{ - static_assert( N != 0u, "Kokkos Error: rank 0 undefined"); - static_assert( N != 1u, "Kokkos Error: rank 1 is not a multi-dimensional range"); - static_assert( N < 7u, "Kokkos Error: Unsupported rank..."); +template +struct Rank { + static_assert(N != 0u, "Kokkos Error: rank 0 undefined"); + static_assert(N != 1u, + "Kokkos Error: rank 1 is not a multi-dimensional range"); + static_assert(N < 7u, "Kokkos Error: Unsupported rank..."); using iteration_pattern = Rank; - static constexpr int rank = N; + static constexpr int rank = N; static constexpr Iterate outer_direction = OuterDir; static constexpr Iterate inner_direction = InnerDir; }; - // multi-dimensional iteration pattern template -struct MDRangePolicy - : public Kokkos::Impl::PolicyTraits -{ - using traits = Kokkos::Impl::PolicyTraits; +struct MDRangePolicy : public Kokkos::Impl::PolicyTraits { + using traits = Kokkos::Impl::PolicyTraits; using range_policy = RangePolicy; typename traits::execution_space m_space; - using impl_range_policy = RangePolicy< typename traits::execution_space - , typename traits::schedule_type - , typename traits::index_type - > ; + using impl_range_policy = + RangePolicy; - typedef MDRangePolicy execution_policy; // needed for is_execution_space interrogation + typedef MDRangePolicy + execution_policy; // needed for is_execution_space interrogation - template + template friend struct MDRangePolicy; - static_assert( !std::is_same::value - , "Kokkos Error: MD iteration pattern not defined" ); + static_assert(!std::is_same::value, + "Kokkos Error: MD iteration pattern not defined"); - using iteration_pattern = typename traits::iteration_pattern; - using work_tag = typename traits::work_tag; - using launch_bounds = typename traits::launch_bounds; - using member_type = typename range_policy::member_type; + using iteration_pattern = typename traits::iteration_pattern; + using work_tag = typename traits::work_tag; + using launch_bounds = typename traits::launch_bounds; + using member_type = typename range_policy::member_type; enum { rank = static_cast(iteration_pattern::rank) }; - using index_type = typename traits::index_type; + using index_type = typename traits::index_type; using array_index_type = long; - using point_type = Kokkos::Array; //was index_type - using tile_type = Kokkos::Array; - // If point_type or tile_type is not templated on a signed integral type (if it is unsigned), - // then if user passes in intializer_list of runtime-determined values of - // signed integral type that are not const will receive a compiler error due - // to an invalid case for implicit conversion - - // "conversion from integer or unscoped enumeration type to integer type that cannot represent all values of the original, except where source is a constant expression whose value can be stored exactly in the target type" + using point_type = Kokkos::Array; // was index_type + using tile_type = Kokkos::Array; + // If point_type or tile_type is not templated on a signed integral type (if + // it is unsigned), then if user passes in intializer_list of + // runtime-determined values of signed integral type that are not const will + // receive a compiler error due to an invalid case for implicit conversion - + // "conversion from integer or unscoped enumeration type to integer type that + // cannot represent all values of the original, except where source is a + // constant expression whose value can be stored exactly in the target type" // This would require the user to either pass a matching index_type parameter - // as template parameter to the MDRangePolicy or static_cast the individual values + // as template parameter to the MDRangePolicy or static_cast the individual + // values point_type m_lower; point_type m_upper; - tile_type m_tile; + tile_type m_tile; point_type m_tile_end; index_type m_num_tiles; index_type m_prod_tile_dims; -/* - // NDE enum impl definition alternative - replace static constexpr int ? - enum { outer_direction = static_cast ( - (iteration_pattern::outer_direction != Iterate::Default) - ? iteration_pattern::outer_direction - : default_outer_direction< typename traits::execution_space>::value ) }; + /* + // NDE enum impl definition alternative - replace static constexpr int ? + enum { outer_direction = static_cast ( + (iteration_pattern::outer_direction != Iterate::Default) + ? iteration_pattern::outer_direction + : default_outer_direction< typename traits::execution_space>::value ) }; - enum { inner_direction = static_cast ( - iteration_pattern::inner_direction != Iterate::Default - ? iteration_pattern::inner_direction - : default_inner_direction< typename traits::execution_space>::value ) }; + enum { inner_direction = static_cast ( + iteration_pattern::inner_direction != Iterate::Default + ? iteration_pattern::inner_direction + : default_inner_direction< typename traits::execution_space>::value ) }; - enum { Right = static_cast( Iterate::Right ) }; - enum { Left = static_cast( Iterate::Left ) }; -*/ - //static constexpr int rank = iteration_pattern::rank; + enum { Right = static_cast( Iterate::Right ) }; + enum { Left = static_cast( Iterate::Left ) }; + */ + // static constexpr int rank = iteration_pattern::rank; - static constexpr int outer_direction = static_cast ( + static constexpr int outer_direction = static_cast( (iteration_pattern::outer_direction != Iterate::Default) - ? iteration_pattern::outer_direction - : default_outer_direction< typename traits::execution_space>::value ); + ? iteration_pattern::outer_direction + : default_outer_direction::value); - static constexpr int inner_direction = static_cast ( + static constexpr int inner_direction = static_cast( iteration_pattern::inner_direction != Iterate::Default - ? iteration_pattern::inner_direction - : default_inner_direction< typename traits::execution_space>::value ) ; + ? iteration_pattern::inner_direction + : default_inner_direction::value); // Ugly ugly workaround intel 14 not handling scoped enum correctly - static constexpr int Right = static_cast( Iterate::Right ); - static constexpr int Left = static_cast( Iterate::Left ); + static constexpr int Right = static_cast(Iterate::Right); + static constexpr int Left = static_cast(Iterate::Left); - KOKKOS_INLINE_FUNCTION const typename traits::execution_space & space() const { return m_space ; } - template < typename LT , typename UT , typename TT = array_index_type > - MDRangePolicy(std::initializer_list const& lower, std::initializer_list const& upper, std::initializer_list const& tile = {} ) - : m_space() { + KOKKOS_INLINE_FUNCTION const typename traits::execution_space& space() const { + return m_space; + } + template + MDRangePolicy(std::initializer_list const& lower, + std::initializer_list const& upper, + std::initializer_list const& tile = {}) + : m_space() { init(lower, upper, tile); } - template < typename LT , typename UT , typename TT = array_index_type > - MDRangePolicy(const typename traits::execution_space & work_space, - std::initializer_list const& lower, std::initializer_list const& upper, std::initializer_list const& tile = {} ) - : m_space( work_space ) { + template + MDRangePolicy(const typename traits::execution_space& work_space, + std::initializer_list const& lower, + std::initializer_list const& upper, + std::initializer_list const& tile = {}) + : m_space(work_space) { init(lower, upper, tile); } - MDRangePolicy( point_type const& lower, point_type const& upper, tile_type const& tile = tile_type{} ) - : m_space() - , m_lower(lower) - , m_upper(upper) - , m_tile(tile) - , m_num_tiles(1) - , m_prod_tile_dims(1) { + MDRangePolicy(point_type const& lower, point_type const& upper, + tile_type const& tile = tile_type{}) + : m_space(), + m_lower(lower), + m_upper(upper), + m_tile(tile), + m_num_tiles(1), + m_prod_tile_dims(1) { init(); } - MDRangePolicy( const typename traits::execution_space & work_space, - point_type const& lower, point_type const& upper, tile_type const& tile = tile_type{} ) - : m_space( work_space ) - , m_lower(lower) - , m_upper(upper) - , m_tile(tile) - , m_num_tiles(1) - , m_prod_tile_dims(1) { + MDRangePolicy(const typename traits::execution_space& work_space, + point_type const& lower, point_type const& upper, + tile_type const& tile = tile_type{}) + : m_space(work_space), + m_lower(lower), + m_upper(upper), + m_tile(tile), + m_num_tiles(1), + m_prod_tile_dims(1) { init(); } - template - MDRangePolicy( const MDRangePolicy p ): - m_space(p.m_space), - m_lower(p.m_lower), - m_upper(p.m_upper), - m_tile(p.m_tile), - m_tile_end(p.m_tile_end), - m_num_tiles(p.m_num_tiles), - m_prod_tile_dims(p.m_prod_tile_dims) {} - -private: - + template + MDRangePolicy(const MDRangePolicy p) + : m_space(p.m_space), + m_lower(p.m_lower), + m_upper(p.m_upper), + m_tile(p.m_tile), + m_tile_end(p.m_tile_end), + m_num_tiles(p.m_num_tiles), + m_prod_tile_dims(p.m_prod_tile_dims) {} + + private: void init() { // Host - if ( true - #if defined(KOKKOS_ENABLE_CUDA) - && !std::is_same< typename traits::execution_space, Kokkos::Cuda >::value - #endif - #if defined(KOKKOS_ENABLE_ROCM) - && !std::is_same< typename traits::execution_space, Kokkos::Experimental::ROCm >::value - #endif - ) - { + if (true +#if defined(KOKKOS_ENABLE_CUDA) + && !std::is_same::value +#endif +#if defined(KOKKOS_ENABLE_ROCM) + && !std::is_same::value +#endif + ) { index_type span; - for (int i=0; i 0)) ) - { + if (m_tile[i] <= 0) { + if (((int)inner_direction == (int)Right && (i < rank - 1)) || + ((int)inner_direction == (int)Left && (i > 0))) { m_tile[i] = 2; - } - else { + } else { m_tile[i] = (span == 0 ? 1 : span); } } - m_tile_end[i] = static_cast((span + m_tile[i] - 1) / m_tile[i]); + m_tile_end[i] = + static_cast((span + m_tile[i] - 1) / m_tile[i]); m_num_tiles *= m_tile_end[i]; m_prod_tile_dims *= m_tile[i]; } } - #if defined(KOKKOS_ENABLE_CUDA) - else // Cuda +#if defined(KOKKOS_ENABLE_CUDA) + else // Cuda { index_type span; - int increment = 1; + int increment = 1; int rank_start = 0; - int rank_end = rank; - if((int)inner_direction == (int)Right) { - increment = -1; - rank_start = rank-1; - rank_end = -1; + int rank_end = rank; + if ((int)inner_direction == (int)Right) { + increment = -1; + rank_start = rank - 1; + rank_end = -1; } - for (int i=rank_start; i!=rank_end; i+=increment) { + for (int i = rank_start; i != rank_end; i += increment) { span = m_upper[i] - m_lower[i]; - if ( m_tile[i] <= 0 ) { + if (m_tile[i] <= 0) { // TODO: determine what is a good default tile size for cuda // may be rank dependent - if ( ((int)inner_direction == (int)Right && (i < rank-1)) - || ((int)inner_direction == (int)Left && (i > 0)) ) - { - if ( m_prod_tile_dims < 256 ) { + if (((int)inner_direction == (int)Right && (i < rank - 1)) || + ((int)inner_direction == (int)Left && (i > 0))) { + if (m_prod_tile_dims < 256) { m_tile[i] = 2; } else { m_tile[i] = 1; } - } - else { + } else { m_tile[i] = 16; } } - m_tile_end[i] = static_cast((span + m_tile[i] - 1) / m_tile[i]); + m_tile_end[i] = + static_cast((span + m_tile[i] - 1) / m_tile[i]); m_num_tiles *= m_tile_end[i]; m_prod_tile_dims *= m_tile[i]; } - if ( m_prod_tile_dims > 1024 ) { // Match Cuda restriction for ParallelReduce; 1024,1024,64 max per dim (Kepler), but product num_threads < 1024 + if (m_prod_tile_dims > + 1024) { // Match Cuda restriction for ParallelReduce; 1024,1024,64 + // max per dim (Kepler), but product num_threads < 1024 printf(" Tile dimensions exceed Cuda limits\n"); - Kokkos::abort(" Cuda ExecSpace Error: MDRange tile dims exceed maximum number of threads per block - choose smaller tile dims"); - //Kokkos::Impl::throw_runtime_exception( " Cuda ExecSpace Error: MDRange tile dims exceed maximum number of threads per block - choose smaller tile dims"); + Kokkos::abort( + " Cuda ExecSpace Error: MDRange tile dims exceed maximum number of " + "threads per block - choose smaller tile dims"); + // Kokkos::Impl::throw_runtime_exception( " Cuda ExecSpace Error: + // MDRange tile dims exceed maximum number of threads per block - choose + // smaller tile dims"); } } - #endif - #if defined(KOKKOS_ENABLE_ROCM) - else // ROCm +#endif +#if defined(KOKKOS_ENABLE_ROCM) + else // ROCm { index_type span; - int increment = 1; + int increment = 1; int rank_start = 0; - int rank_end = rank; - if((int)inner_direction == (int)Right) { - increment = -1; - rank_start = rank-1; - rank_end = -1; + int rank_end = rank; + if ((int)inner_direction == (int)Right) { + increment = -1; + rank_start = rank - 1; + rank_end = -1; } - for (int i=rank_start; i!=rank_end; i+=increment) { + for (int i = rank_start; i != rank_end; i += increment) { span = m_upper[i] - m_lower[i]; - if ( m_tile[i] <= 0 ) { + if (m_tile[i] <= 0) { // TODO: determine what is a good default tile size for rocm // may be rank dependent - if ( ((int)inner_direction == (int)Right && (i < rank-1)) - || ((int)inner_direction == (int)Left && (i > 0)) ) - { - if ( m_prod_tile_dims < 256 ) { + if (((int)inner_direction == (int)Right && (i < rank - 1)) || + ((int)inner_direction == (int)Left && (i > 0))) { + if (m_prod_tile_dims < 256) { m_tile[i] = 4; } else { m_tile[i] = 1; } - } - else { + } else { m_tile[i] = 16; } } - m_tile_end[i] = static_cast((span + m_tile[i] - 1) / m_tile[i]); + m_tile_end[i] = + static_cast((span + m_tile[i] - 1) / m_tile[i]); m_num_tiles *= m_tile_end[i]; m_prod_tile_dims *= m_tile[i]; } - if ( m_prod_tile_dims > 1024 ) { //but product num_threads < 1024 + if (m_prod_tile_dims > 1024) { // but product num_threads < 1024 printf(" Tile dimensions exceed ROCm limits\n"); - Kokkos::abort(" ROCm ExecSpace Error: MDRange tile dims exceed maximum number of threads per block - choose smaller tile dims"); - //Kokkos::Impl::throw_runtime_exception( " Cuda ExecSpace Error: MDRange tile dims exceed maximum number of threads per block - choose smaller tile dims"); + Kokkos::abort( + " ROCm ExecSpace Error: MDRange tile dims exceed maximum number of " + "threads per block - choose smaller tile dims"); + // Kokkos::Impl::throw_runtime_exception( " Cuda ExecSpace Error: + // MDRange tile dims exceed maximum number of threads per block - choose + // smaller tile dims"); } } - #endif +#endif } - template < typename LT , typename UT , typename TT = array_index_type > - void init( std::initializer_list const& lower, std::initializer_list const& upper, std::initializer_list const& tile = {} ) - { - if(static_cast(m_lower.size()) != rank || static_cast(m_upper.size()) != rank) - Kokkos::abort("MDRangePolicy: Constructor initializer lists have wrong size"); + template + void init(std::initializer_list const& lower, + std::initializer_list const& upper, + std::initializer_list const& tile = {}) { + if (static_cast(m_lower.size()) != rank || + static_cast(m_upper.size()) != rank) + Kokkos::abort( + "MDRangePolicy: Constructor initializer lists have wrong size"); - for ( auto i = 0; i < rank; ++i ) { + for (auto i = 0; i < rank; ++i) { m_lower[i] = static_cast(lower.begin()[i]); m_upper[i] = static_cast(upper.begin()[i]); - if(static_cast(tile.size())==rank) + if (static_cast(tile.size()) == rank) m_tile[i] = static_cast(tile.begin()[i]); else m_tile[i] = 0; } - m_num_tiles = 1; + m_num_tiles = 1; m_prod_tile_dims = 1; // Host - if ( true - #if defined(KOKKOS_ENABLE_CUDA) - && !std::is_same< typename traits::execution_space, Kokkos::Cuda >::value - #endif - #if defined(KOKKOS_ENABLE_ROCM) - && !std::is_same< typename traits::execution_space, Kokkos::Experimental::ROCm >::value - #endif - ) - { + if (true +#if defined(KOKKOS_ENABLE_CUDA) + && !std::is_same::value +#endif +#if defined(KOKKOS_ENABLE_ROCM) + && !std::is_same::value +#endif + ) { index_type span; - for (int i=0; i 0)) ) - { + if (m_tile[i] <= 0) { + if (((int)inner_direction == (int)Right && (i < rank - 1)) || + ((int)inner_direction == (int)Left && (i > 0))) { m_tile[i] = 2; - } - else { + } else { m_tile[i] = (span == 0 ? 1 : span); } } - m_tile_end[i] = static_cast((span + m_tile[i] - 1) / m_tile[i]); + m_tile_end[i] = + static_cast((span + m_tile[i] - 1) / m_tile[i]); m_num_tiles *= m_tile_end[i]; m_prod_tile_dims *= m_tile[i]; } } - #if defined(KOKKOS_ENABLE_CUDA) - else // Cuda +#if defined(KOKKOS_ENABLE_CUDA) + else // Cuda { index_type span; - int increment = 1; + int increment = 1; int rank_start = 0; - int rank_end = rank; - if((int)inner_direction == (int)Right) { - increment = -1; - rank_start = rank-1; - rank_end = -1; + int rank_end = rank; + if ((int)inner_direction == (int)Right) { + increment = -1; + rank_start = rank - 1; + rank_end = -1; } - for (int i=rank_start; i!=rank_end; i+=increment) { + for (int i = rank_start; i != rank_end; i += increment) { span = m_upper[i] - m_lower[i]; - if ( m_tile[i] <= 0 ) { + if (m_tile[i] <= 0) { // TODO: determine what is a good default tile size for cuda // may be rank dependent - if ( ((int)inner_direction == (int)Right && (i < rank-1)) - || ((int)inner_direction == (int)Left && (i > 0)) ) - { - if ( m_prod_tile_dims < 256 ) { + if (((int)inner_direction == (int)Right && (i < rank - 1)) || + ((int)inner_direction == (int)Left && (i > 0))) { + if (m_prod_tile_dims < 256) { m_tile[i] = 2; } else { m_tile[i] = 1; } - } - else { + } else { m_tile[i] = 16; } } - m_tile_end[i] = static_cast((span + m_tile[i] - 1) / m_tile[i]); + m_tile_end[i] = + static_cast((span + m_tile[i] - 1) / m_tile[i]); m_num_tiles *= m_tile_end[i]; m_prod_tile_dims *= m_tile[i]; } - if ( m_prod_tile_dims > 1024 ) { // Match Cuda restriction for ParallelReduce; 1024,1024,64 max per dim (Kepler), but product num_threads < 1024 + if (m_prod_tile_dims > + 1024) { // Match Cuda restriction for ParallelReduce; 1024,1024,64 + // max per dim (Kepler), but product num_threads < 1024 printf(" Tile dimensions exceed Cuda limits\n"); - Kokkos::abort(" Cuda ExecSpace Error: MDRange tile dims exceed maximum number of threads per block - choose smaller tile dims"); - //Kokkos::Impl::throw_runtime_exception( " Cuda ExecSpace Error: MDRange tile dims exceed maximum number of threads per block - choose smaller tile dims"); + Kokkos::abort( + " Cuda ExecSpace Error: MDRange tile dims exceed maximum number of " + "threads per block - choose smaller tile dims"); + // Kokkos::Impl::throw_runtime_exception( " Cuda ExecSpace Error: + // MDRange tile dims exceed maximum number of threads per block - choose + // smaller tile dims"); } } - #endif - #if defined(KOKKOS_ENABLE_ROCM) - else // ROCm +#endif +#if defined(KOKKOS_ENABLE_ROCM) + else // ROCm { index_type span; - int increment = 1; + int increment = 1; int rank_start = 0; - int rank_end = rank; - if((int)inner_direction == (int)Right) { - increment = -1; - rank_start = rank-1; - rank_end = -1; + int rank_end = rank; + if ((int)inner_direction == (int)Right) { + increment = -1; + rank_start = rank - 1; + rank_end = -1; } - for (int i=rank_start; i!=rank_end; i+=increment) { + for (int i = rank_start; i != rank_end; i += increment) { span = m_upper[i] - m_lower[i]; - if ( m_tile[i] <= 0 ) { + if (m_tile[i] <= 0) { // TODO: determine what is a good default tile size for cuda // may be rank dependent - if ( ((int)inner_direction == (int)Right && (i < rank-1)) - || ((int)inner_direction == (int)Left && (i > 0)) ) - { - if ( m_prod_tile_dims < 256 ) { + if (((int)inner_direction == (int)Right && (i < rank - 1)) || + ((int)inner_direction == (int)Left && (i > 0))) { + if (m_prod_tile_dims < 256) { m_tile[i] = 2; } else { m_tile[i] = 1; } - } - else { + } else { m_tile[i] = 16; } } - m_tile_end[i] = static_cast((span + m_tile[i] - 1) / m_tile[i]); + m_tile_end[i] = + static_cast((span + m_tile[i] - 1) / m_tile[i]); m_num_tiles *= m_tile_end[i]; m_prod_tile_dims *= m_tile[i]; } - if ( m_prod_tile_dims > 1024 ) { // Match ROCm restriction for ParallelReduce; 1024,1024,1024 max per dim , but product num_threads < 1024 + if (m_prod_tile_dims > + 1024) { // Match ROCm restriction for ParallelReduce; 1024,1024,1024 + // max per dim , but product num_threads < 1024 printf(" Tile dimensions exceed ROCm limits\n"); - Kokkos::abort(" ROCm ExecSpace Error: MDRange tile dims exceed maximum number of threads per block - choose smaller tile dims"); - //Kokkos::Impl::throw_runtime_exception( " Cuda ExecSpace Error: MDRange tile dims exceed maximum number of threads per block - choose smaller tile dims"); + Kokkos::abort( + " ROCm ExecSpace Error: MDRange tile dims exceed maximum number of " + "threads per block - choose smaller tile dims"); + // Kokkos::Impl::throw_runtime_exception( " Cuda ExecSpace Error: + // MDRange tile dims exceed maximum number of threads per block - choose + // smaller tile dims"); } } - #endif +#endif } - }; -} // namespace Kokkos +} // namespace Kokkos // For backward compatibility -namespace Kokkos { namespace Experimental { - using Kokkos::MDRangePolicy; - using Kokkos::Rank; - using Kokkos::Iterate; -} } // end Kokkos::Experimental +namespace Kokkos { +namespace Experimental { +using Kokkos::Iterate; +using Kokkos::MDRangePolicy; +using Kokkos::Rank; +} // namespace Experimental +} // namespace Kokkos // ------------------------------------------------------------------ // #ifdef KOKKOS_ENABLE_DEPRECATED_CODE // ------------------------------------------------------------------ // -//md_parallel_for - deprecated use parallel_for +// md_parallel_for - deprecated use parallel_for // ------------------------------------------------------------------ // -namespace Kokkos { namespace Experimental { +namespace Kokkos { +namespace Experimental { template -void md_parallel_for( MDRange const& range - , Functor const& f - , const std::string& str = "" - , typename std::enable_if<( true - #if defined( KOKKOS_ENABLE_CUDA) - && !std::is_same< typename MDRange::range_policy::execution_space, Kokkos::Cuda>::value - #endif - #if defined( KOKKOS_ENABLE_ROCM) - && !std::is_same< typename MDRange::range_policy::execution_space, Kokkos::Experimental::ROCm>::value - #endif - ) >::type* = 0 - ) -{ +void md_parallel_for( + MDRange const& range, Functor const& f, const std::string& str = "", + typename std::enable_if< + (true +#if defined(KOKKOS_ENABLE_CUDA) + && !std::is_same::value +#endif +#if defined(KOKKOS_ENABLE_ROCM) + && !std::is_same::value +#endif + )>::type* = 0) { Kokkos::Impl::Experimental::MDFunctor g(range, f); using range_policy = typename MDRange::impl_range_policy; - Kokkos::parallel_for( range_policy(0, range.m_num_tiles).set_chunk_size(1), g, str ); + Kokkos::parallel_for(range_policy(0, range.m_num_tiles).set_chunk_size(1), g, + str); } template -void md_parallel_for( const std::string& str - , MDRange const& range - , Functor const& f - , typename std::enable_if<( true - #if defined( KOKKOS_ENABLE_CUDA) - && !std::is_same< typename MDRange::range_policy::execution_space, Kokkos::Cuda>::value - #endif - #if defined( KOKKOS_ENABLE_ROCM) - && !std::is_same< typename MDRange::range_policy::execution_space, Kokkos::Experimental::ROCm>::value - #endif - ) >::type* = 0 - ) -{ +void md_parallel_for( + const std::string& str, MDRange const& range, Functor const& f, + typename std::enable_if< + (true +#if defined(KOKKOS_ENABLE_CUDA) + && !std::is_same::value +#endif +#if defined(KOKKOS_ENABLE_ROCM) + && !std::is_same::value +#endif + )>::type* = 0) { Kokkos::Impl::Experimental::MDFunctor g(range, f); using range_policy = typename MDRange::impl_range_policy; - Kokkos::parallel_for( range_policy(0, range.m_num_tiles).set_chunk_size(1), g, str ); + Kokkos::parallel_for(range_policy(0, range.m_num_tiles).set_chunk_size(1), g, + str); } // Cuda specialization -#if defined( __CUDACC__ ) && defined( KOKKOS_ENABLE_CUDA ) +#if defined(__CUDACC__) && defined(KOKKOS_ENABLE_CUDA) template -void md_parallel_for( const std::string& str - , MDRange const& range - , Functor const& f - , typename std::enable_if<( true - #if defined( KOKKOS_ENABLE_CUDA) - && std::is_same< typename MDRange::range_policy::execution_space, Kokkos::Cuda>::value - #endif - ) >::type* = 0 - ) -{ - Kokkos::Impl::DeviceIterateTile closure(range, f); +void md_parallel_for( + const std::string& str, MDRange const& range, Functor const& f, + typename std::enable_if< + (true +#if defined(KOKKOS_ENABLE_CUDA) + && std::is_same::value +#endif + )>::type* = 0) { + Kokkos::Impl::DeviceIterateTile + closure(range, f); closure.execute(); } template -void md_parallel_for( MDRange const& range - , Functor const& f - , const std::string& str = "" - , typename std::enable_if<( true - #if defined( KOKKOS_ENABLE_CUDA) - && std::is_same< typename MDRange::range_policy::execution_space, Kokkos::Cuda>::value - #endif - ) >::type* = 0 - ) -{ - Kokkos::Impl::DeviceIterateTile closure(range, f); +void md_parallel_for( + MDRange const& range, Functor const& f, const std::string& str = "", + typename std::enable_if< + (true +#if defined(KOKKOS_ENABLE_CUDA) + && std::is_same::value +#endif + )>::type* = 0) { + Kokkos::Impl::DeviceIterateTile + closure(range, f); closure.execute(); } #endif // ------------------------------------------------------------------ // // ------------------------------------------------------------------ // -//md_parallel_reduce - deprecated use parallel_reduce +// md_parallel_reduce - deprecated use parallel_reduce // ------------------------------------------------------------------ // template -void md_parallel_reduce( MDRange const& range - , Functor const& f - , ValueType & v - , const std::string& str = "" - , typename std::enable_if<( true - #if defined( KOKKOS_ENABLE_CUDA) - && !std::is_same< typename MDRange::range_policy::execution_space, Kokkos::Cuda>::value - #endif - #if defined( KOKKOS_ENABLE_ROCM) - && !std::is_same< typename MDRange::range_policy::execution_space, Kokkos::Experimental::ROCm>::value - #endif - ) >::type* = 0 - ) -{ - Kokkos::Impl::Experimental::MDFunctor g(range, f); +void md_parallel_reduce( + MDRange const& range, Functor const& f, ValueType& v, + const std::string& str = "", + typename std::enable_if< + (true +#if defined(KOKKOS_ENABLE_CUDA) + && !std::is_same::value +#endif +#if defined(KOKKOS_ENABLE_ROCM) + && !std::is_same::value +#endif + )>::type* = 0) { + Kokkos::Impl::Experimental::MDFunctor g(range, + f); using range_policy = typename MDRange::impl_range_policy; - Kokkos::parallel_reduce( str, range_policy(0, range.m_num_tiles).set_chunk_size(1), g, v ); + Kokkos::parallel_reduce( + str, range_policy(0, range.m_num_tiles).set_chunk_size(1), g, v); } template -void md_parallel_reduce( const std::string& str - , MDRange const& range - , Functor const& f - , ValueType & v - , typename std::enable_if<( true - #if defined( KOKKOS_ENABLE_CUDA) - && !std::is_same< typename MDRange::range_policy::execution_space, Kokkos::Cuda>::value - #endif - #if defined( KOKKOS_ENABLE_ROCM) - && !std::is_same< typename MDRange::range_policy::execution_space, Kokkos::Experimental::ROCm>::value - #endif - ) >::type* = 0 - ) -{ - Kokkos::Impl::Experimental::MDFunctor g(range, f); +void md_parallel_reduce( + const std::string& str, MDRange const& range, Functor const& f, + ValueType& v, + typename std::enable_if< + (true +#if defined(KOKKOS_ENABLE_CUDA) + && !std::is_same::value +#endif +#if defined(KOKKOS_ENABLE_ROCM) + && !std::is_same::value +#endif + )>::type* = 0) { + Kokkos::Impl::Experimental::MDFunctor g(range, + f); using range_policy = typename MDRange::impl_range_policy; - Kokkos::parallel_reduce( str, range_policy(0, range.m_num_tiles).set_chunk_size(1), g, v ); + Kokkos::parallel_reduce( + str, range_policy(0, range.m_num_tiles).set_chunk_size(1), g, v); } // Cuda - md_parallel_reduce not implemented - use parallel_reduce -} } // namespace Kokkos::Experimental +} // namespace Experimental +} // namespace Kokkos #endif namespace Kokkos { namespace Experimental { namespace Impl { -template -struct PolicyPropertyAdaptor,MDRangePolicy> { +template +struct PolicyPropertyAdaptor, + MDRangePolicy> { typedef MDRangePolicy policy_in_t; typedef MDRangePolicy> policy_out_t; + typename policy_in_t::traits::schedule_type, + typename policy_in_t::traits::work_tag, + typename policy_in_t::traits::index_type, + typename policy_in_t::traits::iteration_pattern, + typename policy_in_t::traits::launch_bounds, + WorkItemProperty::ImplWorkItemProperty

    > + policy_out_t; }; -} -} -} - - -#endif //KOKKOS_CORE_EXP_MD_RANGE_POLICY_HPP +} // namespace Impl +} // namespace Experimental +} // namespace Kokkos +#endif // KOKKOS_CORE_EXP_MD_RANGE_POLICY_HPP diff --git a/lib/kokkos/core/src/Kokkos_AnonymousSpace.hpp b/lib/kokkos/core/src/Kokkos_AnonymousSpace.hpp index c345158996..a4e887668f 100644 --- a/lib/kokkos/core/src/Kokkos_AnonymousSpace.hpp +++ b/lib/kokkos/core/src/Kokkos_AnonymousSpace.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -53,28 +54,28 @@ namespace Kokkos { class AnonymousSpace { -public: + public: //! Tag this class as a kokkos memory space - typedef AnonymousSpace memory_space; + typedef AnonymousSpace memory_space; typedef Kokkos::DefaultExecutionSpace execution_space; - typedef size_t size_type; + typedef size_t size_type; //! This memory space preferred device_type - typedef Kokkos::Device< execution_space, memory_space > device_type; + typedef Kokkos::Device device_type; /**\brief Default memory space instance */ - AnonymousSpace() = default; - AnonymousSpace( AnonymousSpace && rhs ) = default; - AnonymousSpace( const AnonymousSpace & rhs ) = default; - AnonymousSpace & operator = ( AnonymousSpace && ) = default; - AnonymousSpace & operator = ( const AnonymousSpace & ) = default; - ~AnonymousSpace() = default; + AnonymousSpace() = default; + AnonymousSpace(AnonymousSpace &&rhs) = default; + AnonymousSpace(const AnonymousSpace &rhs) = default; + AnonymousSpace &operator=(AnonymousSpace &&) = default; + AnonymousSpace &operator=(const AnonymousSpace &) = default; + ~AnonymousSpace() = default; /**\brief Return Name of the MemorySpace */ - static constexpr const char* name() { return "Anonymous"; } + static constexpr const char *name() { return "Anonymous"; } }; -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- @@ -82,46 +83,43 @@ namespace Kokkos { namespace Impl { -template -struct MemorySpaceAccess< Kokkos::AnonymousSpace , OtherSpace > { +template +struct MemorySpaceAccess { enum { assignable = true }; enum { accessible = true }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template -struct MemorySpaceAccess< OtherSpace, Kokkos::AnonymousSpace > { +template +struct MemorySpaceAccess { enum { assignable = true }; enum { accessible = true }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::AnonymousSpace, Kokkos::AnonymousSpace > { +template <> +struct MemorySpaceAccess { enum { assignable = true }; enum { accessible = true }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template -struct VerifyExecutionCanAccessMemorySpace -{ - enum {value = 1}; +template +struct VerifyExecutionCanAccessMemorySpace { + enum { value = 1 }; KOKKOS_INLINE_FUNCTION static void verify(void) {} KOKKOS_INLINE_FUNCTION static void verify(const void *) {} }; -template -struct VerifyExecutionCanAccessMemorySpace -{ - enum {value = 1}; +template +struct VerifyExecutionCanAccessMemorySpace { + enum { value = 1 }; KOKKOS_INLINE_FUNCTION static void verify(void) {} KOKKOS_INLINE_FUNCTION static void verify(const void *) {} }; -} // namespace Impl +} // namespace Impl -} // namespace Kokkos - -#endif // #define KOKKOS_ANONYMOUSSPACE_HPP +} // namespace Kokkos +#endif // #define KOKKOS_ANONYMOUSSPACE_HPP diff --git a/lib/kokkos/core/src/Kokkos_Array.hpp b/lib/kokkos/core/src/Kokkos_Array.hpp index 8e5862fe9c..88e7883cb9 100644 --- a/lib/kokkos/core/src/Kokkos_Array.hpp +++ b/lib/kokkos/core/src/Kokkos_Array.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -82,7 +83,7 @@ template struct ArrayBoundsCheck { KOKKOS_INLINE_FUNCTION ArrayBoundsCheck(Integral i, size_t N) { - if ( size_t(i) >= N) { + if (size_t(i) >= N) { #ifdef KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST std::string s = "Kokkos::Array: index "; s += std::to_string(i); @@ -95,7 +96,7 @@ struct ArrayBoundsCheck { } } }; -} // end namespace Impl +} // end namespace Impl #define KOKKOS_ARRAY_BOUNDS_CHECK(i, N) \ Kokkos::Impl::ArrayBoundsCheck(i, N) @@ -104,17 +105,14 @@ struct ArrayBoundsCheck { #define KOKKOS_ARRAY_BOUNDS_CHECK(i, N) (void)0 -#endif // !defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK ) +#endif // !defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK ) /**\brief Derived from the C++17 'std::array'. * Dropping the iterator interface. */ -template< class T = void - , size_t N =KOKKOS_INVALID_INDEX - , class Proxy = void - > +template struct Array { -public: + public: /** * The elements of this C array shall not be accessed directly. The data * member has to be declared public to enable aggregate initialization as for @@ -122,115 +120,113 @@ public: * @private */ T m_internal_implementation_private_member_data[N]; -public: - typedef T & reference ; - typedef typename std::add_const::type & const_reference ; - typedef size_t size_type ; - typedef ptrdiff_t difference_type ; - typedef T value_type ; - typedef T * pointer ; - typedef typename std::add_const::type * const_pointer ; - - KOKKOS_INLINE_FUNCTION static constexpr size_type size() { return N ; } - KOKKOS_INLINE_FUNCTION static constexpr bool empty(){ return false ; } - KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return N ; } - - template< typename iType > - KOKKOS_INLINE_FUNCTION - reference operator[]( const iType & i ) - { - static_assert( ( std::is_integral::value || std::is_enum::value ) , "Must be integral argument" ); - KOKKOS_ARRAY_BOUNDS_CHECK(i, N); - return m_internal_implementation_private_member_data[i]; - } + public: + typedef T& reference; + typedef typename std::add_const::type& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T* pointer; + typedef typename std::add_const::type* const_pointer; + + KOKKOS_INLINE_FUNCTION static constexpr size_type size() { return N; } + KOKKOS_INLINE_FUNCTION static constexpr bool empty() { return false; } + KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return N; } + + template + KOKKOS_INLINE_FUNCTION reference operator[](const iType& i) { + static_assert( + (std::is_integral::value || std::is_enum::value), + "Must be integral argument"); + KOKKOS_ARRAY_BOUNDS_CHECK(i, N); + return m_internal_implementation_private_member_data[i]; + } - template< typename iType > - KOKKOS_INLINE_FUNCTION - const_reference operator[]( const iType & i ) const - { - static_assert( ( std::is_integral::value || std::is_enum::value ) , "Must be integral argument" ); - KOKKOS_ARRAY_BOUNDS_CHECK(i, N); - return m_internal_implementation_private_member_data[i]; - } + template + KOKKOS_INLINE_FUNCTION const_reference operator[](const iType& i) const { + static_assert( + (std::is_integral::value || std::is_enum::value), + "Must be integral argument"); + KOKKOS_ARRAY_BOUNDS_CHECK(i, N); + return m_internal_implementation_private_member_data[i]; + } - KOKKOS_INLINE_FUNCTION pointer data() - { - return & m_internal_implementation_private_member_data[0]; - } - KOKKOS_INLINE_FUNCTION const_pointer data() const - { - return & m_internal_implementation_private_member_data[0]; - } + KOKKOS_INLINE_FUNCTION pointer data() { + return &m_internal_implementation_private_member_data[0]; + } + KOKKOS_INLINE_FUNCTION const_pointer data() const { + return &m_internal_implementation_private_member_data[0]; + } - #ifdef KOKKOS_IMPL_ROCM_CLANG_WORKAROUND +#ifdef KOKKOS_IMPL_ROCM_CLANG_WORKAROUND // Do not default unless move and move-assignment are also defined KOKKOS_INLINE_FUNCTION - ~Array() = default ; - Array() = default ; - Array( const Array & ) = default ; - Array & operator = ( const Array & ) = default ; + ~Array() = default; + Array() = default; + Array(const Array&) = default; + Array& operator=(const Array&) = default; // Some supported compilers are not sufficiently C++11 compliant // for default move constructor and move assignment operator. - Array( Array && ) = default ; - Array & operator = ( Array && ) = default ; - + Array(Array&&) = default; + Array& operator=(Array&&) = default; + KOKKOS_INLINE_FUNCTION Array(const std::initializer_list& vals) { - for(int i=0; i +struct Array { + public: + typedef T& reference; + typedef typename std::add_const::type& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T* pointer; + typedef typename std::add_const::type* const_pointer; + + KOKKOS_INLINE_FUNCTION static constexpr size_type size() { return 0; } + KOKKOS_INLINE_FUNCTION static constexpr bool empty() { return true; } + KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return 0; } + + template + KOKKOS_INLINE_FUNCTION reference operator[](const iType&) { + static_assert( + (std::is_integral::value || std::is_enum::value), + "Must be integer argument"); + Kokkos::abort("Unreachable code"); + return *reinterpret_cast(-1); + } -template< class T , class Proxy > -struct Array { -public: - - typedef typename std::add_const::type & reference ; - typedef typename std::add_const::type & const_reference ; - typedef size_t size_type ; - typedef ptrdiff_t difference_type ; - typedef typename std::add_const::type value_type ; - typedef typename std::add_const::type * pointer ; - typedef typename std::add_const::type * const_pointer ; - - KOKKOS_INLINE_FUNCTION static constexpr size_type size() { return 0 ; } - KOKKOS_INLINE_FUNCTION static constexpr bool empty() { return true ; } - KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return 0 ; } - - template< typename iType > - KOKKOS_INLINE_FUNCTION - value_type operator[]( const iType & ) - { - static_assert( ( std::is_integral::value || std::is_enum::value ) , "Must be integer argument" ); - return value_type(); - } - - template< typename iType > - KOKKOS_INLINE_FUNCTION - value_type operator[]( const iType & ) const - { - static_assert( ( std::is_integral::value || std::is_enum::value ) , "Must be integer argument" ); - return value_type(); - } + template + KOKKOS_INLINE_FUNCTION const_reference operator[](const iType&) const { + static_assert( + (std::is_integral::value || std::is_enum::value), + "Must be integer argument"); + Kokkos::abort("Unreachable code"); + return *reinterpret_cast(-1); + } - KOKKOS_INLINE_FUNCTION pointer data() { return pointer(0) ; } + KOKKOS_INLINE_FUNCTION pointer data() { return pointer(0); } KOKKOS_INLINE_FUNCTION const_pointer data() const { return const_pointer(0); } #ifdef KOKKOS_CUDA_9_DEFAULTED_BUG_WORKAROUND KOKKOS_INLINE_FUNCTION ~Array() {} KOKKOS_INLINE_FUNCTION Array() {} - KOKKOS_INLINE_FUNCTION Array( const Array & ) {} - KOKKOS_INLINE_FUNCTION Array & operator = ( const Array & ) {} + KOKKOS_INLINE_FUNCTION Array(const Array&) {} + KOKKOS_INLINE_FUNCTION Array& operator=(const Array&) {} #else - KOKKOS_INLINE_FUNCTION ~Array() = default; - KOKKOS_INLINE_FUNCTION Array() = default; - KOKKOS_INLINE_FUNCTION Array( const Array & ) = default; - KOKKOS_INLINE_FUNCTION Array & operator = ( const Array & ) = default; + KOKKOS_INLINE_FUNCTION ~Array() = default; + KOKKOS_INLINE_FUNCTION Array() = default; + KOKKOS_INLINE_FUNCTION Array(const Array&) = default; + KOKKOS_INLINE_FUNCTION Array& operator=(const Array&) = default; #endif // Some supported compilers are not sufficiently C++11 compliant @@ -239,62 +235,59 @@ public: // Array & operator = ( Array && ) = default ; }; - -template<> -struct Array -{ +template <> +struct Array { struct contiguous {}; struct strided {}; }; -template< class T > -struct Array< T ,KOKKOS_INVALID_INDEX , Array<>::contiguous > -{ -private: - T * m_elem ; - size_t m_size ; -public: - - typedef T & reference ; - typedef typename std::add_const::type & const_reference ; - typedef size_t size_type ; - typedef ptrdiff_t difference_type ; - typedef T value_type ; - typedef T * pointer ; - typedef typename std::add_const::type * const_pointer ; - - KOKKOS_INLINE_FUNCTION constexpr size_type size() const { return m_size ; } - KOKKOS_INLINE_FUNCTION constexpr bool empty() const { return 0 != m_size ; } - KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return m_size ; } - - template< typename iType > - KOKKOS_INLINE_FUNCTION - reference operator[]( const iType & i ) - { - static_assert( ( std::is_integral::value || std::is_enum::value ) , "Must be integral argument" ); - KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size); - return m_elem[i]; - } +template +struct Array::contiguous> { + private: + T* m_elem; + size_t m_size; + + public: + typedef T& reference; + typedef typename std::add_const::type& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T* pointer; + typedef typename std::add_const::type* const_pointer; + + KOKKOS_INLINE_FUNCTION constexpr size_type size() const { return m_size; } + KOKKOS_INLINE_FUNCTION constexpr bool empty() const { return 0 != m_size; } + KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return m_size; } + + template + KOKKOS_INLINE_FUNCTION reference operator[](const iType& i) { + static_assert( + (std::is_integral::value || std::is_enum::value), + "Must be integral argument"); + KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size); + return m_elem[i]; + } - template< typename iType > - KOKKOS_INLINE_FUNCTION - const_reference operator[]( const iType & i ) const - { - static_assert( ( std::is_integral::value || std::is_enum::value ) , "Must be integral argument" ); - KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size); - return m_elem[i]; - } + template + KOKKOS_INLINE_FUNCTION const_reference operator[](const iType& i) const { + static_assert( + (std::is_integral::value || std::is_enum::value), + "Must be integral argument"); + KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size); + return m_elem[i]; + } - KOKKOS_INLINE_FUNCTION pointer data() { return m_elem ; } - KOKKOS_INLINE_FUNCTION const_pointer data() const { return m_elem ; } + KOKKOS_INLINE_FUNCTION pointer data() { return m_elem; } + KOKKOS_INLINE_FUNCTION const_pointer data() const { return m_elem; } #ifdef KOKKOS_CUDA_9_DEFAULTED_BUG_WORKAROUND KOKKOS_INLINE_FUNCTION ~Array() {} #else - KOKKOS_INLINE_FUNCTION ~Array() = default; + KOKKOS_INLINE_FUNCTION ~Array() = default; #endif - Array() = delete ; - Array( const Array & rhs ) = delete ; + Array() = delete; + Array(const Array& rhs) = delete; // Some supported compilers are not sufficiently C++11 compliant // for default move constructor and move assignment operator. @@ -302,76 +295,72 @@ public: // Array & operator = ( Array && rhs ) = delete ; KOKKOS_INLINE_FUNCTION - Array & operator = ( const Array & rhs ) - { - const size_t n = std::min( m_size , rhs.size() ); - for ( size_t i = 0 ; i < n ; ++i ) m_elem[i] = rhs[i] ; - return *this ; - } + Array& operator=(const Array& rhs) { + const size_t n = std::min(m_size, rhs.size()); + for (size_t i = 0; i < n; ++i) m_elem[i] = rhs[i]; + return *this; + } - template< size_t N , class P > - KOKKOS_INLINE_FUNCTION - Array & operator = ( const Array & rhs ) - { - const size_t n = std::min( m_size , rhs.size() ); - for ( size_t i = 0 ; i < n ; ++i ) m_elem[i] = rhs[i] ; - return *this ; - } + template + KOKKOS_INLINE_FUNCTION Array& operator=(const Array& rhs) { + const size_t n = std::min(m_size, rhs.size()); + for (size_t i = 0; i < n; ++i) m_elem[i] = rhs[i]; + return *this; + } - KOKKOS_INLINE_FUNCTION constexpr Array( pointer arg_ptr , size_type arg_size , size_type = 0 ) - : m_elem(arg_ptr), m_size(arg_size) {} + KOKKOS_INLINE_FUNCTION constexpr Array(pointer arg_ptr, size_type arg_size, + size_type = 0) + : m_elem(arg_ptr), m_size(arg_size) {} }; -template< class T > -struct Array< T ,KOKKOS_INVALID_INDEX , Array<>::strided > -{ -private: - T * m_elem ; - size_t m_size ; - size_t m_stride ; -public: - - typedef T & reference ; - typedef typename std::add_const::type & const_reference ; - typedef size_t size_type ; - typedef ptrdiff_t difference_type ; - typedef T value_type ; - typedef T * pointer ; - typedef typename std::add_const::type * const_pointer ; - - KOKKOS_INLINE_FUNCTION constexpr size_type size() const { return m_size ; } - KOKKOS_INLINE_FUNCTION constexpr bool empty() const { return 0 != m_size ; } - KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return m_size ; } - - template< typename iType > - KOKKOS_INLINE_FUNCTION - reference operator[]( const iType & i ) - { - static_assert( ( std::is_integral::value || std::is_enum::value ) , "Must be integral argument" ); - KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size); - return m_elem[i*m_stride]; - } +template +struct Array::strided> { + private: + T* m_elem; + size_t m_size; + size_t m_stride; + + public: + typedef T& reference; + typedef typename std::add_const::type& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T* pointer; + typedef typename std::add_const::type* const_pointer; + + KOKKOS_INLINE_FUNCTION constexpr size_type size() const { return m_size; } + KOKKOS_INLINE_FUNCTION constexpr bool empty() const { return 0 != m_size; } + KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return m_size; } + + template + KOKKOS_INLINE_FUNCTION reference operator[](const iType& i) { + static_assert( + (std::is_integral::value || std::is_enum::value), + "Must be integral argument"); + KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size); + return m_elem[i * m_stride]; + } - template< typename iType > - KOKKOS_INLINE_FUNCTION - const_reference operator[]( const iType & i ) const - { - static_assert( ( std::is_integral::value || std::is_enum::value ) , "Must be integral argument" ); - KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size); - return m_elem[i*m_stride]; - } + template + KOKKOS_INLINE_FUNCTION const_reference operator[](const iType& i) const { + static_assert( + (std::is_integral::value || std::is_enum::value), + "Must be integral argument"); + KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size); + return m_elem[i * m_stride]; + } - KOKKOS_INLINE_FUNCTION pointer data() { return m_elem ; } - KOKKOS_INLINE_FUNCTION const_pointer data() const { return m_elem ; } + KOKKOS_INLINE_FUNCTION pointer data() { return m_elem; } + KOKKOS_INLINE_FUNCTION const_pointer data() const { return m_elem; } #ifdef KOKKOS_CUDA_9_DEFAULTED_BUG_WORKAROUND KOKKOS_INLINE_FUNCTION ~Array() {} #else - KOKKOS_INLINE_FUNCTION ~Array() = default; + KOKKOS_INLINE_FUNCTION ~Array() = default; #endif - Array() = delete ; - Array( const Array & ) = delete ; - + Array() = delete; + Array(const Array&) = delete; // Some supported compilers are not sufficiently C++11 compliant // for default move constructor and move assignment operator. @@ -379,27 +368,24 @@ public: // Array & operator = ( Array && rhs ) = delete ; KOKKOS_INLINE_FUNCTION - Array & operator = ( const Array & rhs ) - { - const size_t n = std::min( m_size , rhs.size() ); - for ( size_t i = 0 ; i < n ; ++i ) m_elem[i] = rhs[i] ; - return *this ; - } + Array& operator=(const Array& rhs) { + const size_t n = std::min(m_size, rhs.size()); + for (size_t i = 0; i < n; ++i) m_elem[i] = rhs[i]; + return *this; + } - template< size_t N , class P > - KOKKOS_INLINE_FUNCTION - Array & operator = ( const Array & rhs ) - { - const size_t n = std::min( m_size , rhs.size() ); - for ( size_t i = 0 ; i < n ; ++i ) m_elem[i] = rhs[i] ; - return *this ; - } + template + KOKKOS_INLINE_FUNCTION Array& operator=(const Array& rhs) { + const size_t n = std::min(m_size, rhs.size()); + for (size_t i = 0; i < n; ++i) m_elem[i] = rhs[i]; + return *this; + } - KOKKOS_INLINE_FUNCTION constexpr Array( pointer arg_ptr , size_type arg_size , size_type arg_stride ) - : m_elem(arg_ptr), m_size(arg_size), m_stride(arg_stride) {} + KOKKOS_INLINE_FUNCTION constexpr Array(pointer arg_ptr, size_type arg_size, + size_type arg_stride) + : m_elem(arg_ptr), m_size(arg_size), m_stride(arg_stride) {} }; -} // namespace Kokkos +} // namespace Kokkos #endif /* #ifndef KOKKOS_ARRAY_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_Atomic.hpp b/lib/kokkos/core/src/Kokkos_Atomic.hpp index c2268bd35f..c4f7fa3ec1 100644 --- a/lib/kokkos/core/src/Kokkos_Atomic.hpp +++ b/lib/kokkos/core/src/Kokkos_Atomic.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -75,7 +76,7 @@ #if defined(_WIN32) #define KOKKOS_ENABLE_WINDOWS_ATOMICS #else -#if defined( KOKKOS_ENABLE_CUDA ) +#if defined(KOKKOS_ENABLE_CUDA) // Compiling NVIDIA device code, must use Cuda atomics: @@ -87,32 +88,30 @@ #endif -#if ! defined( KOKKOS_ENABLE_GNU_ATOMICS ) && \ - ! defined( KOKKOS_ENABLE_INTEL_ATOMICS ) && \ - ! defined( KOKKOS_ENABLE_OPENMP_ATOMICS ) && \ - ! defined( KOKKOS_ENABLE_STD_ATOMICS ) && \ - ! defined( KOKKOS_ENABLE_SERIAL_ATOMICS ) +#if !defined(KOKKOS_ENABLE_GNU_ATOMICS) && \ + !defined(KOKKOS_ENABLE_INTEL_ATOMICS) && \ + !defined(KOKKOS_ENABLE_OPENMP_ATOMICS) && \ + !defined(KOKKOS_ENABLE_STD_ATOMICS) && \ + !defined(KOKKOS_ENABLE_SERIAL_ATOMICS) // Compiling for non-Cuda atomic implementation has not been pre-selected. // Choose the best implementation for the detected compiler. // Preference: GCC, INTEL, OMP31 -#if defined( KOKKOS_INTERNAL_NOT_PARALLEL ) +#if defined(KOKKOS_INTERNAL_NOT_PARALLEL) #define KOKKOS_ENABLE_SERIAL_ATOMICS -#elif defined( KOKKOS_COMPILER_GNU ) || \ - defined( KOKKOS_COMPILER_CLANG ) || \ - ( defined ( KOKKOS_COMPILER_NVCC ) ) +#elif defined(KOKKOS_COMPILER_GNU) || defined(KOKKOS_COMPILER_CLANG) || \ + (defined(KOKKOS_COMPILER_NVCC)) #define KOKKOS_ENABLE_GNU_ATOMICS -#elif defined( KOKKOS_COMPILER_INTEL ) || \ - defined( KOKKOS_COMPILER_CRAYC ) +#elif defined(KOKKOS_COMPILER_INTEL) || defined(KOKKOS_COMPILER_CRAYC) #define KOKKOS_ENABLE_INTEL_ATOMICS -#elif defined( _OPENMP ) && ( 201107 <= _OPENMP ) +#elif defined(_OPENMP) && (201107 <= _OPENMP) #define KOKKOS_ENABLE_OPENMP_ATOMICS @@ -131,43 +130,37 @@ namespace Kokkos { template -KOKKOS_INLINE_FUNCTION -void atomic_add(volatile T * const dest, const T src); +KOKKOS_INLINE_FUNCTION void atomic_add(volatile T* const dest, const T src); // Atomic increment -template -KOKKOS_INLINE_FUNCTION -void atomic_increment(volatile T* a); +template +KOKKOS_INLINE_FUNCTION void atomic_increment(volatile T* a); -template -KOKKOS_INLINE_FUNCTION -void atomic_decrement(volatile T* a); -} +template +KOKKOS_INLINE_FUNCTION void atomic_decrement(volatile T* a); +} // namespace Kokkos namespace Kokkos { - -inline -const char * atomic_query_version() -{ -#if defined( KOKKOS_ENABLE_CUDA_ATOMICS ) - return "KOKKOS_ENABLE_CUDA_ATOMICS" ; -#elif defined( KOKKOS_ENABLE_GNU_ATOMICS ) - return "KOKKOS_ENABLE_GNU_ATOMICS" ; -#elif defined( KOKKOS_ENABLE_INTEL_ATOMICS ) - return "KOKKOS_ENABLE_INTEL_ATOMICS" ; -#elif defined( KOKKOS_ENABLE_OPENMP_ATOMICS ) - return "KOKKOS_ENABLE_OPENMP_ATOMICS" ; -#elif defined( KOKKOS_ENABLE_WINDOWS_ATOMICS ) +inline const char* atomic_query_version() { +#if defined(KOKKOS_ENABLE_CUDA_ATOMICS) + return "KOKKOS_ENABLE_CUDA_ATOMICS"; +#elif defined(KOKKOS_ENABLE_GNU_ATOMICS) + return "KOKKOS_ENABLE_GNU_ATOMICS"; +#elif defined(KOKKOS_ENABLE_INTEL_ATOMICS) + return "KOKKOS_ENABLE_INTEL_ATOMICS"; +#elif defined(KOKKOS_ENABLE_OPENMP_ATOMICS) + return "KOKKOS_ENABLE_OPENMP_ATOMICS"; +#elif defined(KOKKOS_ENABLE_WINDOWS_ATOMICS) return "KOKKOS_ENABLE_WINDOWS_ATOMICS"; -#elif defined( KOKKOS_ENABLE_SERIAL_ATOMICS ) +#elif defined(KOKKOS_ENABLE_SERIAL_ATOMICS) return "KOKKOS_ENABLE_SERIAL_ATOMICS"; #else #error "No valid response for atomic_query_version!" #endif } -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- // Atomic Memory Orders @@ -175,16 +168,14 @@ const char * atomic_query_version() // Implements Strongly-typed analogs of C++ standard memory orders #include "impl/Kokkos_Atomic_Memory_Order.hpp" -#if defined( KOKKOS_ENABLE_ROCM ) +#if defined(KOKKOS_ENABLE_ROCM) namespace Kokkos { namespace Impl { -extern KOKKOS_INLINE_FUNCTION -bool lock_address_rocm_space(void* ptr); +extern KOKKOS_INLINE_FUNCTION bool lock_address_rocm_space(void* ptr); -extern KOKKOS_INLINE_FUNCTION -void unlock_address_rocm_space(void* ptr); -} -} +extern KOKKOS_INLINE_FUNCTION void unlock_address_rocm_space(void* ptr); +} // namespace Impl +} // namespace Kokkos #include #endif @@ -212,8 +203,9 @@ void unlock_address_rocm_space(void* ptr); // Atomic compare-and-exchange // // template -// bool atomic_compare_exchange_strong(volatile T* const dest, const T compare, const T val) -// { bool equal = compare == *dest ; if ( equal ) { *dest = val ; } return equal ; } +// bool atomic_compare_exchange_strong(volatile T* const dest, const T compare, +// const T val) { bool equal = compare == *dest ; if ( equal ) { *dest = val ; } +// return equal ; } #include "impl/Kokkos_Atomic_Compare_Exchange_Strong.hpp" @@ -275,7 +267,8 @@ void unlock_address_rocm_space(void* ptr); //---------------------------------------------------------------------------- // Memory fence // -// All loads and stores from this thread will be globally consistent before continuing +// All loads and stores from this thread will be globally consistent before +// continuing // // void memory_fence() {...}; #include "impl/Kokkos_Memory_Fence.hpp" @@ -301,23 +294,22 @@ void unlock_address_rocm_space(void* ptr); #include "impl/Kokkos_Atomic_Load.hpp" #include "impl/Kokkos_Atomic_Store.hpp" - //---------------------------------------------------------------------------- // This atomic-style macro should be an inlined function, not a macro -#if defined( KOKKOS_COMPILER_GNU ) && !defined(__PGIC__) && !defined(__CUDA_ARCH__) +#if defined(KOKKOS_COMPILER_GNU) && !defined(__PGIC__) && \ + !defined(__CUDA_ARCH__) - #define KOKKOS_NONTEMPORAL_PREFETCH_LOAD(addr) __builtin_prefetch(addr,0,0) - #define KOKKOS_NONTEMPORAL_PREFETCH_STORE(addr) __builtin_prefetch(addr,1,0) +#define KOKKOS_NONTEMPORAL_PREFETCH_LOAD(addr) __builtin_prefetch(addr, 0, 0) +#define KOKKOS_NONTEMPORAL_PREFETCH_STORE(addr) __builtin_prefetch(addr, 1, 0) #else - #define KOKKOS_NONTEMPORAL_PREFETCH_LOAD(addr) ((void)0) - #define KOKKOS_NONTEMPORAL_PREFETCH_STORE(addr) ((void)0) +#define KOKKOS_NONTEMPORAL_PREFETCH_LOAD(addr) ((void)0) +#define KOKKOS_NONTEMPORAL_PREFETCH_STORE(addr) ((void)0) #endif //---------------------------------------------------------------------------- #endif /* KOKKOS_ATOMIC_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_Complex.hpp b/lib/kokkos/core/src/Kokkos_Complex.hpp index a3ada5d55e..a9af073b41 100644 --- a/lib/kokkos/core/src/Kokkos_Complex.hpp +++ b/lib/kokkos/core/src/Kokkos_Complex.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -57,658 +58,683 @@ namespace Kokkos { /// complex number. As with std::complex, this is only defined for /// \c float, \c double, and long double. The latter is /// currently forbidden in CUDA device kernels. -template -class complex { -private: - RealType re_, im_; +template +class +#ifdef KOKKOS_ENABLE_COMPLEX_ALIGN + alignas(2 * sizeof(RealType)) +#endif + complex { + private: + RealType re_{}; + RealType im_{}; -public: + public: //! The type of the real or imaginary parts of this complex number. - typedef RealType value_type; + using value_type = RealType; //! Default constructor (initializes both real and imaginary parts to zero). - KOKKOS_INLINE_FUNCTION complex () : - re_ (0.0), im_ (0.0) - {} + KOKKOS_INLINE_FUNCTION + complex() noexcept = default; //! Copy constructor. - KOKKOS_INLINE_FUNCTION complex (const complex& src) : - re_ (src.re_), im_ (src.im_) - {} + KOKKOS_INLINE_FUNCTION + complex(const complex&) noexcept = default; - //! Copy constructor from volatile. - KOKKOS_INLINE_FUNCTION complex (const volatile complex& src) : - re_ (src.re_), im_ (src.im_) - {} + KOKKOS_INLINE_FUNCTION + complex& operator=(const complex&) noexcept = default; + + /// \brief Conversion constructor from compatible RType + template ::value, + int>::type = 0> + KOKKOS_INLINE_FUNCTION complex(const complex& other) noexcept + // Intentionally do the conversions implicitly here so that users don't + // get any warnings about narrowing, etc., that they would expect to get + // otherwise. + : re_(other.real()), im_(other.imag()) {} /// \brief Conversion constructor from std::complex. /// /// This constructor cannot be called in a CUDA device function, /// because std::complex's methods and nonmember functions are not /// marked as CUDA device functions. - template - complex (const std::complex& src) : - re_ (std::real (src)), im_ (std::imag (src)) - {} + KOKKOS_INLINE_FUNCTION + complex(const std::complex& src) noexcept + // We can use this aspect of the standard to avoid calling + // non-device-marked functions `std::real` and `std::imag`: "For any + // object z of type complex, reinterpret_cast(z)[0] is the + // real part of z and reinterpret_cast(z)[1] is the imaginary + // part of z." Now we don't have to provide a whole bunch of the overloads + // of things taking either Kokkos::complex or std::complex + : re_(reinterpret_cast(src)[0]), + im_(reinterpret_cast(src)[1]) {} /// \brief Conversion operator to std::complex. /// /// This operator cannot be called in a CUDA device function, /// because std::complex's methods and nonmember functions are not /// marked as CUDA device functions. - operator std::complex () const { - return std::complex (re_, im_); + // TODO: make explicit. DJS 2019-08-28 + operator std::complex() const noexcept { + return std::complex(re_, im_); } /// \brief Constructor that takes just the real part, and sets the /// imaginary part to zero. - template - KOKKOS_INLINE_FUNCTION complex (const InputRealType& val) : - re_ (val), im_ (static_cast(0.0)) - {} - - // BUG HCC WORKAROUND - KOKKOS_INLINE_FUNCTION complex( const RealType& re, const RealType& im): - re_ (re), im_ (im) - {} - - //! Constructor that takes the real and imaginary parts. - template - KOKKOS_INLINE_FUNCTION complex (const RealType1& re, const RealType2& im) : - re_ (re), im_ (im) - {} + KOKKOS_INLINE_FUNCTION complex(const RealType& val) noexcept + : re_(val), im_(static_cast(0)) {} - //! Assignment operator. - template - KOKKOS_INLINE_FUNCTION - complex& operator= (const complex& src) { - re_ = src.re_; - im_ = src.im_; - return *this; - } - - /// \brief Assignment operator, for volatile *this and - /// nonvolatile input. - /// - /// \param src [in] Input; right-hand side of the assignment. - /// - /// This operator returns \c void instead of volatile - /// complex& . See Kokkos Issue #177 for the - /// explanation. In practice, this means that you should not chain - /// assignments with volatile lvalues. - template - KOKKOS_INLINE_FUNCTION - void operator= (const complex& src) volatile { - re_ = src.re_; - im_ = src.im_; - // We deliberately do not return anything here. See explanation - // in public documentation above. - } - - //! Assignment operator. - template - KOKKOS_INLINE_FUNCTION - volatile complex& operator= (const volatile complex& src) volatile { - re_ = src.re_; - im_ = src.im_; - return *this; - } - - //! Assignment operator. - template + //! Constructor that takes the real and imaginary parts. KOKKOS_INLINE_FUNCTION - complex& operator= (const volatile complex& src) { - re_ = src.re_; - im_ = src.im_; - return *this; - } + complex(const RealType& re, const RealType& im) noexcept : re_(re), im_(im) {} //! Assignment operator (from a real number). - template - KOKKOS_INLINE_FUNCTION - complex& operator= (const InputRealType& val) { + KOKKOS_INLINE_FUNCTION complex& operator=(const RealType& val) noexcept { re_ = val; - im_ = static_cast (0.0); + im_ = RealType(0); return *this; } - //! Assignment operator (from a real number). - template - KOKKOS_INLINE_FUNCTION - void operator= (const InputRealType& val) volatile { - re_ = val; - im_ = static_cast (0.0); - } - /// \brief Assignment operator from std::complex. /// /// This constructor cannot be called in a CUDA device function, /// because std::complex's methods and nonmember functions are not /// marked as CUDA device functions. - template - complex& operator= (const std::complex& src) { - re_ = std::real (src); - im_ = std::imag (src); + complex& operator=(const std::complex& src) noexcept { + *this = complex(src); return *this; } //! The imaginary part of this complex number. - KOKKOS_INLINE_FUNCTION RealType& imag () { - return im_; - } + KOKKOS_INLINE_FUNCTION + KOKKOS_CONSTEXPR_14 RealType& imag() noexcept { return im_; } //! The real part of this complex number. - KOKKOS_INLINE_FUNCTION RealType& real () { - return re_; - } + KOKKOS_INLINE_FUNCTION + KOKKOS_CONSTEXPR_14 RealType& real() noexcept { return re_; } //! The imaginary part of this complex number. - KOKKOS_INLINE_FUNCTION const RealType imag () const { - return im_; - } + KOKKOS_INLINE_FUNCTION + constexpr RealType imag() const noexcept { return im_; } //! The real part of this complex number. - KOKKOS_INLINE_FUNCTION const RealType real () const { - return re_; - } - - //! The imaginary part of this complex number (volatile overload). - KOKKOS_INLINE_FUNCTION volatile RealType& imag () volatile { - return im_; - } - - //! The real part of this complex number (volatile overload). - KOKKOS_INLINE_FUNCTION volatile RealType& real () volatile { - return re_; - } - - //! The imaginary part of this complex number (volatile overload). - KOKKOS_INLINE_FUNCTION const RealType imag () const volatile { - return im_; - } - - //! The real part of this complex number (volatile overload). - KOKKOS_INLINE_FUNCTION const RealType real () const volatile { - return re_; - } + KOKKOS_INLINE_FUNCTION + constexpr RealType real() const noexcept { return re_; } //! Set the imaginary part of this complex number. - KOKKOS_INLINE_FUNCTION void imag (RealType v) { - im_ = v; - } + KOKKOS_INLINE_FUNCTION + KOKKOS_CONSTEXPR_14 + void imag(RealType v) noexcept { im_ = v; } //! Set the real part of this complex number. - KOKKOS_INLINE_FUNCTION void real (RealType v) { - re_ = v; - } - - template KOKKOS_INLINE_FUNCTION - complex& - operator += (const complex& src) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); - re_ += src.re_; - im_ += src.im_; - return *this; - } + KOKKOS_CONSTEXPR_14 + void real(RealType v) noexcept { re_ = v; } - template - KOKKOS_INLINE_FUNCTION - void - operator += (const volatile complex& src) volatile { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); + KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator+=( + const complex& src) noexcept { re_ += src.re_; im_ += src.im_; - } - - KOKKOS_INLINE_FUNCTION - complex& - operator += (const std::complex& src) { - re_ += src.real(); - im_ += src.imag(); return *this; } - template - KOKKOS_INLINE_FUNCTION - complex& - operator += (const InputRealType& src) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); + KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator+=( + const RealType& src) noexcept { re_ += src; return *this; } - template - KOKKOS_INLINE_FUNCTION - void - operator += (const volatile InputRealType& src) volatile { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); - re_ += src; - } - - template - KOKKOS_INLINE_FUNCTION - complex& - operator -= (const complex& src) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); + KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator-=( + const complex& src) noexcept { re_ -= src.re_; im_ -= src.im_; return *this; } - KOKKOS_INLINE_FUNCTION - complex& - operator -= (const std::complex& src) { - re_ -= src.real(); - im_ -= src.imag(); - return *this; - } - - template - KOKKOS_INLINE_FUNCTION - complex& - operator -= (const InputRealType& src) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); + KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator-=( + const RealType& src) noexcept { re_ -= src; return *this; } - template - KOKKOS_INLINE_FUNCTION - complex& - operator *= (const complex& src) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); - const RealType realPart = re_ * src.re_ - im_ * src.im_; - const RealType imagPart = re_ * src.im_ + im_ * src.re_; - re_ = realPart; - im_ = imagPart; - return *this; - } - - template - KOKKOS_INLINE_FUNCTION - void - operator *= (const volatile complex& src) volatile { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); + KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator*=( + const complex& src) noexcept { const RealType realPart = re_ * src.re_ - im_ * src.im_; const RealType imagPart = re_ * src.im_ + im_ * src.re_; - re_ = realPart; - im_ = imagPart; - } - - KOKKOS_INLINE_FUNCTION - complex& - operator *= (const std::complex& src) { - const RealType realPart = re_ * src.real() - im_ * src.imag(); - const RealType imagPart = re_ * src.imag() + im_ * src.real(); - re_ = realPart; - im_ = imagPart; + re_ = realPart; + im_ = imagPart; return *this; } - template - KOKKOS_INLINE_FUNCTION - complex& - operator *= (const InputRealType& src) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); + KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator*=( + const RealType& src) noexcept { re_ *= src; im_ *= src; return *this; } - template - KOKKOS_INLINE_FUNCTION - void - operator *= (const volatile InputRealType& src) volatile { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); - re_ *= src; - im_ *= src; - } - - template - KOKKOS_INLINE_FUNCTION - complex& - operator /= (const complex& y) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); - + // Conditional noexcept, just in case RType throws on divide-by-zero + KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator/=( + const complex& y) noexcept(noexcept(RealType{} / RealType{})) { // Scale (by the "1-norm" of y) to avoid unwarranted overflow. // If the real part is +/-Inf and the imaginary part is -/+Inf, // this won't change the result. - const RealType s = std::fabs (y.real ()) + std::fabs (y.imag ()); + const RealType s = std::fabs(y.real()) + std::fabs(y.imag()); // If s is 0, then y is zero, so x/y == real(x)/0 + i*imag(x)/0. // In that case, the relation x/y == (x/s) / (y/s) doesn't hold, // because y/s is NaN. - if (s == 0.0) { + // TODO mark this branch unlikely + if (s == RealType(0)) { this->re_ /= s; this->im_ /= s; - } - else { - const complex x_scaled (this->re_ / s, this->im_ / s); - const complex y_conj_scaled (y.re_ / s, -(y.im_) / s); - const RealType y_scaled_abs = y_conj_scaled.re_ * y_conj_scaled.re_ + - y_conj_scaled.im_ * y_conj_scaled.im_; // abs(y) == abs(conj(y)) + } else { + const complex x_scaled(this->re_ / s, this->im_ / s); + const complex y_conj_scaled(y.re_ / s, -(y.im_) / s); + const RealType y_scaled_abs = + y_conj_scaled.re_ * y_conj_scaled.re_ + + y_conj_scaled.im_ * y_conj_scaled.im_; // abs(y) == abs(conj(y)) *this = x_scaled * y_conj_scaled; *this /= y_scaled_abs; } return *this; } - - KOKKOS_INLINE_FUNCTION - complex& - operator /= (const std::complex& y) { + KOKKOS_CONSTEXPR_14 + KOKKOS_INLINE_FUNCTION complex& operator/=( + const std::complex& y) noexcept(noexcept(RealType{} / + RealType{})) { // Scale (by the "1-norm" of y) to avoid unwarranted overflow. // If the real part is +/-Inf and the imaginary part is -/+Inf, // this won't change the result. - const RealType s = std::fabs (y.real ()) + std::fabs (y.imag ()); + const RealType s = std::fabs(y.real()) + std::fabs(y.imag()); // If s is 0, then y is zero, so x/y == real(x)/0 + i*imag(x)/0. // In that case, the relation x/y == (x/s) / (y/s) doesn't hold, // because y/s is NaN. - if (s == 0.0) { + if (s == RealType(0)) { this->re_ /= s; this->im_ /= s; - } - else { - const complex x_scaled (this->re_ / s, this->im_ / s); - const complex y_conj_scaled (y.re_ / s, -(y.im_) / s); - const RealType y_scaled_abs = y_conj_scaled.re_ * y_conj_scaled.re_ + - y_conj_scaled.im_ * y_conj_scaled.im_; // abs(y) == abs(conj(y)) + } else { + const complex x_scaled(this->re_ / s, this->im_ / s); + const complex y_conj_scaled(y.re_ / s, -(y.im_) / s); + const RealType y_scaled_abs = + y_conj_scaled.re_ * y_conj_scaled.re_ + + y_conj_scaled.im_ * y_conj_scaled.im_; // abs(y) == abs(conj(y)) *this = x_scaled * y_conj_scaled; *this /= y_scaled_abs; } return *this; } - - template - KOKKOS_INLINE_FUNCTION - complex& - operator /= (const InputRealType& src) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); - + KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator/=( + const RealType& src) noexcept(noexcept(RealType{} / RealType{})) { re_ /= src; im_ /= src; return *this; } - template - KOKKOS_INLINE_FUNCTION - bool - operator == (const complex& src) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); + //--------------------------------------------------------------------------- + // TODO: refactor Kokkos reductions to remove dependency on + // volatile member overloads since they are being deprecated in c++20 + //--------------------------------------------------------------------------- + + //! Copy constructor from volatile. + template ::value, + int>::type = 0> + KOKKOS_INLINE_FUNCTION complex(const volatile complex& src) noexcept + // Intentionally do the conversions implicitly here so that users don't + // get any warnings about narrowing, etc., that they would expect to get + // otherwise. + : re_(src.re_), im_(src.im_) {} - return (re_ == static_cast(src.re_)) && (im_ == static_cast(src.im_)); + /// \brief Assignment operator, for volatile *this and + /// nonvolatile input. + /// + /// \param src [in] Input; right-hand side of the assignment. + /// + /// This operator returns \c void instead of volatile + /// complex& . See Kokkos Issue #177 for the + /// explanation. In practice, this means that you should not chain + /// assignments with volatile lvalues. + KOKKOS_INLINE_FUNCTION void operator=( + const complex& src) volatile noexcept { + re_ = src.re_; + im_ = src.im_; + // We deliberately do not return anything here. See explanation + // in public documentation above. } - KOKKOS_INLINE_FUNCTION - bool - operator == (const std::complex& src) { - return (re_ == src.real()) && (im_ == src.imag()); + //! Assignment operator, volatile LHS and volatile RHS + // TODO Should this return void like the other volatile assignment operators? + KOKKOS_INLINE_FUNCTION volatile complex& operator=( + const volatile complex& src) volatile noexcept { + re_ = src.re_; + im_ = src.im_; + return *this; } - template - KOKKOS_INLINE_FUNCTION - bool - operator == (const InputRealType src) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); + //! Assignment operator, volatile RHS and non-volatile LHS + KOKKOS_INLINE_FUNCTION complex& operator=( + const volatile complex& src) noexcept { + re_ = src.re_; + im_ = src.im_; + return *this; + } + + // Mirroring the behavior of the assignment operators from complex RHS in the + // RealType RHS versions. - return (re_ == static_cast(src)) && (im_ == RealType(0)); + //! Assignment operator (from a volatile real number). + KOKKOS_INLINE_FUNCTION void operator=(const volatile RealType& val) noexcept { + re_ = val; + im_ = RealType(0); + // We deliberately do not return anything here. See explanation + // in public documentation above. } - template - KOKKOS_INLINE_FUNCTION - bool - operator != (const complex& src) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); + //! Assignment operator volatile LHS and non-volatile RHS + KOKKOS_INLINE_FUNCTION complex& operator=( + const RealType& val) volatile noexcept { + re_ = val; + im_ = RealType(0); + return *this; + } - return (re_ != static_cast(src.re_)) || (im_ != static_cast(src.im_)); + //! Assignment operator volatile LHS and volatile RHS + // TODO Should this return void like the other volatile assignment operators? + KOKKOS_INLINE_FUNCTION complex& operator=( + const volatile RealType& val) volatile noexcept { + re_ = val; + im_ = RealType(0); + return *this; } + //! The imaginary part of this complex number (volatile overload). KOKKOS_INLINE_FUNCTION - bool - operator != (const std::complex& src) { - return (re_ != src.real()) || (im_ != src.imag()); - } + volatile RealType& imag() volatile noexcept { return im_; } + + //! The real part of this complex number (volatile overload). + KOKKOS_INLINE_FUNCTION + volatile RealType& real() volatile noexcept { return re_; } + + //! The imaginary part of this complex number (volatile overload). + KOKKOS_INLINE_FUNCTION + RealType imag() const volatile noexcept { return im_; } - template + //! The real part of this complex number (volatile overload). KOKKOS_INLINE_FUNCTION - bool - operator != (const InputRealType src) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); + RealType real() const volatile noexcept { return re_; } + + KOKKOS_INLINE_FUNCTION void operator+=( + const volatile complex& src) volatile noexcept { + re_ += src.re_; + im_ += src.im_; + } + + KOKKOS_INLINE_FUNCTION void operator+=( + const volatile RealType& src) volatile noexcept { + re_ += src; + } + + KOKKOS_INLINE_FUNCTION void operator*=( + const volatile complex& src) volatile noexcept { + const RealType realPart = re_ * src.re_ - im_ * src.im_; + const RealType imagPart = re_ * src.im_ + im_ * src.re_; - return (re_ != static_cast(src)) || (im_ != RealType(0)); + re_ = realPart; + im_ = imagPart; } - + + KOKKOS_INLINE_FUNCTION void operator*=( + const volatile RealType& src) volatile noexcept { + re_ *= src; + im_ *= src; + } + + // TODO DSH 2019-10-7 why are there no volatile /= and friends? }; +//============================================================================== +// {{{1 + +// Note that this is not the same behavior as std::complex, which doesn't allow +// implicit conversions, but since this is the way we had it before, we have +// to do it this way now. + +//! Binary == operator for complex complex. +template +KOKKOS_INLINE_FUNCTION bool operator==(complex const& x, + complex const& y) noexcept { + using common_type = typename std::common_type::type; + return common_type(x.real()) == common_type(y.real()) && + common_type(x.imag()) == common_type(y.imag()); +} + +// TODO (here and elsewhere) decide if we should convert to a Kokkos::complex +// and do the comparison in a device-marked function +//! Binary == operator for std::complex complex. +template +inline bool operator==(std::complex const& x, + complex const& y) noexcept { + using common_type = typename std::common_type::type; + return common_type(x.real()) == common_type(y.real()) && + common_type(x.imag()) == common_type(y.imag()); +} + +//! Binary == operator for complex std::complex. +template +inline bool operator==(complex const& x, + std::complex const& y) noexcept { + using common_type = typename std::common_type::type; + return common_type(x.real()) == common_type(y.real()) && + common_type(x.imag()) == common_type(y.imag()); +} + +//! Binary == operator for complex real. +template < + class RealType1, class RealType2, + // Constraints to avoid participation in oparator==() for every possible RHS + typename std::enable_if::value, + int>::type = 0> +KOKKOS_INLINE_FUNCTION bool operator==(complex const& x, + RealType2 const& y) noexcept { + using common_type = typename std::common_type::type; + return common_type(x.real()) == common_type(y) && + common_type(x.imag()) == common_type(0); +} + +//! Binary == operator for real complex. +template < + class RealType1, class RealType2, + // Constraints to avoid participation in oparator==() for every possible RHS + typename std::enable_if::value, + int>::type = 0> +KOKKOS_INLINE_FUNCTION bool operator==(RealType1 const& x, + complex const& y) noexcept { + using common_type = typename std::common_type::type; + return common_type(x) == common_type(y.real()) && + common_type(0) == common_type(y.imag()); +} + +//! Binary != operator for complex complex. +template +KOKKOS_INLINE_FUNCTION bool operator!=(complex const& x, + complex const& y) noexcept { + using common_type = typename std::common_type::type; + return common_type(x.real()) != common_type(y.real()) || + common_type(x.imag()) != common_type(y.imag()); +} + +//! Binary != operator for std::complex complex. +template +inline bool operator!=(std::complex const& x, + complex const& y) noexcept { + using common_type = typename std::common_type::type; + return common_type(x.real()) != common_type(y.real()) || + common_type(x.imag()) != common_type(y.imag()); +} + +//! Binary != operator for complex std::complex. +template +inline bool operator!=(complex const& x, + std::complex const& y) noexcept { + using common_type = typename std::common_type::type; + return common_type(x.real()) != common_type(y.real()) || + common_type(x.imag()) != common_type(y.imag()); +} + +//! Binary != operator for complex real. +template < + class RealType1, class RealType2, + // Constraints to avoid participation in oparator==() for every possible RHS + typename std::enable_if::value, + int>::type = 0> +KOKKOS_INLINE_FUNCTION bool operator!=(complex const& x, + RealType2 const& y) noexcept { + using common_type = typename std::common_type::type; + return common_type(x.real()) != common_type(y) || + common_type(x.imag()) != common_type(0); +} + +//! Binary != operator for real complex. +template < + class RealType1, class RealType2, + // Constraints to avoid participation in oparator==() for every possible RHS + typename std::enable_if::value, + int>::type = 0> +KOKKOS_INLINE_FUNCTION bool operator!=(RealType1 const& x, + complex const& y) noexcept { + using common_type = typename std::common_type::type; + return common_type(x) != common_type(y.real()) || + common_type(0) != common_type(y.imag()); +} + +// end Equality and inequality }}}1 +//============================================================================== //! Binary + operator for complex complex. -template +template KOKKOS_INLINE_FUNCTION -complex::type> -operator + (const complex& x, const complex& y) { - return complex::type > (x.real () + y.real (), x.imag () + y.imag ()); + complex::type> + operator+(const complex& x, + const complex& y) noexcept { + return complex::type>( + x.real() + y.real(), x.imag() + y.imag()); } //! Binary + operator for complex scalar. -template +template KOKKOS_INLINE_FUNCTION -complex::type> -operator + (const complex& x, const RealType2& y) { - return complex::type> (x.real () + y , x.imag ()); + complex::type> + operator+(const complex& x, const RealType2& y) noexcept { + return complex::type>( + x.real() + y, x.imag()); } //! Binary + operator for scalar complex. -template +template KOKKOS_INLINE_FUNCTION -complex::type> -operator + (const RealType1& x, const complex& y) { - return complex::type> (x + y.real (), y.imag ()); + complex::type> + operator+(const RealType1& x, const complex& y) noexcept { + return complex::type>( + x + y.real(), y.imag()); } //! Unary + operator for complex. -template -KOKKOS_INLINE_FUNCTION -complex -operator + (const complex& x) { - return x; +template +KOKKOS_INLINE_FUNCTION complex operator+( + const complex& x) noexcept { + return complex{+x.real(), +x.imag()}; } //! Binary - operator for complex. -template +template KOKKOS_INLINE_FUNCTION -complex::type> -operator - (const complex& x, const complex& y) { - return complex::type> (x.real () - y.real (), x.imag () - y.imag ()); + complex::type> + operator-(const complex& x, + const complex& y) noexcept { + return complex::type>( + x.real() - y.real(), x.imag() - y.imag()); } //! Binary - operator for complex scalar. -template +template KOKKOS_INLINE_FUNCTION -complex::type> -operator - (const complex& x, const RealType2& y) { - return complex::type> (x.real () - y , x.imag ()); + complex::type> + operator-(const complex& x, const RealType2& y) noexcept { + return complex::type>( + x.real() - y, x.imag()); } //! Binary - operator for scalar complex. -template +template KOKKOS_INLINE_FUNCTION -complex::type> -operator - (const RealType1& x, const complex& y) { - return complex::type> (x - y.real (), - y.imag ()); + complex::type> + operator-(const RealType1& x, const complex& y) noexcept { + return complex::type>( + x - y.real(), -y.imag()); } //! Unary - operator for complex. -template -KOKKOS_INLINE_FUNCTION -complex -operator - (const complex& x) { - return complex (-x.real (), -x.imag ()); +template +KOKKOS_INLINE_FUNCTION complex operator-( + const complex& x) noexcept { + return complex(-x.real(), -x.imag()); } //! Binary * operator for complex. -template +template KOKKOS_INLINE_FUNCTION -complex::type> -operator * (const complex& x, const complex& y) { - return complex::type> (x.real () * y.real () - x.imag () * y.imag (), - x.real () * y.imag () + x.imag () * y.real ()); + complex::type> + operator*(const complex& x, + const complex& y) noexcept { + return complex::type>( + x.real() * y.real() - x.imag() * y.imag(), + x.real() * y.imag() + x.imag() * y.real()); } /// \brief Binary * operator for std::complex and complex. /// -/// This function exists because GCC 4.7.2 (and perhaps other -/// compilers) are not able to deduce that they can multiply -/// std::complex by Kokkos::complex, by first converting std::complex -/// to Kokkos::complex. +/// This needs to exist because template parameters can't be deduced when +/// conversions occur. We could probably fix this using hidden friends patterns /// /// This function cannot be called in a CUDA device function, because /// std::complex's methods and nonmember functions are not marked as /// CUDA device functions. -template -inline -complex::type> -operator * (const std::complex& x, const complex& y) { - return complex::type> (x.real () * y.real () - x.imag () * y.imag (), - x.real () * y.imag () + x.imag () * y.real ()); +template +inline complex::type> operator*( + const std::complex& x, const complex& y) { + return complex::type>( + x.real() * y.real() - x.imag() * y.imag(), + x.real() * y.imag() + x.imag() * y.real()); } /// \brief Binary * operator for RealType times complex. /// /// This function exists because the compiler doesn't know that /// RealType and complex commute with respect to operator*. -template +template KOKKOS_INLINE_FUNCTION -complex::type> -operator * (const RealType1& x, const complex& y) { - return complex::type> (x * y.real (), x * y.imag ()); + complex::type> + operator*(const RealType1& x, const complex& y) noexcept { + return complex::type>( + x * y.real(), x * y.imag()); } /// \brief Binary * operator for RealType times complex. /// /// This function exists because the compiler doesn't know that /// RealType and complex commute with respect to operator*. -template +template KOKKOS_INLINE_FUNCTION -complex::type> -operator * (const complex& y, const RealType2& x) { - return complex::type> (x * y.real (), x * y.imag ()); + complex::type> + operator*(const complex& y, const RealType2& x) noexcept { + return complex::type>( + x * y.real(), x * y.imag()); } //! Imaginary part of a complex number. -template -KOKKOS_INLINE_FUNCTION -RealType imag (const complex& x) { - return x.imag (); +template +KOKKOS_INLINE_FUNCTION RealType imag(const complex& x) noexcept { + return x.imag(); } //! Real part of a complex number. -template -KOKKOS_INLINE_FUNCTION -RealType real (const complex& x) { - return x.real (); +template +KOKKOS_INLINE_FUNCTION RealType real(const complex& x) noexcept { + return x.real(); } //! Absolute value (magnitude) of a complex number. -template -KOKKOS_INLINE_FUNCTION -RealType abs (const complex& x) { +template +KOKKOS_INLINE_FUNCTION RealType abs(const complex& x) { #ifndef __CUDA_ARCH__ using std::hypot; #endif - return hypot(x.real(),x.imag()); + return hypot(x.real(), x.imag()); } //! Power of a complex number -template -KOKKOS_INLINE_FUNCTION -Kokkos::complex pow (const complex& x, const RealType& e) { - RealType r = abs(x); - RealType phi = std::atan(x.imag()/x.real()); - return std::pow(r,e) * Kokkos::complex(std::cos(phi*e),std::sin(phi*e)); +template +KOKKOS_INLINE_FUNCTION Kokkos::complex pow(const complex& x, + const RealType& e) { + RealType r = abs(x); + RealType phi = std::atan(x.imag() / x.real()); + return std::pow(r, e) * + Kokkos::complex(std::cos(phi * e), std::sin(phi * e)); } //! Square root of a complex number. -template -KOKKOS_INLINE_FUNCTION -Kokkos::complex sqrt (const complex& x) { - RealType r = abs(x); - RealType phi = std::atan(x.imag()/x.real()); - return std::sqrt(r) * Kokkos::complex(std::cos(phi*0.5),std::sin(phi*0.5)); +template +KOKKOS_INLINE_FUNCTION Kokkos::complex sqrt( + const complex& x) { + RealType r = abs(x); + RealType phi = std::atan(x.imag() / x.real()); + return std::sqrt(r) * + Kokkos::complex(std::cos(phi * 0.5), std::sin(phi * 0.5)); } //! Conjugate of a complex number. -template -KOKKOS_INLINE_FUNCTION -complex conj (const complex& x) { - return complex (real (x), -imag (x)); +template +KOKKOS_INLINE_FUNCTION complex conj( + const complex& x) noexcept { + return complex(real(x), -imag(x)); } //! Exponential of a complex number. -template -KOKKOS_INLINE_FUNCTION -complex exp (const complex& x) { - return std::exp(x.real()) * complex (std::cos (x.imag()), std::sin(x.imag())); +template +KOKKOS_INLINE_FUNCTION complex exp(const complex& x) { + return std::exp(x.real()) * + complex(std::cos(x.imag()), std::sin(x.imag())); } /// This function cannot be called in a CUDA device function, /// because std::complex's methods and nonmember functions are not /// marked as CUDA device functions. -template -inline -complex -exp (const std::complex& c) { - return complex( std::exp( c.real() )*std::cos( c.imag() ), std::exp( c.real() )*std::sin( c.imag() ) ); +template +inline complex exp(const std::complex& c) { + return complex(std::exp(c.real()) * std::cos(c.imag()), + std::exp(c.real()) * std::sin(c.imag())); } //! Binary operator / for complex and real numbers -template +template KOKKOS_INLINE_FUNCTION -complex::type> -operator / (const complex& x, const RealType2& y) { - return complex::type> (real (x) / y, imag (x) / y); + complex::type> + operator/(const complex& x, + const RealType2& y) noexcept(noexcept(RealType1{} / + RealType2{})) { + return complex::type>( + real(x) / y, imag(x) / y); } //! Binary operator / for complex. -template +template KOKKOS_INLINE_FUNCTION -complex::type> -operator / (const complex& x, const complex& y) { + complex::type> + operator/(const complex& x, + const complex& y) noexcept(noexcept(RealType1{} / + RealType2{})) { // Scale (by the "1-norm" of y) to avoid unwarranted overflow. // If the real part is +/-Inf and the imaginary part is -/+Inf, // this won't change the result. - typedef typename std::common_type::type common_real_type; - const common_real_type s = std::fabs (real (y)) + std::fabs (imag (y)); + typedef + typename std::common_type::type common_real_type; + const common_real_type s = std::fabs(real(y)) + std::fabs(imag(y)); // If s is 0, then y is zero, so x/y == real(x)/0 + i*imag(x)/0. // In that case, the relation x/y == (x/s) / (y/s) doesn't hold, // because y/s is NaN. if (s == 0.0) { - return complex (real (x) / s, imag (x) / s); - } - else { - const complex x_scaled (real (x) / s, imag (x) / s); - const complex y_conj_scaled (real (y) / s, -imag (y) / s); - const RealType1 y_scaled_abs = real (y_conj_scaled) * real (y_conj_scaled) + - imag (y_conj_scaled) * imag (y_conj_scaled); // abs(y) == abs(conj(y)) + return complex(real(x) / s, imag(x) / s); + } else { + const complex x_scaled(real(x) / s, imag(x) / s); + const complex y_conj_scaled(real(y) / s, -imag(y) / s); + const RealType1 y_scaled_abs = + real(y_conj_scaled) * real(y_conj_scaled) + + imag(y_conj_scaled) * imag(y_conj_scaled); // abs(y) == abs(conj(y)) complex result = x_scaled * y_conj_scaled; result /= y_scaled_abs; return result; @@ -716,119 +742,43 @@ operator / (const complex& x, const complex& y) { } //! Binary operator / for complex and real numbers -template -KOKKOS_INLINE_FUNCTION -complex::type> -operator / (const RealType1& x, const complex& y) { - return complex::type> (x)/y; -} - -//! Equality operator for two complex numbers. -template -KOKKOS_INLINE_FUNCTION -bool -operator == (const complex& x, const complex& y) { - typedef typename std::common_type::type common_real_type; - return ( static_cast(real (x)) == static_cast(real (y)) && - static_cast(imag (x)) == static_cast(imag (y)) ); -} - -/// \brief Equality operator for std::complex and Kokkos::complex. -/// -/// This cannot be a device function, since std::real is not. -/// Otherwise, CUDA builds will give compiler warnings ("warning: -/// calling a constexpr __host__ function("real") from a __host__ -/// __device__ function("operator==") is not allowed"). -template -inline -bool -operator == (const std::complex& x, const complex& y) { - typedef typename std::common_type::type common_real_type; - return ( static_cast(std::real (x)) == static_cast(real (y)) && - static_cast(std::imag (x)) == static_cast(imag (y)) ); -} - -//! Equality operator for complex and real number. -template -KOKKOS_INLINE_FUNCTION -bool -operator == (const complex& x, const RealType2& y) { - typedef typename std::common_type::type common_real_type; - return ( static_cast(real (x)) == static_cast(y) && - static_cast(imag (x)) == static_cast(0.0) ); -} - -//! Equality operator for real and complex number. -template -KOKKOS_INLINE_FUNCTION -bool -operator == (const RealType1& x, const complex& y) { - return y == x; -} - -//! Inequality operator for two complex numbers. -template +template KOKKOS_INLINE_FUNCTION -bool -operator != (const complex& x, const complex& y) { - typedef typename std::common_type::type common_real_type; - return ( static_cast(real (x)) != static_cast(real (y)) || - static_cast(imag (x)) != static_cast(imag (y)) ); -} - -//! Inequality operator for std::complex and Kokkos::complex. -template -inline -bool -operator != (const std::complex& x, const complex& y) { - typedef typename std::common_type::type common_real_type; - return ( static_cast(std::real (x)) != static_cast(real (y)) || - static_cast(std::imag (x)) != static_cast(imag (y)) ); + complex::type> + operator/(const RealType1& x, + const complex& y) noexcept(noexcept(RealType1{} / + RealType2{})) { + return complex::type>(x) / y; } -//! Inequality operator for complex and real number. -template -KOKKOS_INLINE_FUNCTION -bool -operator != (const complex& x, const RealType2& y) { - typedef typename std::common_type::type common_real_type; - return ( static_cast(real (x)) != static_cast(y) || - static_cast(imag (x)) != static_cast(0.0) ); -} - -//! Inequality operator for real and complex number. -template -KOKKOS_INLINE_FUNCTION -bool -operator != (const RealType1& x, const complex& y) { - return y != x; -} - -template -std::ostream& operator << (std::ostream& os, const complex& x) { - const std::complex x_std (Kokkos::real (x), Kokkos::imag (x)); +template +std::ostream& operator<<(std::ostream& os, const complex& x) { + const std::complex x_std(Kokkos::real(x), Kokkos::imag(x)); os << x_std; return os; } -template -std::ostream& operator >> (std::ostream& os, complex& x) { +template +std::istream& operator>>(std::istream& is, complex& x) { std::complex x_std; - os >> x_std; - x = x_std; // only assigns on success of above - return os; + is >> x_std; + x = x_std; // only assigns on success of above + return is; } - -template +template struct reduction_identity > { typedef reduction_identity t_red_ident; - KOKKOS_FORCEINLINE_FUNCTION constexpr static Kokkos::complex sum() - {return Kokkos::complex(t_red_ident::sum(),t_red_ident::sum());} - KOKKOS_FORCEINLINE_FUNCTION constexpr static Kokkos::complex prod() - {return Kokkos::complex(t_red_ident::prod(),t_red_ident::sum());} + KOKKOS_FORCEINLINE_FUNCTION constexpr static Kokkos::complex + sum() noexcept { + return Kokkos::complex(t_red_ident::sum(), t_red_ident::sum()); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static Kokkos::complex + prod() noexcept { + return Kokkos::complex(t_red_ident::prod(), t_red_ident::sum()); + } }; -} // namespace Kokkos +} // namespace Kokkos -#endif // KOKKOS_COMPLEX_HPP +#endif // KOKKOS_COMPLEX_HPP diff --git a/lib/kokkos/core/src/Kokkos_Concepts.hpp b/lib/kokkos/core/src/Kokkos_Concepts.hpp index ca2e8b4eb6..abfa88e1d2 100644 --- a/lib/kokkos/core/src/Kokkos_Concepts.hpp +++ b/lib/kokkos/core/src/Kokkos_Concepts.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -54,245 +55,264 @@ namespace Kokkos { -//Schedules for Execution Policies +// Schedules for Execution Policies struct Static {}; struct Dynamic {}; -//Schedule Wrapper Type -template -struct Schedule -{ - static_assert( std::is_same::value - || std::is_same::value - , "Kokkos: Invalid Schedule<> type." - ); - using schedule_type = Schedule ; - using type = T; +// Schedule Wrapper Type +template +struct Schedule { + static_assert(std::is_same::value || + std::is_same::value, + "Kokkos: Invalid Schedule<> type."); + using schedule_type = Schedule; + using type = T; }; -//Specify Iteration Index Type -template -struct IndexType -{ - static_assert(std::is_integral::value,"Kokkos: Invalid IndexType<>."); - using index_type = IndexType ; - using type = T; +// Specify Iteration Index Type +template +struct IndexType { + static_assert(std::is_integral::value, "Kokkos: Invalid IndexType<>."); + using index_type = IndexType; + using type = T; }; namespace Experimental { - struct WorkItemProperty { - template - struct ImplWorkItemProperty { - static const unsigned value = Property; - using work_item_property = ImplWorkItemProperty; - }; - - constexpr static const ImplWorkItemProperty<0> None = ImplWorkItemProperty<0>(); - constexpr static const ImplWorkItemProperty<1> HintLightWeight = ImplWorkItemProperty<1>(); - constexpr static const ImplWorkItemProperty<2> HintHeavyWeight = ImplWorkItemProperty<2>(); - constexpr static const ImplWorkItemProperty<4> HintRegular = ImplWorkItemProperty<4>(); - constexpr static const ImplWorkItemProperty<8> HintIrregular = ImplWorkItemProperty<8>(); - typedef ImplWorkItemProperty<0> None_t; - typedef ImplWorkItemProperty<1> HintLightWeight_t; - typedef ImplWorkItemProperty<2> HintHeavyWeight_t; - typedef ImplWorkItemProperty<4> HintRegular_t; - typedef ImplWorkItemProperty<8> HintIrregular_t; +struct WorkItemProperty { + template + struct ImplWorkItemProperty { + static const unsigned value = Property; + using work_item_property = ImplWorkItemProperty; }; -template -inline constexpr WorkItemProperty::ImplWorkItemProperty operator | - (WorkItemProperty::ImplWorkItemProperty, WorkItemProperty::ImplWorkItemProperty) { - return WorkItemProperty::ImplWorkItemProperty(); -} + constexpr static const ImplWorkItemProperty<0> None = + ImplWorkItemProperty<0>(); + constexpr static const ImplWorkItemProperty<1> HintLightWeight = + ImplWorkItemProperty<1>(); + constexpr static const ImplWorkItemProperty<2> HintHeavyWeight = + ImplWorkItemProperty<2>(); + constexpr static const ImplWorkItemProperty<4> HintRegular = + ImplWorkItemProperty<4>(); + constexpr static const ImplWorkItemProperty<8> HintIrregular = + ImplWorkItemProperty<8>(); + typedef ImplWorkItemProperty<0> None_t; + typedef ImplWorkItemProperty<1> HintLightWeight_t; + typedef ImplWorkItemProperty<2> HintHeavyWeight_t; + typedef ImplWorkItemProperty<4> HintRegular_t; + typedef ImplWorkItemProperty<8> HintIrregular_t; +}; -template -inline constexpr WorkItemProperty::ImplWorkItemProperty operator & - (WorkItemProperty::ImplWorkItemProperty, WorkItemProperty::ImplWorkItemProperty) { - return WorkItemProperty::ImplWorkItemProperty(); +template +inline constexpr WorkItemProperty::ImplWorkItemProperty operator|( + WorkItemProperty::ImplWorkItemProperty, + WorkItemProperty::ImplWorkItemProperty) { + return WorkItemProperty::ImplWorkItemProperty(); } -template -inline constexpr bool operator == (WorkItemProperty::ImplWorkItemProperty, WorkItemProperty::ImplWorkItemProperty) { - return pv1 == pv2; +template +inline constexpr WorkItemProperty::ImplWorkItemProperty operator&( + WorkItemProperty::ImplWorkItemProperty, + WorkItemProperty::ImplWorkItemProperty) { + return WorkItemProperty::ImplWorkItemProperty(); } +template +inline constexpr bool operator==(WorkItemProperty::ImplWorkItemProperty, + WorkItemProperty::ImplWorkItemProperty) { + return pv1 == pv2; } +} // namespace Experimental + /**\brief Specify Launch Bounds for CUDA execution. * * If no launch bounds specified then do not set launch bounds. */ -template< unsigned int maxT = 0 /* Max threads per block */ - , unsigned int minB = 0 /* Min blocks per SM */ - > -struct LaunchBounds -{ +template +struct LaunchBounds { using launch_bounds = LaunchBounds; - using type = LaunchBounds; - static unsigned int constexpr maxTperB {maxT}; - static unsigned int constexpr minBperSM {minB}; + using type = LaunchBounds; + static unsigned int constexpr maxTperB{maxT}; + static unsigned int constexpr minBperSM{minB}; }; -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- namespace Kokkos { -#define KOKKOS_IMPL_IS_CONCEPT( CONCEPT ) \ - template< typename T > struct is_ ## CONCEPT { \ - private: \ - template< typename , typename = std::true_type > struct have : std::false_type {}; \ - template< typename U > struct have::type, \ - typename std::remove_cv::type \ - >::type> : std::true_type {}; \ - template< typename U > struct have::type, \ - typename std::remove_cv::type \ - >::type> : std::true_type {}; \ - public: \ - enum { value = is_ ## CONCEPT::template have::value }; \ +#define KOKKOS_IMPL_IS_CONCEPT(CONCEPT) \ + template \ + struct is_##CONCEPT { \ + private: \ + template \ + struct have : std::false_type {}; \ + template \ + struct have::type, \ + typename std::remove_cv::type>::type> \ + : std::true_type {}; \ + template \ + struct have::type, \ + typename std::remove_cv::type>::type> \ + : std::true_type {}; \ + \ + public: \ + enum { value = is_##CONCEPT::template have::value }; \ }; // Public concept: -KOKKOS_IMPL_IS_CONCEPT( memory_space ) -KOKKOS_IMPL_IS_CONCEPT( memory_traits ) -KOKKOS_IMPL_IS_CONCEPT( execution_space ) -KOKKOS_IMPL_IS_CONCEPT( execution_policy ) -KOKKOS_IMPL_IS_CONCEPT( array_layout ) -KOKKOS_IMPL_IS_CONCEPT( reducer ) +KOKKOS_IMPL_IS_CONCEPT(memory_space) +KOKKOS_IMPL_IS_CONCEPT(memory_traits) +KOKKOS_IMPL_IS_CONCEPT(execution_space) +KOKKOS_IMPL_IS_CONCEPT(execution_policy) +KOKKOS_IMPL_IS_CONCEPT(array_layout) +KOKKOS_IMPL_IS_CONCEPT(reducer) namespace Experimental { -KOKKOS_IMPL_IS_CONCEPT( work_item_property ) +KOKKOS_IMPL_IS_CONCEPT(work_item_property) } namespace Impl { // For backward compatibility: -using Kokkos::is_memory_space ; -using Kokkos::is_memory_traits ; -using Kokkos::is_execution_space ; -using Kokkos::is_execution_policy ; -using Kokkos::is_array_layout ; +using Kokkos::is_array_layout; +using Kokkos::is_execution_policy; +using Kokkos::is_execution_space; +using Kokkos::is_memory_space; +using Kokkos::is_memory_traits; // Implementation concept: -KOKKOS_IMPL_IS_CONCEPT( iteration_pattern ) -KOKKOS_IMPL_IS_CONCEPT( schedule_type ) -KOKKOS_IMPL_IS_CONCEPT( index_type ) -KOKKOS_IMPL_IS_CONCEPT( launch_bounds ) -KOKKOS_IMPL_IS_CONCEPT( thread_team_member ) -KOKKOS_IMPL_IS_CONCEPT( host_thread_team_member ) +KOKKOS_IMPL_IS_CONCEPT(iteration_pattern) +KOKKOS_IMPL_IS_CONCEPT(schedule_type) +KOKKOS_IMPL_IS_CONCEPT(index_type) +KOKKOS_IMPL_IS_CONCEPT(launch_bounds) +KOKKOS_IMPL_IS_CONCEPT(thread_team_member) +KOKKOS_IMPL_IS_CONCEPT(host_thread_team_member) -} +} // namespace Impl #undef KOKKOS_IMPL_IS_CONCEPT -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- namespace Kokkos { -template< class ExecutionSpace , class MemorySpace > +template struct Device { - static_assert( Kokkos::is_execution_space::value - , "Execution space is not valid" ); - static_assert( Kokkos::is_memory_space::value - , "Memory space is not valid" ); - typedef ExecutionSpace execution_space; - typedef MemorySpace memory_space; - typedef Device device_type; + static_assert(Kokkos::is_execution_space::value, + "Execution space is not valid"); + static_assert(Kokkos::is_memory_space::value, + "Memory space is not valid"); + typedef ExecutionSpace execution_space; + typedef MemorySpace memory_space; + typedef Device device_type; }; - -template< typename T > +template struct is_space { -private: - - template< typename , typename = void > - struct exe : std::false_type { typedef void space ; }; - - template< typename , typename = void > - struct mem : std::false_type { typedef void space ; }; + private: + template + struct exe : std::false_type { + typedef void space; + }; - template< typename , typename = void > - struct dev : std::false_type { typedef void space ; }; + template + struct mem : std::false_type { + typedef void space; + }; - template< typename U > - struct exe::type> - : std::is_same::type - { typedef typename U::execution_space space ; }; + template + struct dev : std::false_type { + typedef void space; + }; - template< typename U > - struct mem::type> - : std::is_same::type - { typedef typename U::memory_space space ; }; + template + struct exe::type> + : std::is_same::type { + typedef typename U::execution_space space; + }; - template< typename U > - struct dev::type> - : std::is_same::type - { typedef typename U::device_type space ; }; + template + struct mem< + U, typename std::conditional::type> + : std::is_same::type { + typedef typename U::memory_space space; + }; - typedef typename is_space::template exe is_exe ; - typedef typename is_space::template mem is_mem ; - typedef typename is_space::template dev is_dev ; + template + struct dev< + U, typename std::conditional::type> + : std::is_same::type { + typedef typename U::device_type space; + }; -public: + typedef typename is_space::template exe is_exe; + typedef typename is_space::template mem is_mem; + typedef typename is_space::template dev is_dev; + public: enum { value = is_exe::value || is_mem::value || is_dev::value }; - typedef typename is_exe::space execution_space ; - typedef typename is_mem::space memory_space ; + typedef typename is_exe::space execution_space; + typedef typename is_mem::space memory_space; // For backward compatibility, deprecated in favor of // Kokkos::Impl::HostMirror::host_mirror_space - typedef typename std::conditional - < std::is_same< memory_space , Kokkos::HostSpace >::value -#if defined( KOKKOS_ENABLE_CUDA ) - || std::is_same< memory_space , Kokkos::CudaUVMSpace >::value - || std::is_same< memory_space , Kokkos::CudaHostPinnedSpace >::value + typedef typename std::conditional< + std::is_same::value +#if defined(KOKKOS_ENABLE_CUDA) + || std::is_same::value || + std::is_same::value #endif /* #if defined( KOKKOS_ENABLE_CUDA ) */ - , memory_space - , Kokkos::HostSpace - >::type host_memory_space ; - -#if defined( KOKKOS_ENABLE_CUDA ) - typedef typename std::conditional - < std::is_same< execution_space , Kokkos::Cuda >::value - , Kokkos::DefaultHostExecutionSpace , execution_space - >::type host_execution_space ; + , + memory_space, Kokkos::HostSpace>::type host_memory_space; + +#if defined(KOKKOS_ENABLE_CUDA) + typedef typename std::conditional< + std::is_same::value, + Kokkos::DefaultHostExecutionSpace, execution_space>::type + host_execution_space; +#else +#if defined(KOKKOS_ENABLE_OPENMPTARGET) + typedef typename std::conditional< + std::is_same::value, + Kokkos::DefaultHostExecutionSpace, execution_space>::type + host_execution_space; #else - #if defined( KOKKOS_ENABLE_OPENMPTARGET ) - typedef typename std::conditional - < std::is_same< execution_space , Kokkos::Experimental::OpenMPTarget >::value - , Kokkos::DefaultHostExecutionSpace , execution_space - >::type host_execution_space ; - #else - typedef execution_space host_execution_space ; - #endif + typedef execution_space host_execution_space; +#endif #endif - typedef typename std::conditional - < std::is_same< execution_space , host_execution_space >::value && - std::is_same< memory_space , host_memory_space >::value - , T , Kokkos::Device< host_execution_space , host_memory_space > - >::type host_mirror_space ; + typedef typename std::conditional< + std::is_same::value && + std::is_same::value, + T, Kokkos::Device >::type + host_mirror_space; }; -// For backward compatibility +// For backward compatiblity namespace Impl { -using Kokkos::is_space ; +using Kokkos::is_space; } -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- @@ -304,12 +324,11 @@ namespace Impl { * The default case can assume accessibility for the same space. * Specializations must be defined for different memory spaces. */ -template< typename DstMemorySpace , typename SrcMemorySpace > +template struct MemorySpaceAccess { - - static_assert( Kokkos::is_memory_space< DstMemorySpace >::value && - Kokkos::is_memory_space< SrcMemorySpace >::value - , "template arguments must be memory spaces" ); + static_assert(Kokkos::is_memory_space::value && + Kokkos::is_memory_space::value, + "template arguments must be memory spaces"); /**\brief Can a View (or pointer) to memory in SrcMemorySpace * be assigned to a View (or pointer) to memory marked DstMemorySpace. @@ -318,7 +337,7 @@ struct MemorySpaceAccess { * 2. All execution spaces that can access DstMemorySpace can also access * SrcMemorySpace. */ - enum { assignable = std::is_same::value }; + enum { assignable = std::is_same::value }; /**\brief For all DstExecSpace::memory_space == DstMemorySpace * DstExecSpace can access SrcMemorySpace. @@ -331,7 +350,8 @@ struct MemorySpaceAccess { enum { deepcopy = assignable }; }; -}} // namespace Kokkos::Impl +} // namespace Impl +} // namespace Kokkos namespace Kokkos { @@ -354,34 +374,31 @@ namespace Kokkos { * When AccessSpace::memory_space == Kokkos::HostSpace * then space is the View host mirror space. */ -template< typename AccessSpace , typename MemorySpace > +template struct SpaceAccessibility { -private: + private: + static_assert(Kokkos::is_space::value, + "template argument #1 must be a Kokkos space"); - static_assert( Kokkos::is_space< AccessSpace >::value - , "template argument #1 must be a Kokkos space" ); - - static_assert( Kokkos::is_memory_space< MemorySpace >::value - , "template argument #2 must be a Kokkos memory space" ); + static_assert(Kokkos::is_memory_space::value, + "template argument #2 must be a Kokkos memory space"); // The input AccessSpace may be a Device // verify that it is a valid combination of spaces. - static_assert( Kokkos::Impl::MemorySpaceAccess - < typename AccessSpace::execution_space::memory_space - , typename AccessSpace::memory_space - >::accessible - , "template argument #1 is an invalid space" ); - - typedef Kokkos::Impl::MemorySpaceAccess - < typename AccessSpace::execution_space::memory_space , MemorySpace > - exe_access ; + static_assert(Kokkos::Impl::MemorySpaceAccess< + typename AccessSpace::execution_space::memory_space, + typename AccessSpace::memory_space>::accessible, + "template argument #1 is an invalid space"); - typedef Kokkos::Impl::MemorySpaceAccess - < typename AccessSpace::memory_space , MemorySpace > - mem_access ; + typedef Kokkos::Impl::MemorySpaceAccess< + typename AccessSpace::execution_space::memory_space, MemorySpace> + exe_access; -public: + typedef Kokkos::Impl::MemorySpaceAccess + mem_access; + public: /**\brief Can AccessSpace::execution_space access MemorySpace ? * * Default based upon memory space accessibility. @@ -394,8 +411,9 @@ public: * Default based upon memory space accessibility. * Specialization required for other relationships. */ - enum { assignable = - is_memory_space< AccessSpace >::value && mem_access::assignable }; + enum { + assignable = is_memory_space::value && mem_access::assignable + }; /**\brief Can deep copy to AccessSpace::memory_Space from MemorySpace ? */ enum { deepcopy = mem_access::deepcopy }; @@ -404,24 +422,24 @@ public: // to be able to access MemorySpace? // If same memory space or not accessible use the AccessSpace // else construct a device with execution space and memory space. - typedef typename std::conditional - < std::is_same::value || - ! exe_access::accessible - , AccessSpace - , Kokkos::Device< typename AccessSpace::execution_space , MemorySpace > - >::type space ; + typedef typename std::conditional< + std::is_same::value || + !exe_access::accessible, + AccessSpace, + Kokkos::Device >::type + space; }; -} // namespace Kokkos +} // namespace Kokkos namespace Kokkos { namespace Impl { -using Kokkos::SpaceAccessibility ; // For backward compatibility +using Kokkos::SpaceAccessibility; // For backward compatibility -}} // namespace Kokkos::Impl +} +} // namespace Kokkos //---------------------------------------------------------------------------- -#endif // KOKKOS_CORE_CONCEPTS_HPP - +#endif // KOKKOS_CORE_CONCEPTS_HPP diff --git a/lib/kokkos/core/src/Kokkos_CopyViews.hpp b/lib/kokkos/core/src/Kokkos_CopyViews.hpp index 9210f21ab7..e64b434d02 100644 --- a/lib/kokkos/core/src/Kokkos_CopyViews.hpp +++ b/lib/kokkos/core/src/Kokkos_CopyViews.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -56,1479 +57,1781 @@ namespace Kokkos { namespace Impl { -template -struct ViewFillLayoutSelector { -}; +template +struct ViewFillLayoutSelector {}; -template<> +template <> struct ViewFillLayoutSelector { static const Kokkos::Iterate iterate = Kokkos::Iterate::Left; }; -template<> +template <> struct ViewFillLayoutSelector { static const Kokkos::Iterate iterate = Kokkos::Iterate::Right; }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos -#include +#include namespace Kokkos { namespace Impl { -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; typedef typename ViewType::non_const_value_type ST; ViewFill(const ViewType&, const ST&); }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; typedef typename ViewType::non_const_value_type ST; ViewFill(const ViewType&, const ST&); KOKKOS_INLINE_FUNCTION - void operator() (const iType&) const; + void operator()(const iType&) const; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; typedef typename ViewType::non_const_value_type ST; ViewFill(const ViewType&, const ST&); KOKKOS_INLINE_FUNCTION - void operator() (const iType&, const iType&) const; + void operator()(const iType&, const iType&) const; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; typedef typename ViewType::non_const_value_type ST; ViewFill(const ViewType&, const ST&); KOKKOS_INLINE_FUNCTION - void operator() (const iType&, const iType&, const iType&) const; + void operator()(const iType&, const iType&, const iType&) const; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; typedef typename ViewType::non_const_value_type ST; ViewFill(const ViewType&, const ST&); KOKKOS_INLINE_FUNCTION - void operator() (const iType&, const iType&, const iType&, const iType&) const; + void operator()(const iType&, const iType&, const iType&, const iType&) const; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; typedef typename ViewType::non_const_value_type ST; ViewFill(const ViewType&, const ST&); KOKKOS_INLINE_FUNCTION - void operator() (const iType&, const iType&, const iType&, const iType&, - const iType&) const; + void operator()(const iType&, const iType&, const iType&, const iType&, + const iType&) const; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; typedef typename ViewType::non_const_value_type ST; ViewFill(const ViewType&, const ST&); KOKKOS_INLINE_FUNCTION - void operator() (const iType&, const iType&, const iType&, const iType&, - const iType&, const iType&) const; + void operator()(const iType&, const iType&, const iType&, const iType&, + const iType&, const iType&) const; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; typedef typename ViewType::non_const_value_type ST; ViewFill(const ViewType&, const ST&); KOKKOS_INLINE_FUNCTION - void operator() (const iType&, const iType&, const iType&, const iType&, - const iType&, const iType&, const iType&) const; + void operator()(const iType&, const iType&, const iType&, const iType&, + const iType&, const iType&, const iType&) const; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; typedef typename ViewType::non_const_value_type ST; ViewFill(const ViewType&, const ST&); KOKKOS_INLINE_FUNCTION - void operator() (const iType&, const iType&, const iType&, const iType&, - const iType&, const iType&, const iType&, const iType&) const; + void operator()(const iType&, const iType&, const iType&, const iType&, + const iType&, const iType&, const iType&, const iType&) const; }; -template -struct ViewFill { +template +struct ViewFill { typedef typename ViewType::non_const_value_type ST; ViewFill(const ViewType& a, const ST& val) { - Kokkos::Impl::DeepCopy< typename ViewType::memory_space, Kokkos::HostSpace >( a.data() , &val, sizeof(ST) ); + Kokkos::Impl::DeepCopy( + a.data(), &val, sizeof(ST)); } }; - -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; - typedef Kokkos::RangePolicy> policy_type; + typedef Kokkos::RangePolicy> policy_type; - ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_):a(a_),val(val_) { + ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_) + : a(a_), val(val_) { ExecSpace().fence(); - Kokkos::parallel_for("Kokkos::ViewFill-1D",policy_type(0,a.extent(0)),*this); + Kokkos::parallel_for("Kokkos::ViewFill-1D", policy_type(0, a.extent(0)), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i) const { - a(i) = val; - }; + void operator()(const iType& i) const { a(i) = val; }; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; - typedef Kokkos::Rank<2,ViewFillLayoutSelector::iterate,ViewFillLayoutSelector::iterate> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; + typedef Kokkos::Rank<2, ViewFillLayoutSelector::iterate, + ViewFillLayoutSelector::iterate> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; - ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_):a(a_),val(val_) { + ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_) + : a(a_), val(val_) { ExecSpace().fence(); Kokkos::parallel_for("Kokkos::ViewFill-2D", - policy_type({0,0},{a.extent(0),a.extent(1)}),*this); + policy_type({0, 0}, {a.extent(0), a.extent(1)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1) const { - a(i0,i1) = val; - }; + void operator()(const iType& i0, const iType& i1) const { a(i0, i1) = val; }; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; - typedef Kokkos::Rank<3,ViewFillLayoutSelector::iterate,ViewFillLayoutSelector::iterate> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; + typedef Kokkos::Rank<3, ViewFillLayoutSelector::iterate, + ViewFillLayoutSelector::iterate> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; - ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_):a(a_),val(val_) { + ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_) + : a(a_), val(val_) { ExecSpace().fence(); - Kokkos::parallel_for("Kokkos::ViewFill-3D", - policy_type({0,0,0},{a.extent(0),a.extent(1),a.extent(2)}),*this); + Kokkos::parallel_for( + "Kokkos::ViewFill-3D", + policy_type({0, 0, 0}, {a.extent(0), a.extent(1), a.extent(2)}), *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i2) const { - a(i0,i1,i2) = val; + void operator()(const iType& i0, const iType& i1, const iType& i2) const { + a(i0, i1, i2) = val; }; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; - typedef Kokkos::Rank<4,ViewFillLayoutSelector::iterate,ViewFillLayoutSelector::iterate> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; + typedef Kokkos::Rank<4, ViewFillLayoutSelector::iterate, + ViewFillLayoutSelector::iterate> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; - ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_):a(a_),val(val_) { + ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_) + : a(a_), val(val_) { ExecSpace().fence(); Kokkos::parallel_for("Kokkos::ViewFill-4D", - policy_type({0,0,0,0},{a.extent(0),a.extent(1),a.extent(2),a.extent(3)}),*this); + policy_type({0, 0, 0, 0}, {a.extent(0), a.extent(1), + a.extent(2), a.extent(3)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i2, const iType& i3) const { - a(i0,i1,i2,i3) = val; + void operator()(const iType& i0, const iType& i1, const iType& i2, + const iType& i3) const { + a(i0, i1, i2, i3) = val; }; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; - typedef Kokkos::Rank<5,ViewFillLayoutSelector::iterate,ViewFillLayoutSelector::iterate> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; + typedef Kokkos::Rank<5, ViewFillLayoutSelector::iterate, + ViewFillLayoutSelector::iterate> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; - ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_):a(a_),val(val_) { + ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_) + : a(a_), val(val_) { ExecSpace().fence(); - Kokkos::parallel_for("Kokkos::ViewFill-5D", - policy_type({0,0,0,0,0},{a.extent(0),a.extent(1),a.extent(2),a.extent(3),a.extent(4)}),*this); + Kokkos::parallel_for( + "Kokkos::ViewFill-5D", + policy_type({0, 0, 0, 0, 0}, {a.extent(0), a.extent(1), a.extent(2), + a.extent(3), a.extent(4)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i2, const iType& i3, const iType& i4) const { - a(i0,i1,i2,i3,i4) = val; + void operator()(const iType& i0, const iType& i1, const iType& i2, + const iType& i3, const iType& i4) const { + a(i0, i1, i2, i3, i4) = val; }; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; - typedef Kokkos::Rank<6,ViewFillLayoutSelector::iterate,ViewFillLayoutSelector::iterate> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; + typedef Kokkos::Rank<6, ViewFillLayoutSelector::iterate, + ViewFillLayoutSelector::iterate> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; - ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_):a(a_),val(val_) { + ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_) + : a(a_), val(val_) { ExecSpace().fence(); Kokkos::parallel_for("Kokkos::ViewFill-6D", - policy_type({0,0,0,0,0,0},{a.extent(0),a.extent(1),a.extent(2),a.extent(3),a.extent(4),a.extent(5)}),*this); + policy_type({0, 0, 0, 0, 0, 0}, + {a.extent(0), a.extent(1), a.extent(2), + a.extent(3), a.extent(4), a.extent(5)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i2, const iType& i3, const iType& i4, const iType& i5) const { - a(i0,i1,i2,i3,i4,i5) = val; + void operator()(const iType& i0, const iType& i1, const iType& i2, + const iType& i3, const iType& i4, const iType& i5) const { + a(i0, i1, i2, i3, i4, i5) = val; }; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; - typedef Kokkos::Rank<6,ViewFillLayoutSelector::iterate,ViewFillLayoutSelector::iterate> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; + typedef Kokkos::Rank<6, ViewFillLayoutSelector::iterate, + ViewFillLayoutSelector::iterate> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; - ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_):a(a_),val(val_) { + ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_) + : a(a_), val(val_) { ExecSpace().fence(); Kokkos::parallel_for("Kokkos::ViewFill-7D", - policy_type({0,0,0,0,0,0},{a.extent(0),a.extent(1),a.extent(2),a.extent(3), - a.extent(5),a.extent(6)}),*this); + policy_type({0, 0, 0, 0, 0, 0}, + {a.extent(0), a.extent(1), a.extent(2), + a.extent(3), a.extent(5), a.extent(6)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i3, - const iType& i4, const iType& i5, const iType& i6) const { - for(iType i2=0; i2 -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; - typedef Kokkos::Rank<6,ViewFillLayoutSelector::iterate,ViewFillLayoutSelector::iterate> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; + typedef Kokkos::Rank<6, ViewFillLayoutSelector::iterate, + ViewFillLayoutSelector::iterate> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; - ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_):a(a_),val(val_) { + ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_) + : a(a_), val(val_) { ExecSpace().fence(); Kokkos::parallel_for("Kokkos::ViewFill-8D", - policy_type({0,0,0,0,0,0},{a.extent(0),a.extent(1),a.extent(3), - a.extent(5),a.extent(6),a.extent(7)}),*this); + policy_type({0, 0, 0, 0, 0, 0}, + {a.extent(0), a.extent(1), a.extent(3), + a.extent(5), a.extent(6), a.extent(7)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i3, - const iType& i5, const iType& i6, const iType& i7) const { - for(iType i2=0; i2 -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; ViewCopy(const ViewTypeA&, const ViewTypeB&); KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0) const; + void operator()(const iType& i0) const; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; ViewCopy(const ViewTypeA&, const ViewTypeB&); KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0,const iType& i1) const; + void operator()(const iType& i0, const iType& i1) const; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; ViewCopy(const ViewTypeA&, const ViewTypeB&); KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0,const iType& i1,const iType& i2) const; + void operator()(const iType& i0, const iType& i1, const iType& i2) const; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; ViewCopy(const ViewTypeA&, const ViewTypeB&); KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0,const iType& i1,const iType& i2,const iType& i3) const; + void operator()(const iType& i0, const iType& i1, const iType& i2, + const iType& i3) const; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; ViewCopy(const ViewTypeA&, const ViewTypeB&); KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0,const iType& i1,const iType& i2,const iType& i3, - const iType& i4) const; + void operator()(const iType& i0, const iType& i1, const iType& i2, + const iType& i3, const iType& i4) const; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; ViewCopy(const ViewTypeA&, const ViewTypeB&); KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0,const iType& i1,const iType& i2,const iType& i3, - const iType& i4,const iType& i5) const; + void operator()(const iType& i0, const iType& i1, const iType& i2, + const iType& i3, const iType& i4, const iType& i5) const; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; ViewCopy(const ViewTypeA&, const ViewTypeB&); KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0,const iType& i1,const iType& i2,const iType& i3, - const iType& i4,const iType& i5,const iType& i6) const; + void operator()(const iType& i0, const iType& i1, const iType& i2, + const iType& i3, const iType& i4, const iType& i5, + const iType& i6) const; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; ViewCopy(const ViewTypeA&, const ViewTypeB&); KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0,const iType& i1,const iType& i2,const iType& i3, - const iType& i4,const iType& i5,const iType& i6,const iType& i7) const; + void operator()(const iType& i0, const iType& i1, const iType& i2, + const iType& i3, const iType& i4, const iType& i5, + const iType& i6, const iType& i7) const; }; - - -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; - typedef Kokkos::RangePolicy> policy_type; + typedef Kokkos::RangePolicy> policy_type; - ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_):a(a_),b(b_) { + ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_) : a(a_), b(b_) { ExecSpace().fence(); - Kokkos::parallel_for("Kokkos::ViewCopy-1D", - policy_type(0,a.extent(0)),*this); + Kokkos::parallel_for("Kokkos::ViewCopy-1D", policy_type(0, a.extent(0)), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0) const { - a(i0) = b(i0); - }; + void operator()(const iType& i0) const { a(i0) = b(i0); }; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::layout_iterate_type_selector::outer_iteration_pattern; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::layout_iterate_type_selector::inner_iteration_pattern; - typedef Kokkos::Rank<2,outer_iteration_pattern,inner_iteration_pattern> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; - - ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_):a(a_),b(b_) { + static const Kokkos::Iterate outer_iteration_pattern = + Kokkos::layout_iterate_type_selector::outer_iteration_pattern; + static const Kokkos::Iterate inner_iteration_pattern = + Kokkos::layout_iterate_type_selector::inner_iteration_pattern; + typedef Kokkos::Rank<2, outer_iteration_pattern, inner_iteration_pattern> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; + + ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_) : a(a_), b(b_) { ExecSpace().fence(); Kokkos::parallel_for("Kokkos::ViewCopy-2D", - policy_type({0,0},{a.extent(0),a.extent(1)}),*this); + policy_type({0, 0}, {a.extent(0), a.extent(1)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1) const { - a(i0,i1) = b(i0,i1); + void operator()(const iType& i0, const iType& i1) const { + a(i0, i1) = b(i0, i1); }; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::layout_iterate_type_selector::outer_iteration_pattern; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::layout_iterate_type_selector::inner_iteration_pattern; - typedef Kokkos::Rank<3,outer_iteration_pattern,inner_iteration_pattern> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; - - ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_):a(a_),b(b_) { + static const Kokkos::Iterate outer_iteration_pattern = + Kokkos::layout_iterate_type_selector::outer_iteration_pattern; + static const Kokkos::Iterate inner_iteration_pattern = + Kokkos::layout_iterate_type_selector::inner_iteration_pattern; + typedef Kokkos::Rank<3, outer_iteration_pattern, inner_iteration_pattern> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; + + ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_) : a(a_), b(b_) { ExecSpace().fence(); - Kokkos::parallel_for("Kokkos::ViewCopy-3D", - policy_type({0,0,0},{a.extent(0),a.extent(1),a.extent(2)}),*this); + Kokkos::parallel_for( + "Kokkos::ViewCopy-3D", + policy_type({0, 0, 0}, {a.extent(0), a.extent(1), a.extent(2)}), *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i2) const { - a(i0,i1,i2) = b(i0,i1,i2); + void operator()(const iType& i0, const iType& i1, const iType& i2) const { + a(i0, i1, i2) = b(i0, i1, i2); }; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::layout_iterate_type_selector::outer_iteration_pattern; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::layout_iterate_type_selector::inner_iteration_pattern; - typedef Kokkos::Rank<4,outer_iteration_pattern,inner_iteration_pattern> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; - - ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_):a(a_),b(b_) { + static const Kokkos::Iterate outer_iteration_pattern = + Kokkos::layout_iterate_type_selector::outer_iteration_pattern; + static const Kokkos::Iterate inner_iteration_pattern = + Kokkos::layout_iterate_type_selector::inner_iteration_pattern; + typedef Kokkos::Rank<4, outer_iteration_pattern, inner_iteration_pattern> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; + + ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_) : a(a_), b(b_) { ExecSpace().fence(); Kokkos::parallel_for("Kokkos::ViewCopy-4D", - policy_type({0,0,0,0},{a.extent(0),a.extent(1),a.extent(2), - a.extent(3)}),*this); + policy_type({0, 0, 0, 0}, {a.extent(0), a.extent(1), + a.extent(2), a.extent(3)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i2, - const iType& i3) const { - a(i0,i1,i2,i3) = b(i0,i1,i2,i3); + void operator()(const iType& i0, const iType& i1, const iType& i2, + const iType& i3) const { + a(i0, i1, i2, i3) = b(i0, i1, i2, i3); }; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::layout_iterate_type_selector::outer_iteration_pattern; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::layout_iterate_type_selector::inner_iteration_pattern; - typedef Kokkos::Rank<5,outer_iteration_pattern,inner_iteration_pattern> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; - - ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_):a(a_),b(b_) { + static const Kokkos::Iterate outer_iteration_pattern = + Kokkos::layout_iterate_type_selector::outer_iteration_pattern; + static const Kokkos::Iterate inner_iteration_pattern = + Kokkos::layout_iterate_type_selector::inner_iteration_pattern; + typedef Kokkos::Rank<5, outer_iteration_pattern, inner_iteration_pattern> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; + + ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_) : a(a_), b(b_) { ExecSpace().fence(); - Kokkos::parallel_for("Kokkos::ViewCopy-5D", - policy_type({0,0,0,0,0},{a.extent(0),a.extent(1),a.extent(2), - a.extent(3),a.extent(4)}),*this); + Kokkos::parallel_for( + "Kokkos::ViewCopy-5D", + policy_type({0, 0, 0, 0, 0}, {a.extent(0), a.extent(1), a.extent(2), + a.extent(3), a.extent(4)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i2, - const iType& i3, const iType& i4) const { - a(i0,i1,i2,i3,i4) = b(i0,i1,i2,i3,i4); + void operator()(const iType& i0, const iType& i1, const iType& i2, + const iType& i3, const iType& i4) const { + a(i0, i1, i2, i3, i4) = b(i0, i1, i2, i3, i4); }; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::layout_iterate_type_selector::outer_iteration_pattern; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::layout_iterate_type_selector::inner_iteration_pattern; - typedef Kokkos::Rank<6,outer_iteration_pattern,inner_iteration_pattern> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; - - ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_):a(a_),b(b_) { + static const Kokkos::Iterate outer_iteration_pattern = + Kokkos::layout_iterate_type_selector::outer_iteration_pattern; + static const Kokkos::Iterate inner_iteration_pattern = + Kokkos::layout_iterate_type_selector::inner_iteration_pattern; + typedef Kokkos::Rank<6, outer_iteration_pattern, inner_iteration_pattern> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; + + ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_) : a(a_), b(b_) { ExecSpace().fence(); Kokkos::parallel_for("Kokkos::ViewCopy-6D", - policy_type({0,0,0,0,0,0},{a.extent(0),a.extent(1),a.extent(2), - a.extent(3),a.extent(4),a.extent(5)}),*this); + policy_type({0, 0, 0, 0, 0, 0}, + {a.extent(0), a.extent(1), a.extent(2), + a.extent(3), a.extent(4), a.extent(5)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i2, - const iType& i3, const iType& i4, const iType& i5) const { - a(i0,i1,i2,i3,i4,i5) = b(i0,i1,i2,i3,i4,i5); + void operator()(const iType& i0, const iType& i1, const iType& i2, + const iType& i3, const iType& i4, const iType& i5) const { + a(i0, i1, i2, i3, i4, i5) = b(i0, i1, i2, i3, i4, i5); }; }; - -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::layout_iterate_type_selector::outer_iteration_pattern; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::layout_iterate_type_selector::inner_iteration_pattern; - typedef Kokkos::Rank<6,outer_iteration_pattern,inner_iteration_pattern> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; - - ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_):a(a_),b(b_) { + static const Kokkos::Iterate outer_iteration_pattern = + Kokkos::layout_iterate_type_selector::outer_iteration_pattern; + static const Kokkos::Iterate inner_iteration_pattern = + Kokkos::layout_iterate_type_selector::inner_iteration_pattern; + typedef Kokkos::Rank<6, outer_iteration_pattern, inner_iteration_pattern> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; + + ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_) : a(a_), b(b_) { ExecSpace().fence(); Kokkos::parallel_for("Kokkos::ViewCopy-7D", - policy_type({0,0,0,0,0,0},{a.extent(0),a.extent(1),a.extent(3), - a.extent(4),a.extent(5),a.extent(6)}),*this); + policy_type({0, 0, 0, 0, 0, 0}, + {a.extent(0), a.extent(1), a.extent(3), + a.extent(4), a.extent(5), a.extent(6)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i3, - const iType& i4, const iType& i5, const iType& i6) const { - for(iType i2=0; i2 -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::layout_iterate_type_selector::outer_iteration_pattern; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::layout_iterate_type_selector::inner_iteration_pattern; - typedef Kokkos::Rank<6,outer_iteration_pattern,inner_iteration_pattern> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; - - ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_):a(a_),b(b_) { + static const Kokkos::Iterate outer_iteration_pattern = + Kokkos::layout_iterate_type_selector::outer_iteration_pattern; + static const Kokkos::Iterate inner_iteration_pattern = + Kokkos::layout_iterate_type_selector::inner_iteration_pattern; + typedef Kokkos::Rank<6, outer_iteration_pattern, inner_iteration_pattern> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; + + ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_) : a(a_), b(b_) { ExecSpace().fence(); Kokkos::parallel_for("Kokkos::ViewCopy-8D", - policy_type({0,0,0,0,0,0},{a.extent(0),a.extent(1),a.extent(3), - a.extent(5),a.extent(6),a.extent(7)}),*this); + policy_type({0, 0, 0, 0, 0, 0}, + {a.extent(0), a.extent(1), a.extent(3), + a.extent(5), a.extent(6), a.extent(7)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i3, - const iType& i5, const iType& i6, const iType& i7) const { - for(iType i2=0; i2 +#include namespace Kokkos { namespace Impl { -template +template void view_copy(const DstType& dst, const SrcType& src) { typedef typename DstType::execution_space dst_execution_space; typedef typename SrcType::execution_space src_execution_space; typedef typename DstType::memory_space dst_memory_space; typedef typename SrcType::memory_space src_memory_space; - enum { DstExecCanAccessSrc = - Kokkos::Impl::SpaceAccessibility< dst_execution_space , src_memory_space >::accessible }; + enum { + DstExecCanAccessSrc = + Kokkos::Impl::SpaceAccessibility::accessible + }; - enum { SrcExecCanAccessDst = - Kokkos::Impl::SpaceAccessibility< src_execution_space , dst_memory_space >::accessible }; + enum { + SrcExecCanAccessDst = + Kokkos::Impl::SpaceAccessibility::accessible + }; - if( ! DstExecCanAccessSrc && ! SrcExecCanAccessDst) { - std::string message("Error: Kokkos::deep_copy with no available copy mechanism: "); - message += src.label(); message += " to "; + if (!DstExecCanAccessSrc && !SrcExecCanAccessDst) { + std::string message( + "Error: Kokkos::deep_copy with no available copy mechanism: "); + message += src.label(); + message += " to "; message += dst.label(); Kokkos::Impl::throw_runtime_exception(message); } // Figure out iteration order in case we need it - int64_t strides[DstType::Rank+1]; + int64_t strides[DstType::Rank + 1]; dst.stride(strides); Kokkos::Iterate iterate; - if ( Kokkos::is_layouttiled::value ) { - iterate = Kokkos::layout_iterate_type_selector::outer_iteration_pattern; - } else if ( std::is_same::value ) { + if (Kokkos::is_layouttiled::value) { + iterate = Kokkos::layout_iterate_type_selector< + typename DstType::array_layout>::outer_iteration_pattern; + } else if (std::is_same::value) { iterate = Kokkos::Iterate::Right; - } else if ( std::is_same::value ) { + } else if (std::is_same::value) { iterate = Kokkos::Iterate::Left; - } else if ( std::is_same::value ) { - if( strides[0] > strides[DstType::Rank-1] ) + } else if (std::is_same::value) { + if (strides[0] > strides[DstType::Rank - 1]) iterate = Kokkos::Iterate::Right; else iterate = Kokkos::Iterate::Left; } else { - if( std::is_same::value ) + if (std::is_same::value) iterate = Kokkos::Iterate::Right; else iterate = Kokkos::Iterate::Left; } - if( (dst.span() >= size_t(std::numeric_limits::max())) || - (src.span() >= size_t(std::numeric_limits::max())) ){ - if(DstExecCanAccessSrc) { - if(iterate == Kokkos::Iterate::Right) - Kokkos::Impl::ViewCopy< typename DstType::uniform_runtime_nomemspace_type, typename SrcType::uniform_runtime_const_nomemspace_type, Kokkos::LayoutRight, dst_execution_space, - DstType::Rank, int64_t >( dst , src ); + if ((dst.span() >= size_t(std::numeric_limits::max())) || + (src.span() >= size_t(std::numeric_limits::max()))) { + if (DstExecCanAccessSrc) { + if (iterate == Kokkos::Iterate::Right) + Kokkos::Impl::ViewCopy< + typename DstType::uniform_runtime_nomemspace_type, + typename SrcType::uniform_runtime_const_nomemspace_type, + Kokkos::LayoutRight, dst_execution_space, DstType::Rank, int64_t>( + dst, src); else - Kokkos::Impl::ViewCopy< typename DstType::uniform_runtime_nomemspace_type, typename SrcType::uniform_runtime_const_nomemspace_type, Kokkos::LayoutLeft, dst_execution_space, - DstType::Rank, int64_t >( dst , src ); + Kokkos::Impl::ViewCopy< + typename DstType::uniform_runtime_nomemspace_type, + typename SrcType::uniform_runtime_const_nomemspace_type, + Kokkos::LayoutLeft, dst_execution_space, DstType::Rank, int64_t>( + dst, src); } else { - if(iterate == Kokkos::Iterate::Right) - Kokkos::Impl::ViewCopy< typename DstType::uniform_runtime_nomemspace_type, typename SrcType::uniform_runtime_const_nomemspace_type, Kokkos::LayoutRight, src_execution_space, - DstType::Rank, int64_t >( dst , src ); + if (iterate == Kokkos::Iterate::Right) + Kokkos::Impl::ViewCopy< + typename DstType::uniform_runtime_nomemspace_type, + typename SrcType::uniform_runtime_const_nomemspace_type, + Kokkos::LayoutRight, src_execution_space, DstType::Rank, int64_t>( + dst, src); else - Kokkos::Impl::ViewCopy< typename DstType::uniform_runtime_nomemspace_type, typename SrcType::uniform_runtime_const_nomemspace_type, Kokkos::LayoutLeft, src_execution_space, - DstType::Rank, int64_t >( dst , src ); + Kokkos::Impl::ViewCopy< + typename DstType::uniform_runtime_nomemspace_type, + typename SrcType::uniform_runtime_const_nomemspace_type, + Kokkos::LayoutLeft, src_execution_space, DstType::Rank, int64_t>( + dst, src); } } else { - if(DstExecCanAccessSrc) { - if(iterate == Kokkos::Iterate::Right) - Kokkos::Impl::ViewCopy< typename DstType::uniform_runtime_nomemspace_type, typename SrcType::uniform_runtime_const_nomemspace_type, Kokkos::LayoutRight, dst_execution_space, - DstType::Rank, int >( dst , src ); + if (DstExecCanAccessSrc) { + if (iterate == Kokkos::Iterate::Right) + Kokkos::Impl::ViewCopy< + typename DstType::uniform_runtime_nomemspace_type, + typename SrcType::uniform_runtime_const_nomemspace_type, + Kokkos::LayoutRight, dst_execution_space, DstType::Rank, int>(dst, + src); else - Kokkos::Impl::ViewCopy< typename DstType::uniform_runtime_nomemspace_type, typename SrcType::uniform_runtime_const_nomemspace_type, Kokkos::LayoutLeft, dst_execution_space, - DstType::Rank, int >( dst , src ); + Kokkos::Impl::ViewCopy< + typename DstType::uniform_runtime_nomemspace_type, + typename SrcType::uniform_runtime_const_nomemspace_type, + Kokkos::LayoutLeft, dst_execution_space, DstType::Rank, int>(dst, + src); } else { - if(iterate == Kokkos::Iterate::Right) - Kokkos::Impl::ViewCopy< typename DstType::uniform_runtime_nomemspace_type, typename SrcType::uniform_runtime_const_nomemspace_type, Kokkos::LayoutRight, src_execution_space, - DstType::Rank, int >( dst , src ); + if (iterate == Kokkos::Iterate::Right) + Kokkos::Impl::ViewCopy< + typename DstType::uniform_runtime_nomemspace_type, + typename SrcType::uniform_runtime_const_nomemspace_type, + Kokkos::LayoutRight, src_execution_space, DstType::Rank, int>(dst, + src); else - Kokkos::Impl::ViewCopy< typename DstType::uniform_runtime_nomemspace_type, typename SrcType::uniform_runtime_const_nomemspace_type, Kokkos::LayoutLeft, src_execution_space, - DstType::Rank, int >( dst , src ); + Kokkos::Impl::ViewCopy< + typename DstType::uniform_runtime_nomemspace_type, + typename SrcType::uniform_runtime_const_nomemspace_type, + Kokkos::LayoutLeft, src_execution_space, DstType::Rank, int>(dst, + src); } - } } -template +template struct CommonSubview; -template -struct CommonSubview { - typedef typename Kokkos::Subview dst_subview_type; - typedef typename Kokkos::Subview src_subview_type; +template +struct CommonSubview { + typedef typename Kokkos::Subview dst_subview_type; + typedef typename Kokkos::Subview src_subview_type; dst_subview_type dst_sub; src_subview_type src_sub; - CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, Args... ): - dst_sub(dst,arg0),src_sub(src,arg0) {} + CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, + Args...) + : dst_sub(dst, arg0), src_sub(src, arg0) {} }; -template -struct CommonSubview { - typedef typename Kokkos::Subview dst_subview_type; - typedef typename Kokkos::Subview src_subview_type; +template +struct CommonSubview { + typedef typename Kokkos::Subview dst_subview_type; + typedef typename Kokkos::Subview src_subview_type; dst_subview_type dst_sub; src_subview_type src_sub; - CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, const Arg1& arg1, Args... ): - dst_sub(dst,arg0,arg1),src_sub(src,arg0,arg1) {} + CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, + const Arg1& arg1, Args...) + : dst_sub(dst, arg0, arg1), src_sub(src, arg0, arg1) {} }; -template -struct CommonSubview { - typedef typename Kokkos::Subview dst_subview_type; - typedef typename Kokkos::Subview src_subview_type; +template +struct CommonSubview { + typedef typename Kokkos::Subview dst_subview_type; + typedef typename Kokkos::Subview src_subview_type; dst_subview_type dst_sub; src_subview_type src_sub; - CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, const Arg1& arg1, - const Arg2& arg2, Args... ): - dst_sub(dst,arg0,arg1,arg2),src_sub(src,arg0,arg1,arg2) {} + CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, + const Arg1& arg1, const Arg2& arg2, Args...) + : dst_sub(dst, arg0, arg1, arg2), src_sub(src, arg0, arg1, arg2) {} }; -template -struct CommonSubview { - typedef typename Kokkos::Subview dst_subview_type; - typedef typename Kokkos::Subview src_subview_type; +template +struct CommonSubview { + typedef typename Kokkos::Subview + dst_subview_type; + typedef typename Kokkos::Subview + src_subview_type; dst_subview_type dst_sub; src_subview_type src_sub; - CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, const Arg1& arg1, - const Arg2& arg2, const Arg3& arg3, - const Args ...): - dst_sub(dst,arg0,arg1,arg2,arg3),src_sub(src,arg0,arg1,arg2,arg3) {} + CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, + const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, + const Args...) + : dst_sub(dst, arg0, arg1, arg2, arg3), + src_sub(src, arg0, arg1, arg2, arg3) {} }; -template -struct CommonSubview { - typedef typename Kokkos::Subview dst_subview_type; - typedef typename Kokkos::Subview src_subview_type; +template +struct CommonSubview { + typedef typename Kokkos::Subview + dst_subview_type; + typedef typename Kokkos::Subview + src_subview_type; dst_subview_type dst_sub; src_subview_type src_sub; - CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, const Arg1& arg1, - const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, - const Args ...): - dst_sub(dst,arg0,arg1,arg2,arg3,arg4),src_sub(src,arg0,arg1,arg2,arg3,arg4) {} + CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, + const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, + const Arg4& arg4, const Args...) + : dst_sub(dst, arg0, arg1, arg2, arg3, arg4), + src_sub(src, arg0, arg1, arg2, arg3, arg4) {} }; -template -struct CommonSubview { - typedef typename Kokkos::Subview dst_subview_type; - typedef typename Kokkos::Subview src_subview_type; +template +struct CommonSubview { + typedef typename Kokkos::Subview + dst_subview_type; + typedef typename Kokkos::Subview + src_subview_type; dst_subview_type dst_sub; src_subview_type src_sub; - CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, const Arg1& arg1, - const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5, - const Args ...): - dst_sub(dst,arg0,arg1,arg2,arg3,arg4,arg5),src_sub(src,arg0,arg1,arg2,arg3,arg4,arg5) {} + CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, + const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, + const Arg4& arg4, const Arg5& arg5, const Args...) + : dst_sub(dst, arg0, arg1, arg2, arg3, arg4, arg5), + src_sub(src, arg0, arg1, arg2, arg3, arg4, arg5) {} }; -template -struct CommonSubview { - typedef typename Kokkos::Subview dst_subview_type; - typedef typename Kokkos::Subview src_subview_type; +template +struct CommonSubview { + typedef typename Kokkos::Subview + dst_subview_type; + typedef typename Kokkos::Subview + src_subview_type; dst_subview_type dst_sub; src_subview_type src_sub; - CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, const Arg1& arg1, - const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5, - const Arg6& arg6, Args...): - dst_sub(dst,arg0,arg1,arg2,arg3,arg4,arg5,arg6),src_sub(src,arg0,arg1,arg2,arg3,arg4,arg5,arg6) {} + CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, + const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, + const Arg4& arg4, const Arg5& arg5, const Arg6& arg6, Args...) + : dst_sub(dst, arg0, arg1, arg2, arg3, arg4, arg5, arg6), + src_sub(src, arg0, arg1, arg2, arg3, arg4, arg5, arg6) {} }; -template -struct CommonSubview { - typedef typename Kokkos::Subview dst_subview_type; - typedef typename Kokkos::Subview src_subview_type; +template +struct CommonSubview { + typedef typename Kokkos::Subview + dst_subview_type; + typedef typename Kokkos::Subview + src_subview_type; dst_subview_type dst_sub; src_subview_type src_sub; - CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, const Arg1& arg1, - const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5, - const Arg6& arg6, const Arg7& arg7): - dst_sub(dst,arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7),src_sub(src,arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7) {} + CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, + const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, + const Arg4& arg4, const Arg5& arg5, const Arg6& arg6, + const Arg7& arg7) + : dst_sub(dst, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7), + src_sub(src, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) {} }; - -template +template struct ViewRemap; -template -struct ViewRemap { - typedef Kokkos::pair p_type; +template +struct ViewRemap { + typedef Kokkos::pair p_type; ViewRemap(const DstType& dst, const SrcType& src) { - if(dst.extent(0) == src.extent(0)) { - view_copy(dst,src); + if (dst.extent(0) == src.extent(0)) { + view_copy(dst, src); } else { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + typedef CommonSubview sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } }; -template -struct ViewRemap { - typedef Kokkos::pair p_type; +template +struct ViewRemap { + typedef Kokkos::pair p_type; ViewRemap(const DstType& dst, const SrcType& src) { - if(dst.extent(0) == src.extent(0)) { - if(dst.extent(1) == src.extent(1)) { - view_copy(dst,src); + if (dst.extent(0) == src.extent(0)) { + if (dst.extent(1) == src.extent(1)) { + view_copy(dst, src); } else { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL,ext1); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } else { - if(dst.extent(1) == src.extent(1)) { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0,Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + if (dst.extent(1) == src.extent(1)) { + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, Kokkos::ALL); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0,ext1); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } } }; -template -struct ViewRemap { - typedef Kokkos::pair p_type; +template +struct ViewRemap { + typedef Kokkos::pair p_type; ViewRemap(const DstType& dst, const SrcType& src) { - if(dst.extent(0) == src.extent(0)) { - if(dst.extent(2) == src.extent(2)) { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL,ext1,Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + if (dst.extent(0) == src.extent(0)) { + if (dst.extent(2) == src.extent(2)) { + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, + Kokkos::ALL); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL,ext1,ext2); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, ext2); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } else { - if(dst.extent(2) == src.extent(2)) { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0,ext1,Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + if (dst.extent(2) == src.extent(2)) { + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, Kokkos::ALL); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0,ext1,ext2); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, ext2); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } } }; -template -struct ViewRemap { - typedef Kokkos::pair p_type; +template +struct ViewRemap { + typedef Kokkos::pair p_type; ViewRemap(const DstType& dst, const SrcType& src) { - if(dst.extent(0) == src.extent(0)) { - if(dst.extent(3) == src.extent(3)) { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL, - ext1,ext2, + if (dst.extent(0) == src.extent(0)) { + if (dst.extent(3) == src.extent(3)) { + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, ext2, Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL, - ext1,ext2, - ext3); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, ext2, ext3); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } else { - if(dst.extent(7) == src.extent(7)) { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0, - ext1,ext2, - Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + if (dst.extent(7) == src.extent(7)) { + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, ext2, Kokkos::ALL); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0, - ext1,ext2, - ext3); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, ext2, ext3); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } } }; -template -struct ViewRemap { - typedef Kokkos::pair p_type; +template +struct ViewRemap { + typedef Kokkos::pair p_type; ViewRemap(const DstType& dst, const SrcType& src) { - if(dst.extent(0) == src.extent(0)) { - if(dst.extent(4) == src.extent(4)) { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL, - ext1,ext2,ext3, + if (dst.extent(0) == src.extent(0)) { + if (dst.extent(4) == src.extent(4)) { + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, ext2, ext3, Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL, - ext1,ext2,ext3, + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, ext2, ext3, ext4); - view_copy(common_subview.dst_sub,common_subview.src_sub); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } else { - if(dst.extent(4) == src.extent(4)) { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0, - ext1,ext2,ext3, + if (dst.extent(4) == src.extent(4)) { + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, ext2, ext3, Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0, - ext1,ext2,ext3, - ext4); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, ext2, ext3, ext4); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } } }; -template -struct ViewRemap { - typedef Kokkos::pair p_type; +template +struct ViewRemap { + typedef Kokkos::pair p_type; ViewRemap(const DstType& dst, const SrcType& src) { - if(dst.extent(0) == src.extent(0)) { - if(dst.extent(5) == src.extent(5)) { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL, - ext1,ext2,ext3,ext4, - Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + if (dst.extent(0) == src.extent(0)) { + if (dst.extent(5) == src.extent(5)) { + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, ext2, ext3, + ext4, Kokkos::ALL); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - p_type ext5(0,std::min(dst.extent(5),src.extent(5))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL, - ext1,ext2,ext3,ext4, - ext5); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + p_type ext5(0, std::min(dst.extent(5), src.extent(5))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, ext2, ext3, + ext4, ext5); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } else { - if(dst.extent(5) == src.extent(5)) { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0, - ext1,ext2,ext3,ext4, + if (dst.extent(5) == src.extent(5)) { + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, ext2, ext3, ext4, Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - p_type ext5(0,std::min(dst.extent(5),src.extent(5))); - - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0, - ext1,ext2,ext3,ext4, + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + p_type ext5(0, std::min(dst.extent(5), src.extent(5))); + + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, ext2, ext3, ext4, ext5); - view_copy(common_subview.dst_sub,common_subview.src_sub); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } } }; -template -struct ViewRemap { - typedef Kokkos::pair p_type; +template +struct ViewRemap { + typedef Kokkos::pair p_type; ViewRemap(const DstType& dst, const SrcType& src) { - if(dst.extent(0) == src.extent(0)) { - if(dst.extent(6) == src.extent(6)) { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - p_type ext5(0,std::min(dst.extent(5),src.extent(5))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL, - ext1,ext2,ext3,ext4,ext5, - Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + if (dst.extent(0) == src.extent(0)) { + if (dst.extent(6) == src.extent(6)) { + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + p_type ext5(0, std::min(dst.extent(5), src.extent(5))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, ext2, ext3, + ext4, ext5, Kokkos::ALL); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - p_type ext5(0,std::min(dst.extent(5),src.extent(5))); - p_type ext6(0,std::min(dst.extent(6),src.extent(6))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL, - ext1,ext2,ext3,ext4,ext5, - ext6); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + p_type ext5(0, std::min(dst.extent(5), src.extent(5))); + p_type ext6(0, std::min(dst.extent(6), src.extent(6))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, ext2, ext3, + ext4, ext5, ext6); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } else { - if(dst.extent(6) == src.extent(6)) { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - p_type ext5(0,std::min(dst.extent(5),src.extent(5))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0, - ext1,ext2,ext3,ext4,ext5, - Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + if (dst.extent(6) == src.extent(6)) { + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + p_type ext5(0, std::min(dst.extent(5), src.extent(5))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, ext2, ext3, ext4, + ext5, Kokkos::ALL); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - p_type ext5(0,std::min(dst.extent(5),src.extent(5))); - p_type ext6(0,std::min(dst.extent(6),src.extent(6))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0, - ext1,ext2,ext3,ext4,ext5, - ext6); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + p_type ext5(0, std::min(dst.extent(5), src.extent(5))); + p_type ext6(0, std::min(dst.extent(6), src.extent(6))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, ext2, ext3, ext4, + ext5, ext6); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } } }; -template -struct ViewRemap { - typedef Kokkos::pair p_type; +template +struct ViewRemap { + typedef Kokkos::pair p_type; ViewRemap(const DstType& dst, const SrcType& src) { - if(dst.extent(0) == src.extent(0)) { - if(dst.extent(7) == src.extent(7)) { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - p_type ext5(0,std::min(dst.extent(5),src.extent(5))); - p_type ext6(0,std::min(dst.extent(6),src.extent(6))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL, - ext1,ext2,ext3,ext4,ext5,ext6, - Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + if (dst.extent(0) == src.extent(0)) { + if (dst.extent(7) == src.extent(7)) { + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + p_type ext5(0, std::min(dst.extent(5), src.extent(5))); + p_type ext6(0, std::min(dst.extent(6), src.extent(6))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, ext2, ext3, + ext4, ext5, ext6, Kokkos::ALL); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - p_type ext5(0,std::min(dst.extent(5),src.extent(5))); - p_type ext6(0,std::min(dst.extent(6),src.extent(6))); - p_type ext7(0,std::min(dst.extent(7),src.extent(7))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL, - ext1,ext2,ext3,ext4,ext5,ext6, - ext7); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + p_type ext5(0, std::min(dst.extent(5), src.extent(5))); + p_type ext6(0, std::min(dst.extent(6), src.extent(6))); + p_type ext7(0, std::min(dst.extent(7), src.extent(7))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, ext2, ext3, + ext4, ext5, ext6, ext7); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } else { - if(dst.extent(7) == src.extent(7)) { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - p_type ext5(0,std::min(dst.extent(5),src.extent(5))); - p_type ext6(0,std::min(dst.extent(6),src.extent(6))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0, - ext1,ext2,ext3,ext4,ext5,ext6, - Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + if (dst.extent(7) == src.extent(7)) { + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + p_type ext5(0, std::min(dst.extent(5), src.extent(5))); + p_type ext6(0, std::min(dst.extent(6), src.extent(6))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, ext2, ext3, ext4, + ext5, ext6, Kokkos::ALL); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - p_type ext5(0,std::min(dst.extent(5),src.extent(5))); - p_type ext6(0,std::min(dst.extent(6),src.extent(6))); - p_type ext7(0,std::min(dst.extent(7),src.extent(7))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0, - ext1,ext2,ext3,ext4,ext5,ext6, - ext7); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + p_type ext5(0, std::min(dst.extent(5), src.extent(5))); + p_type ext6(0, std::min(dst.extent(6), src.extent(6))); + p_type ext7(0, std::min(dst.extent(7), src.extent(7))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, ext2, ext3, ext4, + ext5, ext6, ext7); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } } }; -} +} // namespace Impl /** \brief Deep copy a value from Host memory into a view. */ -template< class DT , class ... DP > -inline -void deep_copy - ( const View & dst - , typename ViewTraits::const_value_type & value - , typename std::enable_if< - std::is_same< typename ViewTraits::specialize , void >::value - >::type * = 0 ) -{ - typedef View ViewType; - if(dst.data() == NULL ) { +template +inline void deep_copy( + const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if::specialize, void>::value>::type* = 0) { + typedef View ViewType; + +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::beginDeepCopy( + Kokkos::Profiling::SpaceHandle( + typename ViewType::memory_space().name()), + dst.label(), dst.data(), + Kokkos::Profiling::SpaceHandle(Kokkos::HostSpace().name()), "Scalar", + &value, dst.span() * sizeof(typename ViewType::value_type)); + } +#endif + + if (dst.data() == NULL) { Kokkos::fence(); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif return; } Kokkos::fence(); - static_assert( - std::is_same< typename ViewType::non_const_value_type , - typename ViewType::value_type >::value - , "deep_copy requires non-const type" ); - - // If contiguous we can simply do a 1D flat loop - if(dst.span_is_contiguous()) { - typedef Kokkos::View::value, + "deep_copy requires non-const type"); + + // If contigous we can simply do a 1D flat loop + if (dst.span_is_contiguous()) { + typedef Kokkos::View< + typename ViewType::value_type*, Kokkos::LayoutRight, Kokkos::Device::type>, - Kokkos::MemoryTraits<0> > - ViewTypeFlat; - - ViewTypeFlat dst_flat(dst.data(),dst.size()); - if(dst.span() < std::numeric_limits::max()) { - Kokkos::Impl::ViewFill< ViewTypeFlat , Kokkos::LayoutRight, typename ViewType::execution_space, ViewTypeFlat::Rank, int >( dst_flat , value ); + typename std::conditional< + ViewType::Rank == 0, typename ViewType::memory_space, + Kokkos::AnonymousSpace>::type>, + Kokkos::MemoryTraits<0>> + ViewTypeFlat; + + ViewTypeFlat dst_flat(dst.data(), dst.size()); + if (dst.span() < static_cast(std::numeric_limits::max())) { + Kokkos::Impl::ViewFill(dst_flat, value); } else - Kokkos::Impl::ViewFill< ViewTypeFlat , Kokkos::LayoutRight, typename ViewType::execution_space, ViewTypeFlat::Rank, int64_t >( dst_flat , value ); + Kokkos::Impl::ViewFill(dst_flat, value); Kokkos::fence(); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif return; } // Figure out iteration order to do the ViewFill - int64_t strides[ViewType::Rank+1]; + int64_t strides[ViewType::Rank + 1]; dst.stride(strides); Kokkos::Iterate iterate; - if ( std::is_same::value ) { + if (std::is_same::value) { iterate = Kokkos::Iterate::Right; - } else if ( std::is_same::value ) { + } else if (std::is_same::value) { iterate = Kokkos::Iterate::Left; - } else if ( std::is_same::value ) { - if( strides[0] > strides[ViewType::Rank>0?ViewType::Rank-1:0] ) + } else if (std::is_same::value) { + if (strides[0] > strides[ViewType::Rank > 0 ? ViewType::Rank - 1 : 0]) iterate = Kokkos::Iterate::Right; else iterate = Kokkos::Iterate::Left; } else { - if( std::is_same::value ) + if (std::is_same::value) iterate = Kokkos::Iterate::Right; else iterate = Kokkos::Iterate::Left; } - // Lets call the right ViewFill functor based on integer space needed and iteration type - typedef typename std::conditional::type ViewTypeUniform; - if(dst.span() > std::numeric_limits::max()) { - if(iterate == Kokkos::Iterate::Right) - Kokkos::Impl::ViewFill< ViewTypeUniform, Kokkos::LayoutRight, typename ViewType::execution_space, ViewType::Rank, int64_t >( dst , value ); + // Lets call the right ViewFill functor based on integer space needed and + // iteration type + typedef typename std::conditional< + ViewType::Rank == 0, typename ViewType::uniform_runtime_type, + typename ViewType::uniform_runtime_nomemspace_type>::type ViewTypeUniform; + if (dst.span() > static_cast(std::numeric_limits::max())) { + if (iterate == Kokkos::Iterate::Right) + Kokkos::Impl::ViewFill(dst, value); else - Kokkos::Impl::ViewFill< ViewTypeUniform, Kokkos::LayoutLeft, typename ViewType::execution_space, ViewType::Rank, int64_t >( dst , value ); + Kokkos::Impl::ViewFill(dst, value); } else { - if(iterate == Kokkos::Iterate::Right) - Kokkos::Impl::ViewFill< ViewTypeUniform, Kokkos::LayoutRight, typename ViewType::execution_space, ViewType::Rank, int >( dst , value ); + if (iterate == Kokkos::Iterate::Right) + Kokkos::Impl::ViewFill(dst, value); else - Kokkos::Impl::ViewFill< ViewTypeUniform, Kokkos::LayoutLeft, typename ViewType::execution_space, ViewType::Rank, int >( dst , value ); + Kokkos::Impl::ViewFill(dst, value); } Kokkos::fence(); + +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif } /** \brief Deep copy into a value in Host memory from a view. */ -template< class ST , class ... SP > -inline -void deep_copy - ( typename ViewTraits::non_const_value_type & dst - , const View & src - , typename std::enable_if< - std::is_same< typename ViewTraits::specialize , void >::value - >::type * = 0 ) -{ - static_assert( ViewTraits::rank == 0 - , "ERROR: Non-rank-zero view in deep_copy( value , View )" ); - - if(src.data() == NULL) { +template +inline void deep_copy( + typename ViewTraits::non_const_value_type& dst, + const View& src, + typename std::enable_if::specialize, void>::value>::type* = 0) { + typedef ViewTraits src_traits; + typedef typename src_traits::memory_space src_memory_space; + + static_assert(src_traits::rank == 0, + "ERROR: Non-rank-zero view in deep_copy( value , View )"); + +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::beginDeepCopy( + Kokkos::Profiling::SpaceHandle(Kokkos::HostSpace().name()), "Scalar", + &dst, Kokkos::Profiling::SpaceHandle(src_memory_space().name()), + src.label(), src.data(), + src.span() * sizeof(typename src_traits::value_type)); + } +#endif + + if (src.data() == NULL) { Kokkos::fence(); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif return; } - typedef ViewTraits src_traits ; - typedef typename src_traits::memory_space src_memory_space ; - Kokkos::Impl::DeepCopy< HostSpace , src_memory_space >( & dst , src.data() , sizeof(ST) ); + Kokkos::Impl::DeepCopy(&dst, src.data(), + sizeof(ST)); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif } //---------------------------------------------------------------------------- /** \brief A deep copy between views of compatible type, and rank zero. */ -template< class DT , class ... DP , class ST , class ... SP > -inline -void deep_copy - ( const View & dst - , const View & src - , typename std::enable_if<( - std::is_same< typename ViewTraits::specialize , void >::value && - std::is_same< typename ViewTraits::specialize , void >::value && - ( unsigned(ViewTraits::rank) == unsigned(0) && - unsigned(ViewTraits::rank) == unsigned(0) ) - )>::type * = 0 ) -{ - static_assert( - std::is_same< typename ViewTraits::value_type , - typename ViewTraits::non_const_value_type >::value - , "deep_copy requires matching non-const destination type" ); - - if(dst.data() == NULL && src.data() == NULL) { +template +inline void deep_copy( + const View& dst, const View& src, + typename std::enable_if<( + std::is_same::specialize, void>::value && + std::is_same::specialize, void>::value && + (unsigned(ViewTraits::rank) == unsigned(0) && + unsigned(ViewTraits::rank) == unsigned(0)))>::type* = 0) { + typedef View dst_type; + typedef View src_type; + + typedef typename dst_type::value_type value_type; + typedef typename dst_type::memory_space dst_memory_space; + typedef typename src_type::memory_space src_memory_space; + + static_assert(std::is_same::value, + "deep_copy requires matching non-const destination type"); + +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::beginDeepCopy( + Kokkos::Profiling::SpaceHandle(dst_memory_space().name()), dst.label(), + dst.data(), Kokkos::Profiling::SpaceHandle(src_memory_space().name()), + src.label(), src.data(), + src.span() * sizeof(typename dst_type::value_type)); + } +#endif + + if (dst.data() == NULL && src.data() == NULL) { Kokkos::fence(); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif return; } - typedef View dst_type ; - typedef View src_type ; - - typedef typename dst_type::value_type value_type ; - typedef typename dst_type::memory_space dst_memory_space ; - typedef typename src_type::memory_space src_memory_space ; - Kokkos::fence(); - if ( dst.data() != src.data() ) { - Kokkos::Impl::DeepCopy< dst_memory_space , src_memory_space >( dst.data() , src.data() , sizeof(value_type) ); + if (dst.data() != src.data()) { + Kokkos::Impl::DeepCopy( + dst.data(), src.data(), sizeof(value_type)); Kokkos::fence(); } +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif } //---------------------------------------------------------------------------- -/** \brief A deep copy between views of the default specialization, compatible type, - * same non-zero rank, same contiguous layout. +/** \brief A deep copy between views of the default specialization, compatible + * type, same non-zero rank, same contiguous layout. */ -template< class DT , class ... DP , class ST , class ... SP > -inline -void deep_copy - ( const View & dst - , const View & src - , typename std::enable_if<( - std::is_same< typename ViewTraits::specialize , void >::value && - std::is_same< typename ViewTraits::specialize , void >::value && - ( unsigned(ViewTraits::rank) != 0 || - unsigned(ViewTraits::rank) != 0 ) - )>::type * = 0 ) -{ - typedef View dst_type ; - typedef View src_type ; - - static_assert( - std::is_same< typename dst_type::value_type , - typename dst_type::non_const_value_type >::value - , "deep_copy requires non-const destination type" ); - - static_assert( - ( unsigned(dst_type::rank) == - unsigned(src_type::rank) ) - , "deep_copy requires Views of equal rank" ); - - - typedef typename dst_type::execution_space dst_execution_space ; - typedef typename src_type::execution_space src_execution_space ; - typedef typename dst_type::memory_space dst_memory_space ; - typedef typename src_type::memory_space src_memory_space ; - typedef typename dst_type::value_type dst_value_type ; - typedef typename src_type::value_type src_value_type ; - if(dst.data() == NULL || src.data() == NULL) { +template +inline void deep_copy( + const View& dst, const View& src, + typename std::enable_if<( + std::is_same::specialize, void>::value && + std::is_same::specialize, void>::value && + (unsigned(ViewTraits::rank) != 0 || + unsigned(ViewTraits::rank) != 0))>::type* = 0) { + typedef View dst_type; + typedef View src_type; + typedef typename dst_type::execution_space dst_execution_space; + typedef typename src_type::execution_space src_execution_space; + typedef typename dst_type::memory_space dst_memory_space; + typedef typename src_type::memory_space src_memory_space; + typedef typename dst_type::value_type dst_value_type; + typedef typename src_type::value_type src_value_type; + + static_assert(std::is_same::value, + "deep_copy requires non-const destination type"); + + static_assert((unsigned(dst_type::rank) == unsigned(src_type::rank)), + "deep_copy requires Views of equal rank"); + +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::beginDeepCopy( + Kokkos::Profiling::SpaceHandle(dst_memory_space().name()), dst.label(), + dst.data(), Kokkos::Profiling::SpaceHandle(src_memory_space().name()), + src.label(), src.data(), + src.span() * sizeof(typename dst_type::value_type)); + } +#endif + + if (dst.data() == NULL || src.data() == NULL) { #ifdef KOKKOS_ENABLE_DEPRECATED_CODE // do nothing #else // throw if dimension mismatch - if ( (src.extent(0) != dst.extent(0)) || - (src.extent(1) != dst.extent(1)) || - (src.extent(2) != dst.extent(2)) || - (src.extent(3) != dst.extent(3)) || - (src.extent(4) != dst.extent(4)) || - (src.extent(5) != dst.extent(5)) || - (src.extent(6) != dst.extent(6)) || - (src.extent(7) != dst.extent(7)) - ) { - std::string message("Deprecation Error: Kokkos::deep_copy extents of views don't match: "); - message += dst.label(); message += "("; - for(int r = 0; r::accessible }; + enum { + DstExecCanAccessSrc = + Kokkos::Impl::SpaceAccessibility::accessible + }; - enum { SrcExecCanAccessDst = - Kokkos::Impl::SpaceAccessibility< src_execution_space , dst_memory_space >::accessible }; + enum { + SrcExecCanAccessDst = + Kokkos::Impl::SpaceAccessibility::accessible + }; // Checking for Overlapping Views. dst_value_type* dst_start = dst.data(); dst_value_type* dst_end = dst.data() + dst.span(); src_value_type* src_start = src.data(); src_value_type* src_end = src.data() + src.span(); - if( ((std::ptrdiff_t)dst_start == (std::ptrdiff_t)src_start) && - ((std::ptrdiff_t)dst_end == (std::ptrdiff_t)src_end) && - (dst.span_is_contiguous() && src.span_is_contiguous()) ) { + if (((std::ptrdiff_t)dst_start == (std::ptrdiff_t)src_start) && + ((std::ptrdiff_t)dst_end == (std::ptrdiff_t)src_end) && + (dst.span_is_contiguous() && src.span_is_contiguous())) { Kokkos::fence(); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif return; } - if( ( ( (std::ptrdiff_t)dst_start < (std::ptrdiff_t)src_end ) && ( (std::ptrdiff_t)dst_end > (std::ptrdiff_t)src_start ) ) && - ( ( dst.span_is_contiguous() && src.span_is_contiguous() ))) { + if ((((std::ptrdiff_t)dst_start < (std::ptrdiff_t)src_end) && + ((std::ptrdiff_t)dst_end > (std::ptrdiff_t)src_start)) && + ((dst.span_is_contiguous() && src.span_is_contiguous()))) { std::string message("Error: Kokkos::deep_copy of overlapping views: "); - message += dst.label(); message += "("; - message += std::to_string((std::ptrdiff_t)dst_start); message += ","; - message += std::to_string((std::ptrdiff_t)dst_end); message += ") "; - message += src.label(); message += "("; - message += std::to_string((std::ptrdiff_t)src_start); message += ","; - message += std::to_string((std::ptrdiff_t)src_end); message += ") "; + message += dst.label(); + message += "("; + message += std::to_string((std::ptrdiff_t)dst_start); + message += ","; + message += std::to_string((std::ptrdiff_t)dst_end); + message += ") "; + message += src.label(); + message += "("; + message += std::to_string((std::ptrdiff_t)src_start); + message += ","; + message += std::to_string((std::ptrdiff_t)src_end); + message += ") "; Kokkos::Impl::throw_runtime_exception(message); } // Check for same extents - if ( (src.extent(0) != dst.extent(0)) || - (src.extent(1) != dst.extent(1)) || - (src.extent(2) != dst.extent(2)) || - (src.extent(3) != dst.extent(3)) || - (src.extent(4) != dst.extent(4)) || - (src.extent(5) != dst.extent(5)) || - (src.extent(6) != dst.extent(6)) || - (src.extent(7) != dst.extent(7)) - ) { + if ((src.extent(0) != dst.extent(0)) || (src.extent(1) != dst.extent(1)) || + (src.extent(2) != dst.extent(2)) || (src.extent(3) != dst.extent(3)) || + (src.extent(4) != dst.extent(4)) || (src.extent(5) != dst.extent(5)) || + (src.extent(6) != dst.extent(6)) || (src.extent(7) != dst.extent(7))) { #ifdef KOKKOS_ENABLE_DEPRECATED_CODE Kokkos::fence(); - if ( DstExecCanAccessSrc ) { - // Copying data between views in accessible memory spaces and either non-contiguous or incompatible shape. - Kokkos::Impl::ViewRemap< dst_type , src_type >( dst , src ); - } - else if ( SrcExecCanAccessDst ) { - // Copying data between views in accessible memory spaces and either non-contiguous or incompatible shape. - Kokkos::Impl::ViewRemap< dst_type , src_type , src_execution_space >( dst , src ); - } - else { - Kokkos::Impl::throw_runtime_exception("deep_copy given views that would require a temporary allocation"); + if (DstExecCanAccessSrc) { + // Copying data between views in accessible memory spaces and either + // non-contiguous or incompatible shape. + Kokkos::Impl::ViewRemap(dst, src); + } else if (SrcExecCanAccessDst) { + // Copying data between views in accessible memory spaces and either + // non-contiguous or incompatible shape. + Kokkos::Impl::ViewRemap(dst, + src); + } else { + Kokkos::Impl::throw_runtime_exception( + "deep_copy given views that would require a temporary allocation"); } Kokkos::fence(); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif return; #else - std::string message("Deprecation Error: Kokkos::deep_copy extents of views don't match: "); - message += dst.label(); message += "("; - for(int r = 0; r::value && - ( - std::is_same< typename dst_type::array_layout , - typename src_type::array_layout >::value - || - ( dst_type::rank == 1 && - src_type::rank == 1 ) - ) && - dst.span_is_contiguous() && - src.span_is_contiguous() && - ((dst_type::rank < 1) || (dst.stride_0() == src.stride_0())) && - ((dst_type::rank < 2) || (dst.stride_1() == src.stride_1())) && - ((dst_type::rank < 3) || (dst.stride_2() == src.stride_2())) && - ((dst_type::rank < 4) || (dst.stride_3() == src.stride_3())) && - ((dst_type::rank < 5) || (dst.stride_4() == src.stride_4())) && - ((dst_type::rank < 6) || (dst.stride_5() == src.stride_5())) && - ((dst_type::rank < 7) || (dst.stride_6() == src.stride_6())) && - ((dst_type::rank < 8) || (dst.stride_7() == src.stride_7())) - ) { + // If same type, equal layout, equal dimensions, equal span, and contiguous + // memory then can byte-wise copy + + if (std::is_same::value && + (std::is_same::value || + (dst_type::rank == 1 && src_type::rank == 1)) && + dst.span_is_contiguous() && src.span_is_contiguous() && + ((dst_type::rank < 1) || (dst.stride_0() == src.stride_0())) && + ((dst_type::rank < 2) || (dst.stride_1() == src.stride_1())) && + ((dst_type::rank < 3) || (dst.stride_2() == src.stride_2())) && + ((dst_type::rank < 4) || (dst.stride_3() == src.stride_3())) && + ((dst_type::rank < 5) || (dst.stride_4() == src.stride_4())) && + ((dst_type::rank < 6) || (dst.stride_5() == src.stride_5())) && + ((dst_type::rank < 7) || (dst.stride_6() == src.stride_6())) && + ((dst_type::rank < 8) || (dst.stride_7() == src.stride_7()))) { const size_t nbytes = sizeof(typename dst_type::value_type) * dst.span(); Kokkos::fence(); - if((void*)dst.data()!=(void*)src.data()) { - Kokkos::Impl::DeepCopy< dst_memory_space , src_memory_space > - ( dst.data() , src.data() , nbytes ); + if ((void*)dst.data() != (void*)src.data()) { + Kokkos::Impl::DeepCopy( + dst.data(), src.data(), nbytes); } Kokkos::fence(); } else { @@ -1536,779 +1839,779 @@ void deep_copy Impl::view_copy(dst, src); Kokkos::fence(); } +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- namespace Experimental { -/** \brief A local deep copy between views of the default specialization, compatible type, - * same non-zero rank. +/** \brief A local deep copy between views of the default specialization, + * compatible type, same non-zero rank. */ -template< class TeamType, class DT , class ... DP , class ST , class ... SP > -void KOKKOS_INLINE_FUNCTION local_deep_copy_contiguous(const TeamType& team, const View & dst, const View & src) { - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, src.span()), [&] (const int& i) { - dst.data()[i] = src.data()[i]; - }); +template +void KOKKOS_INLINE_FUNCTION +local_deep_copy_contiguous(const TeamType& team, const View& dst, + const View& src) { + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, src.span()), + [&](const int& i) { dst.data()[i] = src.data()[i]; }); } //---------------------------------------------------------------------------- -template< class DT , class ... DP , class ST , class ... SP > -void KOKKOS_INLINE_FUNCTION local_deep_copy_contiguous(const View & dst, const View & src) { - - for(size_t i=0;i +void KOKKOS_INLINE_FUNCTION local_deep_copy_contiguous( + const View& dst, const View& src) { + for (size_t i = 0; i < src.span(); ++i) { + dst.data()[i] = src.data()[i]; + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP , class ST , class ... SP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 1 && - unsigned(ViewTraits::rank) == 1 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 1 && + unsigned(ViewTraits::rank) == + 1)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0); + const size_t N = dst.extent(0); - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - dst(i) = src(i); - }); - team.team_barrier(); + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), + [&](const int& i) { dst(i) = src(i); }); + team.team_barrier(); } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP , class ST , class ... SP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 2 && - unsigned(ViewTraits::rank) == 2 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 2 && + unsigned(ViewTraits::rank) == + 2)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1); + const size_t N = dst.extent(0) * dst.extent(1); - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,src); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int i1 = i/dst.extent(0); - dst(i0,i1) = src(i0,i1); - }); - team.team_barrier(); - } + if (dst.span_is_contiguous() && src.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, src); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int i1 = i / dst.extent(0); + dst(i0, i1) = src(i0, i1); + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP , class ST , class ... SP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 3 && - unsigned(ViewTraits::rank) == 3 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 3 && + unsigned(ViewTraits::rank) == + 3)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1)*dst.extent(2); + const size_t N = dst.extent(0) * dst.extent(1) * dst.extent(2); - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,src); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int itmp = i/dst.extent(0); - int i1 = itmp%dst.extent(1); - int i2 = itmp/dst.extent(1); - dst(i0,i1,i2) = src(i0,i1,i2); - }); - team.team_barrier(); - } + if (dst.span_is_contiguous() && src.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, src); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int itmp = i / dst.extent(0); + int i1 = itmp % dst.extent(1); + int i2 = itmp / dst.extent(1); + dst(i0, i1, i2) = src(i0, i1, i2); + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP , class ST , class ... SP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 4 && - unsigned(ViewTraits::rank) == 4 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 4 && + unsigned(ViewTraits::rank) == + 4)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1)*dst.extent(2)*dst.extent(3); + const size_t N = + dst.extent(0) * dst.extent(1) * dst.extent(2) * dst.extent(3); - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,src); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int itmp = i/dst.extent(0); - int i1 = itmp%dst.extent(1); - itmp = itmp/dst.extent(1); - int i2 = itmp%dst.extent(2); - int i3 = itmp/dst.extent(2); - dst(i0,i1,i2,i3) = src(i0,i1,i2,i3); - }); - team.team_barrier(); - } + if (dst.span_is_contiguous() && src.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, src); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int itmp = i / dst.extent(0); + int i1 = itmp % dst.extent(1); + itmp = itmp / dst.extent(1); + int i2 = itmp % dst.extent(2); + int i3 = itmp / dst.extent(2); + dst(i0, i1, i2, i3) = src(i0, i1, i2, i3); + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP , class ST , class ... SP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 5 && - unsigned(ViewTraits::rank) == 5 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 5 && + unsigned(ViewTraits::rank) == + 5)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1)*dst.extent(2)*dst.extent(3)*dst.extent(4); + const size_t N = dst.extent(0) * dst.extent(1) * dst.extent(2) * + dst.extent(3) * dst.extent(4); - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,src); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int itmp = i/dst.extent(0); - int i1 = itmp%dst.extent(1); - itmp = itmp/dst.extent(1); - int i2 = itmp%dst.extent(2); - itmp = itmp/dst.extent(2); - int i3 = itmp%dst.extent(3); - int i4 = itmp/dst.extent(3); - dst(i0,i1,i2,i3,i4) = src(i0,i1,i2,i3,i4); - }); - team.team_barrier(); - } + if (dst.span_is_contiguous() && src.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, src); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int itmp = i / dst.extent(0); + int i1 = itmp % dst.extent(1); + itmp = itmp / dst.extent(1); + int i2 = itmp % dst.extent(2); + itmp = itmp / dst.extent(2); + int i3 = itmp % dst.extent(3); + int i4 = itmp / dst.extent(3); + dst(i0, i1, i2, i3, i4) = src(i0, i1, i2, i3, i4); + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP , class ST , class ... SP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 6 && - unsigned(ViewTraits::rank) == 6 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 6 && + unsigned(ViewTraits::rank) == + 6)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1)*dst.extent(2)*dst.extent(3)*dst.extent(4)*dst.extent(5); + const size_t N = dst.extent(0) * dst.extent(1) * dst.extent(2) * + dst.extent(3) * dst.extent(4) * dst.extent(5); - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,src); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int itmp = i/dst.extent(0); - int i1 = itmp%dst.extent(1); - itmp = itmp/dst.extent(1); - int i2 = itmp%dst.extent(2); - itmp = itmp/dst.extent(2); - int i3 = itmp%dst.extent(3); - itmp = itmp/dst.extent(3); - int i4 = itmp%dst.extent(4); - int i5 = itmp/dst.extent(4); - dst(i0,i1,i2,i3,i4,i5) = src(i0,i1,i2,i3,i4,i5); - }); - team.team_barrier(); - } + if (dst.span_is_contiguous() && src.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, src); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int itmp = i / dst.extent(0); + int i1 = itmp % dst.extent(1); + itmp = itmp / dst.extent(1); + int i2 = itmp % dst.extent(2); + itmp = itmp / dst.extent(2); + int i3 = itmp % dst.extent(3); + itmp = itmp / dst.extent(3); + int i4 = itmp % dst.extent(4); + int i5 = itmp / dst.extent(4); + dst(i0, i1, i2, i3, i4, i5) = src(i0, i1, i2, i3, i4, i5); + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP , class ST , class ... SP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 7 && - unsigned(ViewTraits::rank) == 7 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 7 && + unsigned(ViewTraits::rank) == + 7)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1)*dst.extent(2)*dst.extent(3)*dst.extent(4)*dst.extent(5)*dst.extent(6); + const size_t N = dst.extent(0) * dst.extent(1) * dst.extent(2) * + dst.extent(3) * dst.extent(4) * dst.extent(5) * + dst.extent(6); - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,src); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int itmp = i/dst.extent(0); - int i1 = itmp%dst.extent(1); - itmp = itmp/dst.extent(1); - int i2 = itmp%dst.extent(2); - itmp = itmp/dst.extent(2); - int i3 = itmp%dst.extent(3); - itmp = itmp/dst.extent(3); - int i4 = itmp%dst.extent(4); - itmp = itmp/dst.extent(4); - int i5 = itmp%dst.extent(5); - int i6 = itmp/dst.extent(5); - dst(i0,i1,i2,i3,i4,i5,i6) = src(i0,i1,i2,i3,i4,i5,i6); - }); - team.team_barrier(); - } + if (dst.span_is_contiguous() && src.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, src); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int itmp = i / dst.extent(0); + int i1 = itmp % dst.extent(1); + itmp = itmp / dst.extent(1); + int i2 = itmp % dst.extent(2); + itmp = itmp / dst.extent(2); + int i3 = itmp % dst.extent(3); + itmp = itmp / dst.extent(3); + int i4 = itmp % dst.extent(4); + itmp = itmp / dst.extent(4); + int i5 = itmp % dst.extent(5); + int i6 = itmp / dst.extent(5); + dst(i0, i1, i2, i3, i4, i5, i6) = src(i0, i1, i2, i3, i4, i5, i6); + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class DT , class ... DP , class ST , class ... SP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 1 && - unsigned(ViewTraits::rank) == 1 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 1 && + unsigned(ViewTraits::rank) == + 1)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0); + const size_t N = dst.extent(0); - - for(size_t i=0;i -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 2 && - unsigned(ViewTraits::rank) == 2 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 2 && + unsigned(ViewTraits::rank) == + 2)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,src); - } else { - - for(size_t i0=0;i0 -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 3 && - unsigned(ViewTraits::rank) == 3 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 3 && + unsigned(ViewTraits::rank) == + 3)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,src); - } else { - - for(size_t i0=0;i0 -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 4 && - unsigned(ViewTraits::rank) == 4 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 4 && + unsigned(ViewTraits::rank) == + 4)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,src); - } else { - - for(size_t i0=0;i0 -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 5 && - unsigned(ViewTraits::rank) == 5 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 5 && + unsigned(ViewTraits::rank) == + 5)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,src); - } else { - - for(size_t i0=0;i0 -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 6 && - unsigned(ViewTraits::rank) == 6 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 6 && + unsigned(ViewTraits::rank) == + 6)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,src); - } else { - - for(size_t i0=0;i0 -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 7 && - unsigned(ViewTraits::rank) == 7 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 7 && + unsigned(ViewTraits::rank) == + 7)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,src); - } else { - - for(size_t i0=0;i0 -void KOKKOS_INLINE_FUNCTION local_deep_copy_contiguous(const TeamType& team, const View & dst, typename ViewTraits::const_value_type & value) { - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, dst.span()), [&] (const int& i) { - dst.data()[i] = value; - }); +template +void KOKKOS_INLINE_FUNCTION local_deep_copy_contiguous( + const TeamType& team, const View& dst, + typename ViewTraits::const_value_type& value) { + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, dst.span()), + [&](const int& i) { dst.data()[i] = value; }); } //---------------------------------------------------------------------------- -template< class DT , class ... DP > -void KOKKOS_INLINE_FUNCTION local_deep_copy_contiguous(const View & dst, typename ViewTraits::const_value_type & value) { - - for(size_t i=0;i +void KOKKOS_INLINE_FUNCTION local_deep_copy_contiguous( + const View& dst, + typename ViewTraits::const_value_type& value) { + for (size_t i = 0; i < dst.span(); ++i) { + dst.data()[i] = value; + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 1 )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 1)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0); + const size_t N = dst.extent(0); - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - dst(i) = value; - }); - team.team_barrier(); + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), + [&](const int& i) { dst(i) = value; }); + team.team_barrier(); } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 2 )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 2)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1); + const size_t N = dst.extent(0) * dst.extent(1); - if ( dst.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,value); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int i1 = i/dst.extent(0); - dst(i0,i1) = value; - }); - team.team_barrier(); - } + if (dst.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, value); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int i1 = i / dst.extent(0); + dst(i0, i1) = value; + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 3 )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 3)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1)*dst.extent(2); + const size_t N = dst.extent(0) * dst.extent(1) * dst.extent(2); - if ( dst.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,value); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int itmp = i/dst.extent(0); - int i1 = itmp%dst.extent(1); - int i2 = itmp/dst.extent(1); - dst(i0,i1,i2) = value; - }); - team.team_barrier(); - } + if (dst.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, value); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int itmp = i / dst.extent(0); + int i1 = itmp % dst.extent(1); + int i2 = itmp / dst.extent(1); + dst(i0, i1, i2) = value; + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 4 )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 4)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1)*dst.extent(2)*dst.extent(3); + const size_t N = + dst.extent(0) * dst.extent(1) * dst.extent(2) * dst.extent(3); - if ( dst.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,value); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int itmp = i/dst.extent(0); - int i1 = itmp%dst.extent(1); - itmp = itmp/dst.extent(1); - int i2 = itmp%dst.extent(2); - int i3 = itmp/dst.extent(2); - dst(i0,i1,i2,i3) = value; - }); - team.team_barrier(); - } + if (dst.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, value); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int itmp = i / dst.extent(0); + int i1 = itmp % dst.extent(1); + itmp = itmp / dst.extent(1); + int i2 = itmp % dst.extent(2); + int i3 = itmp / dst.extent(2); + dst(i0, i1, i2, i3) = value; + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 5 )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 5)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1)*dst.extent(2)*dst.extent(3)*dst.extent(4); + const size_t N = dst.extent(0) * dst.extent(1) * dst.extent(2) * + dst.extent(3) * dst.extent(4); - if ( dst.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,value); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int itmp = i/dst.extent(0); - int i1 = itmp%dst.extent(1); - itmp = itmp/dst.extent(1); - int i2 = itmp%dst.extent(2); - itmp = itmp/dst.extent(2); - int i3 = itmp%dst.extent(3); - int i4 = itmp/dst.extent(3); - dst(i0,i1,i2,i3,i4) = value; - }); - team.team_barrier(); - } + if (dst.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, value); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int itmp = i / dst.extent(0); + int i1 = itmp % dst.extent(1); + itmp = itmp / dst.extent(1); + int i2 = itmp % dst.extent(2); + itmp = itmp / dst.extent(2); + int i3 = itmp % dst.extent(3); + int i4 = itmp / dst.extent(3); + dst(i0, i1, i2, i3, i4) = value; + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 6 )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 6)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1)*dst.extent(2)*dst.extent(3)*dst.extent(4)*dst.extent(5); + const size_t N = dst.extent(0) * dst.extent(1) * dst.extent(2) * + dst.extent(3) * dst.extent(4) * dst.extent(5); - if ( dst.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,value); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int itmp = i/dst.extent(0); - int i1 = itmp%dst.extent(1); - itmp = itmp/dst.extent(1); - int i2 = itmp%dst.extent(2); - itmp = itmp/dst.extent(2); - int i3 = itmp%dst.extent(3); - itmp = itmp/dst.extent(3); - int i4 = itmp%dst.extent(4); - int i5 = itmp/dst.extent(4); - dst(i0,i1,i2,i3,i4,i5) = value; - }); - team.team_barrier(); - } + if (dst.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, value); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int itmp = i / dst.extent(0); + int i1 = itmp % dst.extent(1); + itmp = itmp / dst.extent(1); + int i2 = itmp % dst.extent(2); + itmp = itmp / dst.extent(2); + int i3 = itmp % dst.extent(3); + itmp = itmp / dst.extent(3); + int i4 = itmp % dst.extent(4); + int i5 = itmp / dst.extent(4); + dst(i0, i1, i2, i3, i4, i5) = value; + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 7 )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 7)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1)*dst.extent(2)*dst.extent(3)*dst.extent(4)*dst.extent(5)*dst.extent(6); + const size_t N = dst.extent(0) * dst.extent(1) * dst.extent(2) * + dst.extent(3) * dst.extent(4) * dst.extent(5) * + dst.extent(6); - if ( dst.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,value); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int itmp = i/dst.extent(0); - int i1 = itmp%dst.extent(1); - itmp = itmp/dst.extent(1); - int i2 = itmp%dst.extent(2); - itmp = itmp/dst.extent(2); - int i3 = itmp%dst.extent(3); - itmp = itmp/dst.extent(3); - int i4 = itmp%dst.extent(4); - itmp = itmp/dst.extent(4); - int i5 = itmp%dst.extent(5); - int i6 = itmp/dst.extent(5); - dst(i0,i1,i2,i3,i4,i5,i6) = value; - }); - team.team_barrier(); - } + if (dst.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, value); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int itmp = i / dst.extent(0); + int i1 = itmp % dst.extent(1); + itmp = itmp / dst.extent(1); + int i2 = itmp % dst.extent(2); + itmp = itmp / dst.extent(2); + int i3 = itmp % dst.extent(3); + itmp = itmp / dst.extent(3); + int i4 = itmp % dst.extent(4); + itmp = itmp / dst.extent(4); + int i5 = itmp % dst.extent(5); + int i6 = itmp / dst.extent(5); + dst(i0, i1, i2, i3, i4, i5, i6) = value; + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class DT , class ... DP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 1 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 1)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0); + const size_t N = dst.extent(0); - - for(size_t i=0;i -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 2 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 2)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,value); - } else { - - for(size_t i0=0;i0 -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 3 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 3)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,value); - } else { - - for(size_t i0=0;i0 -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 4 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 4)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,value); - } else { - - for(size_t i0=0;i0 -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 5 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 5)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,value); - } else { - - for(size_t i0=0;i0 -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 6 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 6)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,value); - } else { - - for(size_t i0=0;i0 -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 7 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 7)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,value); - } else { - - for(size_t i0=0;i0 & dst, namespace Kokkos { /** \brief Deep copy a value from Host memory into a view. */ -template< class ExecSpace ,class DT , class ... DP > -inline -void deep_copy - ( const ExecSpace & - , const View & dst - , typename ViewTraits::const_value_type & value - , typename std::enable_if< - Kokkos::Impl::is_execution_space< ExecSpace >::value && - std::is_same< typename ViewTraits::specialize , void >::value - >::type * = 0 ) -{ - static_assert( - std::is_same< typename ViewTraits::non_const_value_type , - typename ViewTraits::value_type >::value - , "deep_copy requires non-const type" ); - +template +inline void deep_copy( + const ExecSpace&, const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if< + Kokkos::Impl::is_execution_space::value && + std::is_same::specialize, + void>::value>::type* = 0) { + typedef ViewTraits dst_traits; + typedef typename dst_traits::memory_space dst_memory_space; + static_assert(std::is_same::value, + "deep_copy requires non-const type"); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::beginDeepCopy( + Kokkos::Profiling::SpaceHandle(dst_memory_space().name()), dst.label(), + dst.data(), Kokkos::Profiling::SpaceHandle(Kokkos::HostSpace().name()), + "(none)", &value, dst.span() * sizeof(typename dst_traits::value_type)); + } +#endif ExecSpace().fence(); - typedef typename View::uniform_runtime_nomemspace_type ViewTypeUniform; - Kokkos::Impl::ViewFill< ViewTypeUniform >( dst , value ); + typedef + typename View::uniform_runtime_nomemspace_type ViewTypeUniform; + Kokkos::Impl::ViewFill(dst, value); ExecSpace().fence(); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif } /** \brief Deep copy into a value in Host memory from a view. */ -template< class ExecSpace , class ST , class ... SP > -inline -void deep_copy - ( const ExecSpace & exec_space - , typename ViewTraits::non_const_value_type & dst - , const View & src - , typename std::enable_if< - Kokkos::Impl::is_execution_space< ExecSpace >::value && - std::is_same< typename ViewTraits::specialize , void >::value - >::type * = 0 ) -{ - static_assert( ViewTraits::rank == 0 - , "ERROR: Non-rank-zero view in deep_copy( value , View )" ); - - if(src.data() == NULL) { +template +inline void deep_copy( + const ExecSpace& exec_space, + typename ViewTraits::non_const_value_type& dst, + const View& src, + typename std::enable_if< + Kokkos::Impl::is_execution_space::value && + std::is_same::specialize, + void>::value>::type* = 0) { + typedef ViewTraits src_traits; + typedef typename src_traits::memory_space src_memory_space; + static_assert(src_traits::rank == 0, + "ERROR: Non-rank-zero view in deep_copy( value , View )"); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::beginDeepCopy( + Kokkos::Profiling::SpaceHandle(Kokkos::HostSpace().name()), "(none)", + &dst, Kokkos::Profiling::SpaceHandle(src_memory_space().name()), + src.label(), src.data(), sizeof(ST)); + } +#endif + + if (src.data() == NULL) { exec_space.fence(); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif return; } - typedef ViewTraits src_traits ; - typedef typename src_traits::memory_space src_memory_space ; - Kokkos::Impl::DeepCopy< HostSpace , src_memory_space , ExecSpace > - ( exec_space , & dst , src.data() , sizeof(ST) ); + Kokkos::Impl::DeepCopy( + exec_space, &dst, src.data(), sizeof(ST)); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif } //---------------------------------------------------------------------------- /** \brief A deep copy between views of compatible type, and rank zero. */ -template< class ExecSpace , class DT , class ... DP , class ST , class ... SP > -inline -void deep_copy - ( const ExecSpace & exec_space - , const View & dst - , const View & src - , typename std::enable_if<( - Kokkos::Impl::is_execution_space< ExecSpace >::value && - std::is_same< typename ViewTraits::specialize , void >::value && - std::is_same< typename ViewTraits::specialize , void >::value && - ( unsigned(ViewTraits::rank) == unsigned(0) && - unsigned(ViewTraits::rank) == unsigned(0) ) - )>::type * = 0 ) -{ - static_assert( - std::is_same< typename ViewTraits::value_type , - typename ViewTraits::non_const_value_type >::value - , "deep_copy requires matching non-const destination type" ); - - typedef View dst_type ; - typedef View src_type ; - - typedef typename dst_type::value_type value_type ; - typedef typename dst_type::memory_space dst_memory_space ; - typedef typename src_type::memory_space src_memory_space ; - if(dst.data() == NULL && src.data() == NULL) { +template +inline void deep_copy( + const ExecSpace& exec_space, const View& dst, + const View& src, + typename std::enable_if<( + Kokkos::Impl::is_execution_space::value && + std::is_same::specialize, void>::value && + std::is_same::specialize, void>::value && + (unsigned(ViewTraits::rank) == unsigned(0) && + unsigned(ViewTraits::rank) == unsigned(0)))>::type* = 0) { + typedef ViewTraits src_traits; + typedef ViewTraits dst_traits; + + typedef typename src_traits::memory_space src_memory_space; + typedef typename dst_traits::memory_space dst_memory_space; + static_assert(std::is_same::value, + "deep_copy requires matching non-const destination type"); + +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::beginDeepCopy( + Kokkos::Profiling::SpaceHandle(dst_memory_space().name()), dst.label(), + dst.data(), Kokkos::Profiling::SpaceHandle(src_memory_space().name()), + src.label(), src.data(), sizeof(DT)); + } +#endif + + if (dst.data() == NULL && src.data() == NULL) { exec_space.fence(); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif return; } exec_space.fence(); - if ( dst.data() != src.data() ) { - Kokkos::Impl::DeepCopy< dst_memory_space , src_memory_space , ExecSpace > - ( exec_space , dst.data() , src.data() , sizeof(value_type) ); + if (dst.data() != src.data()) { + Kokkos::Impl::DeepCopy( + exec_space, dst.data(), src.data(), + sizeof(typename dst_traits::value_type)); } exec_space.fence(); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif } //---------------------------------------------------------------------------- -/** \brief A deep copy between views of the default specialization, compatible type, - * same non-zero rank +/** \brief A deep copy between views of the default specialization, compatible + * type, same non-zero rank */ -template< class ExecSpace , class DT, class ... DP, class ST, class ... SP > -inline -void deep_copy - ( const ExecSpace & exec_space - , const View & dst - , const View & src - , typename std::enable_if<( - Kokkos::Impl::is_execution_space< ExecSpace >::value && - std::is_same< typename ViewTraits::specialize , void >::value && - std::is_same< typename ViewTraits::specialize , void >::value && - ( unsigned(ViewTraits::rank) != 0 || - unsigned(ViewTraits::rank) != 0 ) - )>::type * = 0 ) -{ - typedef View dst_type ; - typedef View src_type ; - - static_assert( - std::is_same< typename dst_type::value_type , - typename dst_type::non_const_value_type >::value - , "deep_copy requires non-const destination type" ); - - static_assert( - ( unsigned(dst_type::rank) == - unsigned(src_type::rank) ) - , "deep_copy requires Views of equal rank" ); - - typedef typename dst_type::execution_space dst_execution_space ; - typedef typename src_type::execution_space src_execution_space ; - typedef typename dst_type::memory_space dst_memory_space ; - typedef typename src_type::memory_space src_memory_space ; - typedef typename dst_type::value_type dst_value_type ; - typedef typename src_type::value_type src_value_type ; - - if(dst.data() == NULL || src.data() == NULL) { +template +inline void deep_copy( + const ExecSpace& exec_space, const View& dst, + const View& src, + typename std::enable_if<( + Kokkos::Impl::is_execution_space::value && + std::is_same::specialize, void>::value && + std::is_same::specialize, void>::value && + (unsigned(ViewTraits::rank) != 0 || + unsigned(ViewTraits::rank) != 0))>::type* = 0) { + typedef View dst_type; + typedef View src_type; + + static_assert(std::is_same::value, + "deep_copy requires non-const destination type"); + + static_assert((unsigned(dst_type::rank) == unsigned(src_type::rank)), + "deep_copy requires Views of equal rank"); + + typedef typename dst_type::execution_space dst_execution_space; + typedef typename src_type::execution_space src_execution_space; + typedef typename dst_type::memory_space dst_memory_space; + typedef typename src_type::memory_space src_memory_space; + typedef typename dst_type::value_type dst_value_type; + typedef typename src_type::value_type src_value_type; + +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::beginDeepCopy( + Kokkos::Profiling::SpaceHandle(dst_memory_space().name()), dst.label(), + dst.data(), Kokkos::Profiling::SpaceHandle(src_memory_space().name()), + src.label(), src.data(), dst.span() * sizeof(dst_value_type)); + } +#endif + + if (dst.data() == NULL || src.data() == NULL) { #ifdef KOKKOS_ENABLE_DEPRECATED_CODE // do nothing #else // throw if dimension mismatch - if ( (src.extent(0) != dst.extent(0)) || - (src.extent(1) != dst.extent(1)) || - (src.extent(2) != dst.extent(2)) || - (src.extent(3) != dst.extent(3)) || - (src.extent(4) != dst.extent(4)) || - (src.extent(5) != dst.extent(5)) || - (src.extent(6) != dst.extent(6)) || - (src.extent(7) != dst.extent(7)) - ) { - std::string message("Deprecation Error: Kokkos::deep_copy extents of views don't match: "); - message += dst.label(); message += "("; - for(int r = 0; r::accessible && - Kokkos::Impl::SpaceAccessibility< ExecSpace , src_memory_space >::accessible + enum { + ExecCanAccessSrcDst = + Kokkos::Impl::SpaceAccessibility::accessible && + Kokkos::Impl::SpaceAccessibility::accessible + }; + enum { + DstExecCanAccessSrc = + Kokkos::Impl::SpaceAccessibility::accessible }; - enum { DstExecCanAccessSrc = - Kokkos::Impl::SpaceAccessibility< dst_execution_space , src_memory_space >::accessible }; - enum { SrcExecCanAccessDst = - Kokkos::Impl::SpaceAccessibility< src_execution_space , dst_memory_space >::accessible }; + enum { + SrcExecCanAccessDst = + Kokkos::Impl::SpaceAccessibility::accessible + }; // Checking for Overlapping Views. dst_value_type* dst_start = dst.data(); dst_value_type* dst_end = dst.data() + dst.span(); src_value_type* src_start = src.data(); src_value_type* src_end = src.data() + src.span(); - if( ( ( (std::ptrdiff_t)dst_start < (std::ptrdiff_t)src_end ) && ( (std::ptrdiff_t)dst_end > (std::ptrdiff_t)src_start ) ) && - ( ( dst.span_is_contiguous() && src.span_is_contiguous() ))) { + if ((((std::ptrdiff_t)dst_start < (std::ptrdiff_t)src_end) && + ((std::ptrdiff_t)dst_end > (std::ptrdiff_t)src_start)) && + ((dst.span_is_contiguous() && src.span_is_contiguous()))) { std::string message("Error: Kokkos::deep_copy of overlapping views: "); - message += dst.label(); message += "("; - message += std::to_string((std::ptrdiff_t)dst_start); message += ","; - message += std::to_string((std::ptrdiff_t)dst_end); message += ") "; - message += src.label(); message += "("; - message += std::to_string((std::ptrdiff_t)src_start); message += ","; - message += std::to_string((std::ptrdiff_t)src_end); message += ") "; + message += dst.label(); + message += "("; + message += std::to_string((std::ptrdiff_t)dst_start); + message += ","; + message += std::to_string((std::ptrdiff_t)dst_end); + message += ") "; + message += src.label(); + message += "("; + message += std::to_string((std::ptrdiff_t)src_start); + message += ","; + message += std::to_string((std::ptrdiff_t)src_end); + message += ") "; Kokkos::Impl::throw_runtime_exception(message); } // Check for same extents - if ( (src.extent(0) != dst.extent(0)) || - (src.extent(1) != dst.extent(1)) || - (src.extent(2) != dst.extent(2)) || - (src.extent(3) != dst.extent(3)) || - (src.extent(4) != dst.extent(4)) || - (src.extent(5) != dst.extent(5)) || - (src.extent(6) != dst.extent(6)) || - (src.extent(7) != dst.extent(7)) - ) { + if ((src.extent(0) != dst.extent(0)) || (src.extent(1) != dst.extent(1)) || + (src.extent(2) != dst.extent(2)) || (src.extent(3) != dst.extent(3)) || + (src.extent(4) != dst.extent(4)) || (src.extent(5) != dst.extent(5)) || + (src.extent(6) != dst.extent(6)) || (src.extent(7) != dst.extent(7))) { #ifdef KOKKOS_ENABLE_DEPRECATED_CODE exec_space.fence(); - if ( ExecCanAccessSrcDst ) { - Kokkos::Impl::ViewRemap< dst_type , src_type , ExecSpace >( dst , src ); - } - else if ( DstExecCanAccessSrc ) { - // Copying data between views in accessible memory spaces and either non-contiguous or incompatible shape. - Kokkos::Impl::ViewRemap< dst_type , src_type >( dst , src ); - } - else if ( SrcExecCanAccessDst ) { - // Copying data between views in accessible memory spaces and either non-contiguous or incompatible shape. - Kokkos::Impl::ViewRemap< dst_type , src_type , src_execution_space >( dst , src ); - } - else { - Kokkos::Impl::throw_runtime_exception("deep_copy given views that would require a temporary allocation"); + if (ExecCanAccessSrcDst) { + Kokkos::Impl::ViewRemap(dst, src); + } else if (DstExecCanAccessSrc) { + // Copying data between views in accessible memory spaces and either + // non-contiguous or incompatible shape. + Kokkos::Impl::ViewRemap(dst, src); + } else if (SrcExecCanAccessDst) { + // Copying data between views in accessible memory spaces and either + // non-contiguous or incompatible shape. + Kokkos::Impl::ViewRemap(dst, + src); + } else { + Kokkos::Impl::throw_runtime_exception( + "deep_copy given views that would require a temporary allocation"); } exec_space.fence(); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif return; #else - std::string message("Deprecation Error: Kokkos::deep_copy extents of views don't match: "); - message += dst.label(); message += "("; - for(int r = 0; r::value && - ( - std::is_same< typename dst_type::array_layout , - typename src_type::array_layout >::value - || - ( dst_type::rank == 1 && - src_type::rank == 1 ) - ) && - dst.span_is_contiguous() && - src.span_is_contiguous() && - ((dst_type::rank < 1) || (dst.stride_0() == src.stride_0())) && - ((dst_type::rank < 2) || (dst.stride_1() == src.stride_1())) && - ((dst_type::rank < 3) || (dst.stride_2() == src.stride_2())) && - ((dst_type::rank < 4) || (dst.stride_3() == src.stride_3())) && - ((dst_type::rank < 5) || (dst.stride_4() == src.stride_4())) && - ((dst_type::rank < 6) || (dst.stride_5() == src.stride_5())) && - ((dst_type::rank < 7) || (dst.stride_6() == src.stride_6())) && - ((dst_type::rank < 8) || (dst.stride_7() == src.stride_7())) - ) { - + // If same type, equal layout, equal dimensions, equal span, and contiguous + // memory then can byte-wise copy + + if (std::is_same::value && + (std::is_same::value || + (dst_type::rank == 1 && src_type::rank == 1)) && + dst.span_is_contiguous() && src.span_is_contiguous() && + ((dst_type::rank < 1) || (dst.stride_0() == src.stride_0())) && + ((dst_type::rank < 2) || (dst.stride_1() == src.stride_1())) && + ((dst_type::rank < 3) || (dst.stride_2() == src.stride_2())) && + ((dst_type::rank < 4) || (dst.stride_3() == src.stride_3())) && + ((dst_type::rank < 5) || (dst.stride_4() == src.stride_4())) && + ((dst_type::rank < 6) || (dst.stride_5() == src.stride_5())) && + ((dst_type::rank < 7) || (dst.stride_6() == src.stride_6())) && + ((dst_type::rank < 8) || (dst.stride_7() == src.stride_7()))) { const size_t nbytes = sizeof(typename dst_type::value_type) * dst.span(); exec_space.fence(); - if((void*)dst.data() != (void*)src.data()) { - Kokkos::Impl::DeepCopy< dst_memory_space , src_memory_space , ExecSpace > - ( exec_space , dst.data() , src.data() , nbytes ); + if ((void*)dst.data() != (void*)src.data()) { + Kokkos::Impl::DeepCopy( + exec_space, dst.data(), src.data(), nbytes); } exec_space.fence(); } else { @@ -2581,6 +2957,11 @@ void deep_copy Impl::view_copy(dst, src); exec_space.fence(); } +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif } } /* namespace Kokkos */ @@ -2590,90 +2971,179 @@ void deep_copy namespace Kokkos { -/** \brief Resize a view with copying old data to new data at the corresponding indices. */ -template< class T , class ... P > -inline -typename std::enable_if< - std::is_same::array_layout,Kokkos::LayoutLeft>::value || - std::is_same::array_layout,Kokkos::LayoutRight>::value ->::type -resize( Kokkos::View & v , - const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG ) -{ - typedef Kokkos::View view_type ; - - static_assert( Kokkos::ViewTraits::is_managed , "Can only resize managed views" ); +/** \brief Resize a view with copying old data to new data at the corresponding + * indices. */ +template +inline typename std::enable_if< + std::is_same::array_layout, + Kokkos::LayoutLeft>::value || + std::is_same::array_layout, + Kokkos::LayoutRight>::value>::type +resize(Kokkos::View& v, const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) { + typedef Kokkos::View view_type; + + static_assert(Kokkos::ViewTraits::is_managed, + "Can only resize managed views"); + + // Fix #904 by checking dimensions before actually resizing. + // + // Rank is known at compile time, so hopefully the compiler will + // remove branches that are compile-time false. The upcoming "if + // constexpr" language feature would make this certain. + if (view_type::Rank == 1 && n0 == static_cast(v.extent(0))) { + return; + } + if (view_type::Rank == 2 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1))) { + return; + } + if (view_type::Rank == 3 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2))) { + return; + } + if (view_type::Rank == 4 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2)) && + n3 == static_cast(v.extent(3))) { + return; + } + if (view_type::Rank == 5 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2)) && + n3 == static_cast(v.extent(3)) && + n4 == static_cast(v.extent(4))) { + return; + } + if (view_type::Rank == 6 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2)) && + n3 == static_cast(v.extent(3)) && + n4 == static_cast(v.extent(4)) && + n5 == static_cast(v.extent(5))) { + return; + } + if (view_type::Rank == 7 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2)) && + n3 == static_cast(v.extent(3)) && + n4 == static_cast(v.extent(4)) && + n5 == static_cast(v.extent(5)) && + n6 == static_cast(v.extent(6))) { + return; + } + if (view_type::Rank == 8 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2)) && + n3 == static_cast(v.extent(3)) && + n4 == static_cast(v.extent(4)) && + n5 == static_cast(v.extent(5)) && + n6 == static_cast(v.extent(6)) && + n7 == static_cast(v.extent(7))) { + return; + } + // If Kokkos ever supports Views of rank > 8, the above code won't + // be incorrect, because avoiding reallocation in resize() is just + // an optimization. + + // TODO (mfh 27 Jun 2017) If the old View has enough space but just + // different dimensions (e.g., if the product of the dimensions, + // including extra space for alignment, will not change), then + // consider just reusing storage. For now, Kokkos always + // reallocates if any of the dimensions change, even if the old View + // has enough space. + + view_type v_resized(v.label(), n0, n1, n2, n3, n4, n5, n6, n7); + + Kokkos::Impl::ViewRemap(v_resized, v); + + v = v_resized; +} + +/** \brief Resize a view with copying old data to new data at the corresponding + * indices. */ +template +inline typename std::enable_if< + std::is_same::array_layout, + Kokkos::LayoutLeft>::value || + std::is_same::array_layout, + Kokkos::LayoutRight>::value>::type +resize(const I& arg_prop, Kokkos::View& v, + const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) { + typedef Kokkos::View view_type; + + static_assert(Kokkos::ViewTraits::is_managed, + "Can only resize managed views"); // Fix #904 by checking dimensions before actually resizing. // // Rank is known at compile time, so hopefully the compiler will // remove branches that are compile-time false. The upcoming "if // constexpr" language feature would make this certain. - if (view_type::Rank == 1 && - n0 == static_cast (v.extent(0))) { + if (view_type::Rank == 1 && n0 == static_cast(v.extent(0))) { return; } - if (view_type::Rank == 2 && - n0 == static_cast (v.extent(0)) && - n1 == static_cast (v.extent(1))) { + if (view_type::Rank == 2 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1))) { return; } - if (view_type::Rank == 3 && - n0 == static_cast (v.extent(0)) && - n1 == static_cast (v.extent(1)) && - n2 == static_cast (v.extent(2))) { + if (view_type::Rank == 3 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2))) { return; } - if (view_type::Rank == 4 && - n0 == static_cast (v.extent(0)) && - n1 == static_cast (v.extent(1)) && - n2 == static_cast (v.extent(2)) && - n3 == static_cast (v.extent(3))) { + if (view_type::Rank == 4 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2)) && + n3 == static_cast(v.extent(3))) { return; } - if (view_type::Rank == 5 && - n0 == static_cast (v.extent(0)) && - n1 == static_cast (v.extent(1)) && - n2 == static_cast (v.extent(2)) && - n3 == static_cast (v.extent(3)) && - n4 == static_cast (v.extent(4))) { + if (view_type::Rank == 5 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2)) && + n3 == static_cast(v.extent(3)) && + n4 == static_cast(v.extent(4))) { return; } - if (view_type::Rank == 6 && - n0 == static_cast (v.extent(0)) && - n1 == static_cast (v.extent(1)) && - n2 == static_cast (v.extent(2)) && - n3 == static_cast (v.extent(3)) && - n4 == static_cast (v.extent(4)) && - n5 == static_cast (v.extent(5))) { + if (view_type::Rank == 6 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2)) && + n3 == static_cast(v.extent(3)) && + n4 == static_cast(v.extent(4)) && + n5 == static_cast(v.extent(5))) { return; } - if (view_type::Rank == 7 && - n0 == static_cast (v.extent(0)) && - n1 == static_cast (v.extent(1)) && - n2 == static_cast (v.extent(2)) && - n3 == static_cast (v.extent(3)) && - n4 == static_cast (v.extent(4)) && - n5 == static_cast (v.extent(5)) && - n6 == static_cast (v.extent(6))) { + if (view_type::Rank == 7 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2)) && + n3 == static_cast(v.extent(3)) && + n4 == static_cast(v.extent(4)) && + n5 == static_cast(v.extent(5)) && + n6 == static_cast(v.extent(6))) { return; } - if (view_type::Rank == 8 && - n0 == static_cast (v.extent(0)) && - n1 == static_cast (v.extent(1)) && - n2 == static_cast (v.extent(2)) && - n3 == static_cast (v.extent(3)) && - n4 == static_cast (v.extent(4)) && - n5 == static_cast (v.extent(5)) && - n6 == static_cast (v.extent(6)) && - n7 == static_cast (v.extent(7))) { + if (view_type::Rank == 8 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2)) && + n3 == static_cast(v.extent(3)) && + n4 == static_cast(v.extent(4)) && + n5 == static_cast(v.extent(5)) && + n6 == static_cast(v.extent(6)) && + n7 == static_cast(v.extent(7))) { return; } // If Kokkos ever supports Views of rank > 8, the above code won't @@ -2687,71 +3157,72 @@ resize( Kokkos::View & v , // reallocates if any of the dimensions change, even if the old View // has enough space. - view_type v_resized( v.label(), n0, n1, n2, n3, n4, n5, n6, n7 ); + view_type v_resized(view_alloc(v.label(), std::forward(arg_prop)), + n0, n1, n2, n3, n4, n5, n6, n7); - Kokkos::Impl::ViewRemap< view_type , view_type >( v_resized , v ); + Kokkos::Impl::ViewRemap(v_resized, v); - v = v_resized ; + v = v_resized; } -/** \brief Resize a view with copying old data to new data at the corresponding indices. */ -template< class T , class ... P > -inline -void resize( Kokkos::View & v , - const typename Kokkos::View::array_layout & layout) -{ - typedef Kokkos::View view_type ; +/** \brief Resize a view with copying old data to new data at the corresponding + * indices. */ +template +inline void resize(Kokkos::View& v, + const typename Kokkos::View::array_layout& layout) { + typedef Kokkos::View view_type; - static_assert( Kokkos::ViewTraits::is_managed , "Can only resize managed views" ); + static_assert(Kokkos::ViewTraits::is_managed, + "Can only resize managed views"); - view_type v_resized( v.label(), layout ); + view_type v_resized(v.label(), layout); - Kokkos::Impl::ViewRemap< view_type , view_type >( v_resized , v ); + Kokkos::Impl::ViewRemap(v_resized, v); - v = v_resized ; + v = v_resized; } /** \brief Resize a view with discarding old data. */ -template< class T , class ... P > -inline -typename std::enable_if< - std::is_same::array_layout,Kokkos::LayoutLeft>::value || - std::is_same::array_layout,Kokkos::LayoutRight>::value ->::type -realloc( Kokkos::View & v , - const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG ) -{ - typedef Kokkos::View view_type ; - - static_assert( Kokkos::ViewTraits::is_managed , "Can only realloc managed views" ); +template +inline typename std::enable_if< + std::is_same::array_layout, + Kokkos::LayoutLeft>::value || + std::is_same::array_layout, + Kokkos::LayoutRight>::value>::type +realloc(Kokkos::View& v, + const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) { + typedef Kokkos::View view_type; + + static_assert(Kokkos::ViewTraits::is_managed, + "Can only realloc managed views"); const std::string label = v.label(); - v = view_type(); // Deallocate first, if the only view to allocation - v = view_type( label, n0, n1, n2, n3, n4, n5, n6, n7 ); + v = view_type(); // Deallocate first, if the only view to allocation + v = view_type(label, n0, n1, n2, n3, n4, n5, n6, n7); } /** \brief Resize a view with discarding old data. */ -template< class T , class ... P > -inline -void realloc( Kokkos::View & v , - const typename Kokkos::View::array_layout & layout) -{ - typedef Kokkos::View view_type ; +template +inline void realloc( + Kokkos::View& v, + const typename Kokkos::View::array_layout& layout) { + typedef Kokkos::View view_type; - static_assert( Kokkos::ViewTraits::is_managed , "Can only realloc managed views" ); + static_assert(Kokkos::ViewTraits::is_managed, + "Can only realloc managed views"); const std::string label = v.label(); - v = view_type(); // Deallocate first, if the only view to allocation - v = view_type( label, layout ); + v = view_type(); // Deallocate first, if the only view to allocation + v = view_type(label, layout); } } /* namespace Kokkos */ @@ -2762,94 +3233,99 @@ namespace Kokkos { namespace Impl { // Deduce Mirror Types -template +template struct MirrorViewType { // The incoming view_type - typedef typename Kokkos::View src_view_type; + typedef typename Kokkos::View src_view_type; // The memory space for the mirror view typedef typename Space::memory_space memory_space; // Check whether it is the same memory space - enum { is_same_memspace = std::is_same::value }; + enum { + is_same_memspace = + std::is_same::value + }; // The array_layout typedef typename src_view_type::array_layout array_layout; - // The data type (we probably want it non-const since otherwise we can't even deep_copy to it. + // The data type (we probably want it non-const since otherwise we can't even + // deep_copy to it. typedef typename src_view_type::non_const_data_type data_type; // The destination view type if it is not the same memory space - typedef Kokkos::View dest_view_type; + typedef Kokkos::View dest_view_type; // If it is the same memory_space return the existsing view_type // This will also keep the unmanaged trait if necessary - typedef typename std::conditional::type view_type; + typedef typename std::conditional::type view_type; }; -template +template struct MirrorType { // The incoming view_type - typedef typename Kokkos::View src_view_type; + typedef typename Kokkos::View src_view_type; // The memory space for the mirror view typedef typename Space::memory_space memory_space; // Check whether it is the same memory space - enum { is_same_memspace = std::is_same::value }; + enum { + is_same_memspace = + std::is_same::value + }; // The array_layout typedef typename src_view_type::array_layout array_layout; - // The data type (we probably want it non-const since otherwise we can't even deep_copy to it. + // The data type (we probably want it non-const since otherwise we can't even + // deep_copy to it. typedef typename src_view_type::non_const_data_type data_type; // The destination view type if it is not the same memory space - typedef Kokkos::View view_type; + typedef Kokkos::View view_type; }; -} +} // namespace Impl + +template +inline typename Kokkos::View::HostMirror create_mirror( + const Kokkos::View& src, + typename std::enable_if< + std::is_same::specialize, void>::value && + !std::is_same::array_layout, + Kokkos::LayoutStride>::value>::type* = 0) { + typedef View src_type; + typedef typename src_type::HostMirror dst_type; -template< class T , class ... P > -inline -typename Kokkos::View::HostMirror -create_mirror( const Kokkos::View & src - , typename std::enable_if< - std::is_same< typename ViewTraits::specialize , void >::value && - ! std::is_same< typename Kokkos::ViewTraits::array_layout - , Kokkos::LayoutStride >::value - >::type * = 0 - ) -{ - typedef View src_type ; - typedef typename src_type::HostMirror dst_type ; - - return dst_type( std::string( src.label() ).append("_mirror") + return dst_type(std::string(src.label()).append("_mirror") #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - , src.extent(0) - , src.extent(1) - , src.extent(2) - , src.extent(3) - , src.extent(4) - , src.extent(5) - , src.extent(6) - , src.extent(7) ); + , + src.extent(0), src.extent(1), src.extent(2), src.extent(3), + src.extent(4), src.extent(5), src.extent(6), src.extent(7)); #else - , src.rank_dynamic > 0 ? src.extent(0): KOKKOS_IMPL_CTOR_DEFAULT_ARG - , src.rank_dynamic > 1 ? src.extent(1): KOKKOS_IMPL_CTOR_DEFAULT_ARG - , src.rank_dynamic > 2 ? src.extent(2): KOKKOS_IMPL_CTOR_DEFAULT_ARG - , src.rank_dynamic > 3 ? src.extent(3): KOKKOS_IMPL_CTOR_DEFAULT_ARG - , src.rank_dynamic > 4 ? src.extent(4): KOKKOS_IMPL_CTOR_DEFAULT_ARG - , src.rank_dynamic > 5 ? src.extent(5): KOKKOS_IMPL_CTOR_DEFAULT_ARG - , src.rank_dynamic > 6 ? src.extent(6): KOKKOS_IMPL_CTOR_DEFAULT_ARG - , src.rank_dynamic > 7 ? src.extent(7): KOKKOS_IMPL_CTOR_DEFAULT_ARG ); + , + src.rank_dynamic > 0 ? src.extent(0) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + src.rank_dynamic > 1 ? src.extent(1) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + src.rank_dynamic > 2 ? src.extent(2) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + src.rank_dynamic > 3 ? src.extent(3) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + src.rank_dynamic > 4 ? src.extent(4) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + src.rank_dynamic > 5 ? src.extent(5) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + src.rank_dynamic > 6 ? src.extent(6) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + src.rank_dynamic > 7 ? src.extent(7) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG); #endif } -template< class T , class ... P > -inline -typename Kokkos::View::HostMirror -create_mirror( const Kokkos::View & src - , typename std::enable_if< - std::is_same< typename ViewTraits::specialize , void >::value && - std::is_same< typename Kokkos::ViewTraits::array_layout - , Kokkos::LayoutStride >::value - >::type * = 0 - ) -{ - typedef View src_type ; - typedef typename src_type::HostMirror dst_type ; - - Kokkos::LayoutStride layout ; +template +inline typename Kokkos::View::HostMirror create_mirror( + const Kokkos::View& src, + typename std::enable_if< + std::is_same::specialize, void>::value && + std::is_same::array_layout, + Kokkos::LayoutStride>::value>::type* = 0) { + typedef View src_type; + typedef typename src_type::HostMirror dst_type; + + Kokkos::LayoutStride layout; layout.dimension[0] = src.extent(0); layout.dimension[1] = src.extent(1); @@ -2869,117 +3345,119 @@ create_mirror( const Kokkos::View & src layout.stride[6] = src.stride_6(); layout.stride[7] = src.stride_7(); - return dst_type( std::string( src.label() ).append("_mirror") , layout ); + return dst_type(std::string(src.label()).append("_mirror"), layout); } - // Create a mirror in a new space (specialization for different space) -template -typename Impl::MirrorType::view_type -create_mirror(const Space& , const Kokkos::View & src - , typename std::enable_if< - std::is_same< typename ViewTraits::specialize , void >::value - >::type * = 0) { - return typename Impl::MirrorType::view_type(src.label(),src.layout()); +template +typename Impl::MirrorType::view_type create_mirror( + const Space&, const Kokkos::View& src, + typename std::enable_if::specialize, void>::value>::type* = 0) { + return typename Impl::MirrorType::view_type(src.label(), + src.layout()); } -template< class T , class ... P > -inline -typename Kokkos::View::HostMirror -create_mirror_view( const Kokkos::View & src - , typename std::enable_if<( - std::is_same< typename Kokkos::View::memory_space - , typename Kokkos::View::HostMirror::memory_space - >::value - && - std::is_same< typename Kokkos::View::data_type - , typename Kokkos::View::HostMirror::data_type - >::value - )>::type * = 0 - ) -{ - return src ; +template +inline typename Kokkos::View::HostMirror create_mirror_view( + const Kokkos::View& src, + typename std::enable_if< + (std::is_same< + typename Kokkos::View::memory_space, + typename Kokkos::View::HostMirror::memory_space>::value && + std::is_same::data_type, + typename Kokkos::View::HostMirror::data_type>:: + value)>::type* = 0) { + return src; } -template< class T , class ... P > -inline -typename Kokkos::View::HostMirror -create_mirror_view( const Kokkos::View & src - , typename std::enable_if< ! ( - std::is_same< typename Kokkos::View::memory_space - , typename Kokkos::View::HostMirror::memory_space - >::value - && - std::is_same< typename Kokkos::View::data_type - , typename Kokkos::View::HostMirror::data_type - >::value - )>::type * = 0 - ) -{ - return Kokkos::create_mirror( src ); +template +inline typename Kokkos::View::HostMirror create_mirror_view( + const Kokkos::View& src, + typename std::enable_if::memory_space, + typename Kokkos::View::HostMirror::memory_space>::value && + std::is_same::data_type, + typename Kokkos::View::HostMirror::data_type>:: + value)>::type* = 0) { + return Kokkos::create_mirror(src); } // Create a mirror view in a new space (specialization for same space) -template -typename Impl::MirrorViewType::view_type -create_mirror_view(const Space& , const Kokkos::View & src - , typename std::enable_if::is_same_memspace>::type* = 0 ) { +template +typename Impl::MirrorViewType::view_type create_mirror_view( + const Space&, const Kokkos::View& src, + typename std::enable_if< + Impl::MirrorViewType::is_same_memspace>::type* = 0) { return src; } // Create a mirror view in a new space (specialization for different space) -template -typename Impl::MirrorViewType::view_type -create_mirror_view(const Space& , const Kokkos::View & src - , typename std::enable_if::is_same_memspace>::type* = 0 ) { - return typename Impl::MirrorViewType::view_type(src.label(),src.layout()); +template +typename Impl::MirrorViewType::view_type create_mirror_view( + const Space&, const Kokkos::View& src, + typename std::enable_if< + !Impl::MirrorViewType::is_same_memspace>::type* = 0) { + return typename Impl::MirrorViewType::view_type(src.label(), + src.layout()); } -// Create a mirror view and deep_copy in a new space (specialization for same space) -template -typename Impl::MirrorViewType::view_type -create_mirror_view_and_copy(const Space& , const Kokkos::View & src - , std::string const& name = "" - , typename std::enable_if::is_same_memspace>::type* = 0 ) { +// Create a mirror view and deep_copy in a new space (specialization for same +// space) +template +typename Impl::MirrorViewType::view_type +create_mirror_view_and_copy( + const Space&, const Kokkos::View& src, + std::string const& name = "", + typename std::enable_if< + Impl::MirrorViewType::is_same_memspace>::type* = 0) { (void)name; return src; } -// Create a mirror view and deep_copy in a new space (specialization for different space) -template -typename Impl::MirrorViewType::view_type -create_mirror_view_and_copy(const Space& , const Kokkos::View & src - , std::string const& name = "" - , typename std::enable_if::is_same_memspace>::type* = 0 ) { - using Mirror = typename Impl::MirrorViewType::view_type; +// Create a mirror view and deep_copy in a new space (specialization for +// different space) +template +typename Impl::MirrorViewType::view_type +create_mirror_view_and_copy( + const Space&, const Kokkos::View& src, + std::string const& name = "", + typename std::enable_if< + !Impl::MirrorViewType::is_same_memspace>::type* = 0) { + using Mirror = typename Impl::MirrorViewType::view_type; std::string label = name.empty() ? src.label() : name; auto mirror = Mirror(ViewAllocateWithoutInitializing(label), src.layout()); deep_copy(mirror, src); return mirror; } - -// Create a mirror view in a new space without initializing (specialization for same space) -template -typename Impl::MirrorViewType::view_type -create_mirror_view(const Space& , const Kokkos::View & src - , Kokkos::Impl::WithoutInitializing_t - , typename std::enable_if::is_same_memspace>::type* = 0 ) { + +// Create a mirror view in a new space without initializing (specialization for +// same space) +template +typename Impl::MirrorViewType::view_type create_mirror_view( + const Space&, const Kokkos::View& src, + Kokkos::Impl::WithoutInitializing_t, + typename std::enable_if< + Impl::MirrorViewType::is_same_memspace>::type* = 0) { return src; } - -// Create a mirror view in a new space without initializing (specialization for different space) -template -typename Impl::MirrorViewType::view_type -create_mirror_view(const Space& , const Kokkos::View & src - , Kokkos::Impl::WithoutInitializing_t - , typename std::enable_if::is_same_memspace>::type* = 0 ) { - using Mirror = typename Impl::MirrorViewType::view_type; - return Mirror(Kokkos::ViewAllocateWithoutInitializing(src.label()), src.layout()); + +// Create a mirror view in a new space without initializing (specialization for +// different space) +template +typename Impl::MirrorViewType::view_type create_mirror_view( + const Space&, const Kokkos::View& src, + Kokkos::Impl::WithoutInitializing_t, + typename std::enable_if< + !Impl::MirrorViewType::is_same_memspace>::type* = 0) { + using Mirror = typename Impl::MirrorViewType::view_type; + return Mirror(Kokkos::ViewAllocateWithoutInitializing(src.label()), + src.layout()); } } /* namespace Kokkos */ - //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- diff --git a/lib/kokkos/core/src/Kokkos_Core.hpp b/lib/kokkos/core/src/Kokkos_Core.hpp index 9fbba0abfa..7661efeca7 100644 --- a/lib/kokkos/core/src/Kokkos_Core.hpp +++ b/lib/kokkos/core/src/Kokkos_Core.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -49,11 +50,11 @@ #include -#if defined( KOKKOS_ENABLE_SERIAL ) +#if defined(KOKKOS_ENABLE_SERIAL) #include #endif -#if defined( KOKKOS_ENABLE_OPENMP ) +#if defined(KOKKOS_ENABLE_OPENMP) #include #endif @@ -62,23 +63,23 @@ #include //#endif -#if defined( KOKKOS_ENABLE_QTHREADS ) +#if defined(KOKKOS_ENABLE_QTHREADS) #include #endif -#if defined( KOKKOS_ENABLE_HPX ) +#if defined(KOKKOS_ENABLE_HPX) #include #endif -#if defined( KOKKOS_ENABLE_THREADS ) +#if defined(KOKKOS_ENABLE_THREADS) #include #endif -#if defined( KOKKOS_ENABLE_CUDA ) +#if defined(KOKKOS_ENABLE_CUDA) #include #endif -#if defined( KOKKOS_ENABLE_ROCM ) +#if defined(KOKKOS_ENABLE_ROCM) #include #endif @@ -111,18 +112,13 @@ struct InitArguments { int skip_device; bool disable_warnings; - InitArguments( int nt = -1 - , int nn = -1 - , int dv = -1 - , bool dw = false - ) - : num_threads{ nt } - , num_numa{ nn } - , device_id{ dv } - , ndevices{ -1 } - , skip_device{ 9999 } - , disable_warnings{ dw } - {} + InitArguments(int nt = -1, int nn = -1, int dv = -1, bool dw = false) + : num_threads{nt}, + num_numa{nn}, + device_id{dv}, + ndevices{-1}, + skip_device{9999}, + disable_warnings{dw} {} }; void initialize(int& narg, char* arg[]); @@ -164,9 +160,9 @@ void finalize_all(); void fence(); /** \brief Print "Bill of Materials" */ -void print_configuration( std::ostream & , const bool detail = false ); +void print_configuration(std::ostream&, const bool detail = false); -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -177,92 +173,80 @@ namespace Kokkos { * The allocation is tracked in Kokkos memory tracking system, so * leaked memory can be identified. */ -template< class Space = typename Kokkos::DefaultExecutionSpace::memory_space > -inline -void * kokkos_malloc( const std::string & arg_alloc_label - , const size_t arg_alloc_size ) -{ - typedef typename Space::memory_space MemorySpace ; - return Impl::SharedAllocationRecord< MemorySpace >:: - allocate_tracked( MemorySpace() , arg_alloc_label , arg_alloc_size ); +template +inline void* kokkos_malloc(const std::string& arg_alloc_label, + const size_t arg_alloc_size) { + typedef typename Space::memory_space MemorySpace; + return Impl::SharedAllocationRecord::allocate_tracked( + MemorySpace(), arg_alloc_label, arg_alloc_size); } -template< class Space = typename Kokkos::DefaultExecutionSpace::memory_space > -inline -void * kokkos_malloc( const size_t arg_alloc_size ) -{ - typedef typename Space::memory_space MemorySpace ; - return Impl::SharedAllocationRecord< MemorySpace >:: - allocate_tracked( MemorySpace() , "no-label" , arg_alloc_size ); +template +inline void* kokkos_malloc(const size_t arg_alloc_size) { + typedef typename Space::memory_space MemorySpace; + return Impl::SharedAllocationRecord::allocate_tracked( + MemorySpace(), "no-label", arg_alloc_size); } -template< class Space = typename Kokkos::DefaultExecutionSpace::memory_space > -inline -void kokkos_free( void * arg_alloc ) -{ - typedef typename Space::memory_space MemorySpace ; - return Impl::SharedAllocationRecord< MemorySpace >:: - deallocate_tracked( arg_alloc ); +template +inline void kokkos_free(void* arg_alloc) { + typedef typename Space::memory_space MemorySpace; + return Impl::SharedAllocationRecord::deallocate_tracked( + arg_alloc); } -template< class Space = typename Kokkos::DefaultExecutionSpace::memory_space > -inline -void * kokkos_realloc( void * arg_alloc , const size_t arg_alloc_size ) -{ - typedef typename Space::memory_space MemorySpace ; - return Impl::SharedAllocationRecord< MemorySpace >:: - reallocate_tracked( arg_alloc , arg_alloc_size ); +template +inline void* kokkos_realloc(void* arg_alloc, const size_t arg_alloc_size) { + typedef typename Space::memory_space MemorySpace; + return Impl::SharedAllocationRecord::reallocate_tracked( + arg_alloc, arg_alloc_size); } -} // namespace Kokkos +} // namespace Kokkos namespace Kokkos { /** \brief ScopeGuard - * Some user scope issues have been identified with some Kokkos::finalize calls; - * ScopeGuard aims to correct these issues. + * Some user scope issues have been identified with some Kokkos::finalize + * calls; ScopeGuard aims to correct these issues. * - * Two requirements for ScopeGuard: - * if Kokkos::is_initialized() in the constructor, don't call Kokkos::initialize or Kokkos::finalize - * it is not copyable or assignable + * Two requirements for ScopeGuard: + * if Kokkos::is_initialized() in the constructor, don't call + * Kokkos::initialize or Kokkos::finalize it is not copyable or assignable */ class ScopeGuard { -public: - ScopeGuard ( int& narg, char* arg[] ) - { - sg_init = false; - if ( ! Kokkos::is_initialized() ) { - initialize( narg, arg ); + public: + ScopeGuard(int& narg, char* arg[]) { + sg_init = false; + if (!Kokkos::is_initialized()) { + initialize(narg, arg); sg_init = true; } } - ScopeGuard ( const InitArguments& args = InitArguments() ) - { - sg_init = false; - if ( ! Kokkos::is_initialized() ) { - initialize( args ); + ScopeGuard(const InitArguments& args = InitArguments()) { + sg_init = false; + if (!Kokkos::is_initialized()) { + initialize(args); sg_init = true; } } - ~ScopeGuard( ) - { - if ( Kokkos::is_initialized() && sg_init) { - finalize(); + ~ScopeGuard() { + if (Kokkos::is_initialized() && sg_init) { + finalize(); } } -//private: - bool sg_init; - - ScopeGuard& operator=( const ScopeGuard& ) = delete; - ScopeGuard( const ScopeGuard& ) = delete; + // private: + bool sg_init; + ScopeGuard& operator=(const ScopeGuard&) = delete; + ScopeGuard(const ScopeGuard&) = delete; }; -} // namespace Kokkos +} // namespace Kokkos #include #include @@ -271,4 +255,3 @@ public: //---------------------------------------------------------------------------- #endif - diff --git a/lib/kokkos/core/src/Kokkos_Core_fwd.hpp b/lib/kokkos/core/src/Kokkos_Core_fwd.hpp index 55c6a5494a..5b89dc51ca 100644 --- a/lib/kokkos/core/src/Kokkos_Core_fwd.hpp +++ b/lib/kokkos/core/src/Kokkos_Core_fwd.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -57,8 +58,8 @@ //---------------------------------------------------------------------------- // Have assumed a 64bit build (8byte pointers) throughout the code base. -static_assert( sizeof(void*) == 8 - , "Kokkos assumes 64-bit build; i.e., 8-byte pointers" ); +static_assert(sizeof(void *) == 8, + "Kokkos assumes 64-bit build; i.e., 8-byte pointers"); //---------------------------------------------------------------------------- @@ -66,133 +67,137 @@ namespace Kokkos { struct AUTO_t { KOKKOS_INLINE_FUNCTION - constexpr const AUTO_t & operator()() const { return *this; } + constexpr const AUTO_t &operator()() const { return *this; } }; namespace { -/**\brief Token to indicate that a parameter's value is to be automatically selected */ +/**\brief Token to indicate that a parameter's value is to be automatically + * selected */ constexpr AUTO_t AUTO = Kokkos::AUTO_t(); -} +} // namespace struct InvalidType {}; -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- // Forward declarations for class inter-relationships namespace Kokkos { -class HostSpace; ///< Memory space for main process and CPU execution spaces +class HostSpace; ///< Memory space for main process and CPU execution spaces class AnonymousSpace; #ifdef KOKKOS_ENABLE_HBWSPACE namespace Experimental { -class HBWSpace; /// Memory space for hbw_malloc from memkind (e.g. for KNL processor) +class HBWSpace; /// Memory space for hbw_malloc from memkind (e.g. for KNL + /// processor) } #endif -#if defined( KOKKOS_ENABLE_SERIAL ) -class Serial; ///< Execution space main process on CPU. +#if defined(KOKKOS_ENABLE_SERIAL) +class Serial; ///< Execution space main process on CPU. #endif -#if defined( KOKKOS_ENABLE_QTHREADS ) +#if defined(KOKKOS_ENABLE_QTHREADS) class Qthreads; ///< Execution space with Qthreads back-end. #endif -#if defined( KOKKOS_ENABLE_HPX ) +#if defined(KOKKOS_ENABLE_HPX) namespace Experimental { class HPX; ///< Execution space with HPX back-end. } #endif -#if defined( KOKKOS_ENABLE_THREADS ) -class Threads; ///< Execution space with pthreads back-end. +#if defined(KOKKOS_ENABLE_THREADS) +class Threads; ///< Execution space with pthreads back-end. #endif -#if defined( KOKKOS_ENABLE_OPENMP ) -class OpenMP; ///< OpenMP execution space. +#if defined(KOKKOS_ENABLE_OPENMP) +class OpenMP; ///< OpenMP execution space. #endif -#if defined( KOKKOS_ENABLE_OPENMPTARGET ) +#if defined(KOKKOS_ENABLE_OPENMPTARGET) namespace Experimental { -class OpenMPTarget; ///< OpenMPTarget execution space. +class OpenMPTarget; ///< OpenMPTarget execution space. class OpenMPTargetSpace; -} +} // namespace Experimental #endif - -#if defined( KOKKOS_ENABLE_CUDA ) +#if defined(KOKKOS_ENABLE_CUDA) class CudaSpace; ///< Memory space on Cuda GPU class CudaUVMSpace; ///< Memory space on Cuda GPU with UVM class CudaHostPinnedSpace; ///< Memory space on Host accessible to Cuda GPU class Cuda; ///< Execution space for Cuda GPU #endif -#if defined( KOKKOS_ENABLE_ROCM ) +#if defined(KOKKOS_ENABLE_ROCM) namespace Experimental { -class ROCmSpace ; ///< Memory space on ROCm GPU -class ROCm ; ///< Execution space for ROCm GPU -} +class ROCmSpace; ///< Memory space on ROCm GPU +class ROCm; ///< Execution space for ROCm GPU +} // namespace Experimental #endif -template +template struct Device; -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- // Set the default execution space. /// Define Kokkos::DefaultExecutionSpace as per configuration option /// or chosen from the enabled execution spaces in the following order: -/// Kokkos::Cuda, Kokkos::Experimental::OpenMPTarget, Kokkos::OpenMP, Kokkos::Threads, Kokkos::Serial +/// Kokkos::Cuda, Kokkos::Experimental::OpenMPTarget, Kokkos::OpenMP, +/// Kokkos::Threads, Kokkos::Serial namespace Kokkos { -#if defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_CUDA ) - typedef Cuda DefaultExecutionSpace; -#elif defined ( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMPTARGET ) - typedef Experimental::OpenMPTarget DefaultExecutionSpace ; -#elif defined ( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_ROCM ) - typedef Experimental::ROCm DefaultExecutionSpace ; -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP ) - typedef OpenMP DefaultExecutionSpace; -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS ) - typedef Threads DefaultExecutionSpace; +#if defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_CUDA) +typedef Cuda DefaultExecutionSpace; +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMPTARGET) +typedef Experimental::OpenMPTarget DefaultExecutionSpace; +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_ROCM) +typedef Experimental::ROCm DefaultExecutionSpace; +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP) +typedef OpenMP DefaultExecutionSpace; +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS) +typedef Threads DefaultExecutionSpace; //#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_QTHREADS ) // typedef Qthreads DefaultExecutionSpace; -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX ) - typedef Kokkos::Experimental::HPX DefaultExecutionSpace; -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL ) - typedef Serial DefaultExecutionSpace; +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX) +typedef Kokkos::Experimental::HPX DefaultExecutionSpace; +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL) +typedef Serial DefaultExecutionSpace; #else -# error "At least one of the following execution spaces must be defined in order to use Kokkos: Kokkos::Cuda, Kokkos::Experimental::OpenMPTarget, Kokkos::OpenMP, Kokkos::Threads, Kokkos::Qthreads, or Kokkos::Serial." +#error \ + "At least one of the following execution spaces must be defined in order to use Kokkos: Kokkos::Cuda, Kokkos::Experimental::OpenMPTarget, Kokkos::OpenMP, Kokkos::Threads, Kokkos::Qthreads, or Kokkos::Serial." #endif -#if defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP ) - typedef OpenMP DefaultHostExecutionSpace; -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS ) - typedef Threads DefaultHostExecutionSpace; +#if defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP) +typedef OpenMP DefaultHostExecutionSpace; +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS) +typedef Threads DefaultHostExecutionSpace; //#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_QTHREADS ) // typedef Qthreads DefaultHostExecutionSpace; -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL ) - typedef Serial DefaultHostExecutionSpace; -#elif defined( KOKKOS_ENABLE_OPENMP ) - typedef OpenMP DefaultHostExecutionSpace; -#elif defined( KOKKOS_ENABLE_THREADS ) - typedef Threads DefaultHostExecutionSpace; +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL) +typedef Serial DefaultHostExecutionSpace; +#elif defined(KOKKOS_ENABLE_OPENMP) +typedef OpenMP DefaultHostExecutionSpace; +#elif defined(KOKKOS_ENABLE_THREADS) +typedef Threads DefaultHostExecutionSpace; //#elif defined( KOKKOS_ENABLE_QTHREADS ) // typedef Qthreads DefaultHostExecutionSpace; -#elif defined( KOKKOS_ENABLE_HPX ) - typedef Kokkos::Experimental::HPX DefaultHostExecutionSpace; -#elif defined( KOKKOS_ENABLE_SERIAL ) - typedef Serial DefaultHostExecutionSpace; +#elif defined(KOKKOS_ENABLE_HPX) +typedef Kokkos::Experimental::HPX DefaultHostExecutionSpace; +#elif defined(KOKKOS_ENABLE_SERIAL) +typedef Serial DefaultHostExecutionSpace; #else -# error "At least one of the following execution spaces must be defined in order to use Kokkos: Kokkos::OpenMP, Kokkos::Threads, Kokkos::Qthreads, or Kokkos::Serial." +#error \ + "At least one of the following execution spaces must be defined in order to use Kokkos: Kokkos::OpenMP, Kokkos::Threads, Kokkos::Qthreads, or Kokkos::Serial." #endif -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- // Detect the active execution space and define its memory space. @@ -203,44 +208,44 @@ namespace Kokkos { namespace Impl { -#if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_CUDA ) && defined( KOKKOS_ENABLE_CUDA ) -typedef Kokkos::CudaSpace ActiveExecutionMemorySpace; -#elif defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_ROCM_GPU ) -typedef Kokkos::HostSpace ActiveExecutionMemorySpace ; -#elif defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) -typedef Kokkos::HostSpace ActiveExecutionMemorySpace; +#if defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_CUDA) && \ + defined(KOKKOS_ENABLE_CUDA) +typedef Kokkos::CudaSpace ActiveExecutionMemorySpace; +#elif defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_ROCM_GPU) +typedef Kokkos::HostSpace ActiveExecutionMemorySpace; +#elif defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST) +typedef Kokkos::HostSpace ActiveExecutionMemorySpace; #else typedef void ActiveExecutionMemorySpace; #endif -template< class ActiveSpace, class MemorySpace > +template struct VerifyExecutionCanAccessMemorySpace { - enum {value = 0}; + enum { value = 0 }; }; -template< class Space > -struct VerifyExecutionCanAccessMemorySpace< Space, Space > -{ - enum {value = 1}; +template +struct VerifyExecutionCanAccessMemorySpace { + enum { value = 1 }; KOKKOS_INLINE_FUNCTION static void verify(void) {} KOKKOS_INLINE_FUNCTION static void verify(const void *) {} }; -} // namespace Impl +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos -#define KOKKOS_RESTRICT_EXECUTION_TO_DATA( DATA_SPACE, DATA_PTR ) \ - Kokkos::Impl::VerifyExecutionCanAccessMemorySpace< \ - Kokkos::Impl::ActiveExecutionMemorySpace, DATA_SPACE >::verify( DATA_PTR ) +#define KOKKOS_RESTRICT_EXECUTION_TO_DATA(DATA_SPACE, DATA_PTR) \ + Kokkos::Impl::VerifyExecutionCanAccessMemorySpace< \ + Kokkos::Impl::ActiveExecutionMemorySpace, DATA_SPACE>::verify(DATA_PTR) -#define KOKKOS_RESTRICT_EXECUTION_TO_( DATA_SPACE ) \ +#define KOKKOS_RESTRICT_EXECUTION_TO_(DATA_SPACE) \ Kokkos::Impl::VerifyExecutionCanAccessMemorySpace< \ - Kokkos::Impl::ActiveExecutionMemorySpace, DATA_SPACE >::verify() + Kokkos::Impl::ActiveExecutionMemorySpace, DATA_SPACE>::verify() //---------------------------------------------------------------------------- namespace Kokkos { - void fence(); +void fence(); } //---------------------------------------------------------------------------- @@ -249,29 +254,33 @@ namespace Kokkos { namespace Impl { -template< class DstSpace, class SrcSpace, class ExecutionSpace = typename DstSpace::execution_space > +template struct DeepCopy; -template +template struct ViewFillETIAvail; -template::value> +template ::value> struct ViewFill; -template +template struct ViewCopyETIAvail; -template::value> +template ::value> struct ViewCopy; -template< class Functor - , class Policy - , class EnableFunctor = void - , class EnablePolicy = void - > +template struct FunctorPolicyExecutionSpace; //---------------------------------------------------------------------------- @@ -281,18 +290,20 @@ struct FunctorPolicyExecutionSpace; /// /// This is an implementation detail of parallel_for. Users should /// skip this and go directly to the nonmember function parallel_for. -template< class FunctorType, class ExecPolicy, class ExecutionSpace = - typename Impl::FunctorPolicyExecutionSpace< FunctorType, ExecPolicy >::execution_space - > class ParallelFor; +template ::execution_space> +class ParallelFor; /// \class ParallelReduce /// \brief Implementation detail of parallel_reduce. /// /// This is an implementation detail of parallel_reduce. Users should /// skip this and go directly to the nonmember function parallel_reduce. -template< class FunctorType, class ExecPolicy, class ReducerType = InvalidType, class ExecutionSpace = - typename Impl::FunctorPolicyExecutionSpace< FunctorType, ExecPolicy >::execution_space - > class ParallelReduce; +template ::execution_space> +class ParallelReduce; /// \class ParallelScan /// \brief Implementation detail of parallel_scan. @@ -300,56 +311,71 @@ template< class FunctorType, class ExecPolicy, class ReducerType = InvalidType, /// This is an implementation detail of parallel_scan. Users should /// skip this and go directly to the documentation of the nonmember /// template function Kokkos::parallel_scan. -template< class FunctorType, class ExecPolicy, class ExecutionSapce = - typename Impl::FunctorPolicyExecutionSpace< FunctorType, ExecPolicy >::execution_space - > class ParallelScan; - -template< class FunctorType, class ExecPolicy, class ReturnType = InvalidType, class ExecutionSapce = - typename Impl::FunctorPolicyExecutionSpace< FunctorType, ExecPolicy >::execution_space - > class ParallelScanWithTotal; - -} // namespace Impl - -template struct Sum; -template struct Prod; -template struct Min; -template struct Max; -template struct MinMax; -template struct MinLoc; -template struct MaxLoc; -template struct MinMaxLoc; -template struct BAnd; -template struct BOr; -template struct LAnd; -template struct LOr; - - -} // namespace Kokkos +template ::execution_space> +class ParallelScan; + +template ::execution_space> +class ParallelScanWithTotal; + +} // namespace Impl + +template +struct Sum; +template +struct Prod; +template +struct Min; +template +struct Max; +template +struct MinMax; +template +struct MinLoc; +template +struct MaxLoc; +template +struct MinMaxLoc; +template +struct BAnd; +template +struct BOr; +template +struct LAnd; +template +struct LOr; + +} // namespace Kokkos #ifdef KOKKOS_ENABLE_DEPRECATED_CODE -namespace Kokkos{ - template struct MinMaxScalar; - template struct MinMaxLocScalar; - template struct ValLocScalar; - - namespace Experimental { - using Kokkos::Sum; - using Kokkos::Prod; - using Kokkos::Min; - using Kokkos::Max; - using Kokkos::MinMax; - using Kokkos::MinLoc; - using Kokkos::MaxLoc; - using Kokkos::MinMaxLoc; - using Kokkos::BAnd; - using Kokkos::BOr; - using Kokkos::LAnd; - using Kokkos::LOr; - using Kokkos::MinMaxScalar; - using Kokkos::MinMaxLocScalar; - using Kokkos::ValLocScalar; - } -} +namespace Kokkos { +template +struct MinMaxScalar; +template +struct MinMaxLocScalar; +template +struct ValLocScalar; + +namespace Experimental { +using Kokkos::BAnd; +using Kokkos::BOr; +using Kokkos::LAnd; +using Kokkos::LOr; +using Kokkos::Max; +using Kokkos::MaxLoc; +using Kokkos::Min; +using Kokkos::MinLoc; +using Kokkos::MinMax; +using Kokkos::MinMaxLoc; +using Kokkos::MinMaxLocScalar; +using Kokkos::MinMaxScalar; +using Kokkos::Prod; +using Kokkos::Sum; +using Kokkos::ValLocScalar; +} // namespace Experimental +} // namespace Kokkos #endif #endif /* #ifndef KOKKOS_CORE_FWD_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_Crs.hpp b/lib/kokkos/core/src/Kokkos_Crs.hpp index 8412ced921..f57863263b 100644 --- a/lib/kokkos/core/src/Kokkos_Crs.hpp +++ b/lib/kokkos/core/src/Kokkos_Crs.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -76,26 +77,27 @@ namespace Kokkos { ///

  • entries( entry , i2 , i3 , ... );
  • ///
  • entries( row_map[i0] + i1 , i2 , i3 , ... );
  • /// -template< class DataType, - class Arg1Type, - class Arg2Type = void, - typename SizeType = typename ViewTraits::size_type> +template ::size_type> class Crs { -protected: + protected: typedef ViewTraits traits; -public: - typedef DataType data_type; - typedef typename traits::array_layout array_layout; - typedef typename traits::execution_space execution_space; - typedef typename traits::memory_space memory_space; - typedef typename traits::device_type device_type; - typedef SizeType size_type; - - typedef Crs< DataType , Arg1Type , Arg2Type , SizeType > staticcrsgraph_type; - typedef Crs< DataType , array_layout , typename traits::host_mirror_space , SizeType > HostMirror; - typedef View row_map_type; - typedef View entries_type; + public: + typedef DataType data_type; + typedef typename traits::array_layout array_layout; + typedef typename traits::execution_space execution_space; + typedef typename traits::memory_space memory_space; + typedef typename traits::device_type device_type; + typedef SizeType size_type; + + typedef Crs staticcrsgraph_type; + typedef Crs + HostMirror; + typedef View row_map_type; + typedef View entries_type; row_map_type row_map; entries_type entries; @@ -103,62 +105,49 @@ public: /* * Default Constructors, operators and destructor */ - KOKKOS_FUNCTION Crs() = default; - KOKKOS_FUNCTION Crs(Crs const &) = default; - KOKKOS_FUNCTION Crs(Crs &&) = default; - KOKKOS_FUNCTION Crs& operator=(Crs const &) = default; - KOKKOS_FUNCTION Crs& operator=(Crs &&) = default; - KOKKOS_FUNCTION ~Crs() = default; + KOKKOS_FUNCTION Crs() = default; + KOKKOS_FUNCTION Crs(Crs const&) = default; + KOKKOS_FUNCTION Crs(Crs&&) = default; + KOKKOS_FUNCTION Crs& operator=(Crs const&) = default; + KOKKOS_FUNCTION Crs& operator=(Crs&&) = default; + KOKKOS_FUNCTION ~Crs() = default; /** \brief Assign to a view of the rhs array. * If the old view is the last view * then allocated memory is deallocated. */ - template - KOKKOS_INLINE_FUNCTION - Crs(const RowMapType& row_map_, const EntriesType& entries_) - : row_map(row_map_), entries(entries_) - { - } + template + KOKKOS_INLINE_FUNCTION Crs(const RowMapType& row_map_, + const EntriesType& entries_) + : row_map(row_map_), entries(entries_) {} /** \brief Return number of rows in the graph */ KOKKOS_INLINE_FUNCTION size_type numRows() const { - return (row_map.extent(0) != 0) ? - row_map.extent(0) - static_cast (1) : - static_cast (0); + return (row_map.extent(0) != 0) + ? row_map.extent(0) - static_cast(1) + : static_cast(0); } }; /*--------------------------------------------------------------------------*/ -template< class OutCounts, - class DataType, - class Arg1Type, - class Arg2Type, +template void get_crs_transpose_counts( - OutCounts& out, - Crs const& in, + OutCounts& out, Crs const& in, std::string const& name = "transpose_counts"); -template< class OutCounts, - class InCrs> +template typename OutCounts::value_type get_crs_row_map_from_counts( - OutCounts& out, - InCrs const& in, - std::string const& name = "row_map"); + OutCounts& out, InCrs const& in, std::string const& name = "row_map"); -template< class DataType, - class Arg1Type, - class Arg2Type, - class SizeType> -void transpose_crs( - Crs& out, - Crs const& in); +template +void transpose_crs(Crs& out, + Crs const& in); -} // namespace Kokkos +} // namespace Kokkos /*--------------------------------------------------------------------------*/ @@ -171,21 +160,22 @@ template class GetCrsTransposeCounts { public: using execution_space = typename InCrs::execution_space; - using self_type = GetCrsTransposeCounts; - using index_type = typename InCrs::size_type; + using self_type = GetCrsTransposeCounts; + using index_type = typename InCrs::size_type; + private: InCrs in; OutCounts out; + public: KOKKOS_INLINE_FUNCTION - void operator()(index_type i) const { - atomic_increment( &out[in.entries(i)] ); - } - GetCrsTransposeCounts(InCrs const& arg_in, OutCounts const& arg_out): - in(arg_in),out(arg_out) { - using policy_type = RangePolicy; + void operator()(index_type i) const { atomic_increment(&out[in.entries(i)]); } + GetCrsTransposeCounts(InCrs const& arg_in, OutCounts const& arg_out) + : in(arg_in), out(arg_out) { + using policy_type = RangePolicy; using closure_type = Kokkos::Impl::ParallelFor; - const closure_type closure(*this, policy_type(0, index_type(in.entries.size()))); + const closure_type closure(*this, + policy_type(0, index_type(in.entries.size()))); closure.execute(); execution_space().fence(); } @@ -195,13 +185,15 @@ template class CrsRowMapFromCounts { public: using execution_space = typename InCounts::execution_space; - using value_type = typename OutRowMap::value_type; - using index_type = typename InCounts::size_type; + using value_type = typename OutRowMap::value_type; + using index_type = typename InCounts::size_type; using last_value_type = Kokkos::View; + private: InCounts m_in; OutRowMap m_out; last_value_type m_last_value; + public: KOKKOS_INLINE_FUNCTION void operator()(index_type i, value_type& update, bool final_pass) const { @@ -209,22 +201,22 @@ class CrsRowMapFromCounts { update += m_in(i); if (final_pass) m_out(i + 1) = update; } else if (final_pass) { - m_out(0) = 0; + m_out(0) = 0; m_last_value() = update; } } KOKKOS_INLINE_FUNCTION void init(value_type& update) const { update = 0; } KOKKOS_INLINE_FUNCTION - void join(volatile value_type& update, const volatile value_type& input) const { + void join(volatile value_type& update, + const volatile value_type& input) const { update += input; } using self_type = CrsRowMapFromCounts; - CrsRowMapFromCounts(InCounts const& arg_in, OutRowMap const& arg_out): - m_in(arg_in), m_out(arg_out), m_last_value("last_value") { - } + CrsRowMapFromCounts(InCounts const& arg_in, OutRowMap const& arg_out) + : m_in(arg_in), m_out(arg_out), m_last_value("last_value") {} value_type execute() { - using policy_type = RangePolicy; + using policy_type = RangePolicy; using closure_type = Kokkos::Impl::ParallelScan; closure_type closure(*this, policy_type(0, m_in.size() + 1)); closure.execute(); @@ -238,31 +230,32 @@ template class FillCrsTransposeEntries { public: using execution_space = typename InCrs::execution_space; - using memory_space = typename InCrs::memory_space; - using value_type = typename OutCrs::entries_type::value_type; - using index_type = typename InCrs::size_type; + using memory_space = typename InCrs::memory_space; + using value_type = typename OutCrs::entries_type::value_type; + using index_type = typename InCrs::size_type; + private: using counters_type = View; InCrs in; OutCrs out; counters_type counters; + public: KOKKOS_INLINE_FUNCTION void operator()(index_type i) const { auto begin = in.row_map(i); - auto end = in.row_map(i + 1); + auto end = in.row_map(i + 1); for (auto j = begin; j < end; ++j) { - auto ti = in.entries(j); - auto tbegin = out.row_map(ti); - auto tj = atomic_fetch_add( &counters(ti), 1 ); - out.entries( tbegin + tj ) = i; + auto ti = in.entries(j); + auto tbegin = out.row_map(ti); + auto tj = atomic_fetch_add(&counters(ti), 1); + out.entries(tbegin + tj) = i; } } using self_type = FillCrsTransposeEntries; - FillCrsTransposeEntries(InCrs const& arg_in, OutCrs const& arg_out): - in(arg_in),out(arg_out), - counters("counters", arg_out.numRows()) { - using policy_type = RangePolicy; + FillCrsTransposeEntries(InCrs const& arg_in, OutCrs const& arg_out) + : in(arg_in), out(arg_out), counters("counters", arg_out.numRows()) { + using policy_type = RangePolicy; using closure_type = Kokkos::Impl::ParallelFor; const closure_type closure(*this, policy_type(0, index_type(in.numRows()))); closure.execute(); @@ -270,7 +263,8 @@ class FillCrsTransposeEntries { } }; -}} // namespace Kokkos::Impl +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ @@ -278,66 +272,51 @@ class FillCrsTransposeEntries { namespace Kokkos { -template< class OutCounts, - class DataType, - class Arg1Type, - class Arg2Type, +template void get_crs_transpose_counts( - OutCounts& out, - Crs const& in, + OutCounts& out, Crs const& in, std::string const& name) { using InCrs = Crs; - out = OutCounts(name, in.numRows()); + out = OutCounts(name, in.numRows()); Kokkos::Impl::GetCrsTransposeCounts functor(in, out); } -template< class OutRowMap, - class InCounts> +template typename OutRowMap::value_type get_crs_row_map_from_counts( - OutRowMap& out, - InCounts const& in, - std::string const& name) { + OutRowMap& out, InCounts const& in, std::string const& name) { out = OutRowMap(ViewAllocateWithoutInitializing(name), in.size() + 1); Kokkos::Impl::CrsRowMapFromCounts functor(in, out); return functor.execute(); } -template< class DataType, - class Arg1Type, - class Arg2Type, - class SizeType> -void transpose_crs( - Crs& out, - Crs const& in) -{ - typedef Crs crs_type ; - typedef typename crs_type::memory_space memory_space ; - typedef View counts_type ; +template +void transpose_crs(Crs& out, + Crs const& in) { + typedef Crs crs_type; + typedef typename crs_type::memory_space memory_space; + typedef View counts_type; { - counts_type counts; - Kokkos::get_crs_transpose_counts(counts, in); - Kokkos::get_crs_row_map_from_counts(out.row_map, counts, - "tranpose_row_map"); + counts_type counts; + Kokkos::get_crs_transpose_counts(counts, in); + Kokkos::get_crs_row_map_from_counts(out.row_map, counts, + "tranpose_row_map"); } out.entries = decltype(out.entries)("transpose_entries", in.entries.size()); - Kokkos::Impl:: - FillCrsTransposeEntries entries_functor(in, out); + Kokkos::Impl::FillCrsTransposeEntries entries_functor( + in, out); } -template< class CrsType, - class Functor, +template struct CountAndFillBase; -template< class CrsType, - class Functor, - class ExecutionSpace> +template struct CountAndFillBase { - using data_type = typename CrsType::size_type; - using size_type = typename CrsType::size_type; + using data_type = typename CrsType::size_type; + using size_type = typename CrsType::size_type; using row_map_type = typename CrsType::row_map_type; - using counts_type = row_map_type; + using counts_type = row_map_type; CrsType m_crs; Functor m_functor; counts_type m_counts; @@ -348,30 +327,26 @@ struct CountAndFillBase { struct Fill {}; inline void operator()(Fill, size_type i) const { auto j = m_crs.row_map(i); - /* we don't want to access entries(entries.size()), even if its just to get its - address and never use it. - this can happen when row (i) is empty and all rows after it are also empty. - we could compare to row_map(i + 1), but that is a read from global memory, - whereas dimension_0() should be part of the View in registers (or constant memory) */ - data_type* fill = - (j == static_cast(m_crs.entries.extent(0))) ? - nullptr : (&(m_crs.entries(j))); + /* we don't want to access entries(entries.size()), even if its just to get + its address and never use it. this can happen when row (i) is empty and + all rows after it are also empty. we could compare to row_map(i + 1), but + that is a read from global memory, whereas dimension_0() should be part + of the View in registers (or constant memory) */ + data_type* fill = (j == static_cast(m_crs.entries.extent(0))) + ? nullptr + : (&(m_crs.entries(j))); m_functor(i, fill); } - CountAndFillBase(CrsType& crs, Functor const& f): - m_crs(crs), - m_functor(f) - {} + CountAndFillBase(CrsType& crs, Functor const& f) : m_crs(crs), m_functor(f) {} }; -#if defined( KOKKOS_ENABLE_CUDA ) -template< class CrsType, - class Functor> +#if defined(KOKKOS_ENABLE_CUDA) +template struct CountAndFillBase { - using data_type = typename CrsType::size_type; - using size_type = typename CrsType::size_type; + using data_type = typename CrsType::size_type; + using size_type = typename CrsType::size_type; using row_map_type = typename CrsType::row_map_type; - using counts_type = row_map_type; + using counts_type = row_map_type; CrsType m_crs; Functor m_functor; counts_type m_counts; @@ -382,70 +357,62 @@ struct CountAndFillBase { struct Fill {}; __device__ inline void operator()(Fill, size_type i) const { auto j = m_crs.row_map(i); - /* we don't want to access entries(entries.size()), even if its just to get its - address and never use it. - this can happen when row (i) is empty and all rows after it are also empty. - we could compare to row_map(i + 1), but that is a read from global memory, - whereas dimension_0() should be part of the View in registers (or constant memory) */ - data_type* fill = - (j == static_cast(m_crs.entries.extent(0))) ? - nullptr : (&(m_crs.entries(j))); + /* we don't want to access entries(entries.size()), even if its just to get + its address and never use it. this can happen when row (i) is empty and + all rows after it are also empty. we could compare to row_map(i + 1), but + that is a read from global memory, whereas dimension_0() should be part + of the View in registers (or constant memory) */ + data_type* fill = (j == static_cast(m_crs.entries.extent(0))) + ? nullptr + : (&(m_crs.entries(j))); m_functor(i, fill); } - CountAndFillBase(CrsType& crs, Functor const& f): - m_crs(crs), - m_functor(f) - {} + CountAndFillBase(CrsType& crs, Functor const& f) : m_crs(crs), m_functor(f) {} }; #endif -template< class CrsType, - class Functor> +template struct CountAndFill : public CountAndFillBase { using base_type = CountAndFillBase; - using typename base_type::data_type; - using typename base_type::size_type; - using typename base_type::counts_type; using typename base_type::Count; + using typename base_type::counts_type; + using typename base_type::data_type; using typename base_type::Fill; + using typename base_type::size_type; using entries_type = typename CrsType::entries_type; - using self_type = CountAndFill; - CountAndFill(CrsType& crs, size_type nrows, Functor const& f): - base_type(crs, f) - { + using self_type = CountAndFill; + CountAndFill(CrsType& crs, size_type nrows, Functor const& f) + : base_type(crs, f) { using execution_space = typename CrsType::execution_space; - this->m_counts = counts_type("counts", nrows); + this->m_counts = counts_type("counts", nrows); { - using count_policy_type = RangePolicy; - using count_closure_type = - Kokkos::Impl::ParallelFor; - const count_closure_type closure(*this, count_policy_type(0, nrows)); - closure.execute(); + using count_policy_type = RangePolicy; + using count_closure_type = + Kokkos::Impl::ParallelFor; + const count_closure_type closure(*this, count_policy_type(0, nrows)); + closure.execute(); } - auto nentries = Kokkos:: - get_crs_row_map_from_counts(this->m_crs.row_map, this->m_counts); + auto nentries = Kokkos::get_crs_row_map_from_counts(this->m_crs.row_map, + this->m_counts); this->m_counts = counts_type(); this->m_crs.entries = entries_type("entries", nentries); { - using fill_policy_type = RangePolicy; - using fill_closure_type = - Kokkos::Impl::ParallelFor; - const fill_closure_type closure(*this, fill_policy_type(0, nrows)); - closure.execute(); + using fill_policy_type = RangePolicy; + using fill_closure_type = + Kokkos::Impl::ParallelFor; + const fill_closure_type closure(*this, fill_policy_type(0, nrows)); + closure.execute(); } crs = this->m_crs; } }; -template< class CrsType, - class Functor> -void count_and_fill_crs( - CrsType& crs, - typename CrsType::size_type nrows, - Functor const& f) { +template +void count_and_fill_crs(CrsType& crs, typename CrsType::size_type nrows, + Functor const& f) { Kokkos::CountAndFill(crs, nrows, f); } -} // namespace Kokkos +} // namespace Kokkos #endif /* #define KOKKOS_CRS_HPP */ diff --git a/lib/kokkos/core/src/Kokkos_Cuda.hpp b/lib/kokkos/core/src/Kokkos_Cuda.hpp index 4eb8ab4d4b..ad62ecf383 100644 --- a/lib/kokkos/core/src/Kokkos_Cuda.hpp +++ b/lib/kokkos/core/src/Kokkos_Cuda.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,7 +46,7 @@ #define KOKKOS_CUDA_HPP #include -#if defined( KOKKOS_ENABLE_CUDA ) +#if defined(KOKKOS_ENABLE_CUDA) #include @@ -62,37 +63,45 @@ #include #include - /*--------------------------------------------------------------------------*/ namespace Kokkos { namespace Impl { -class CudaExec ; -class CudaInternal ; -} // namespace Impl -} // namespace Kokkos +class CudaExec; +class CudaInternal; +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ namespace Kokkos { namespace Impl { - namespace Experimental { - enum class CudaLaunchMechanism:unsigned{Default=0,ConstantMemory=1,GlobalMemory=2,LocalMemory=4}; - - constexpr inline CudaLaunchMechanism operator | (CudaLaunchMechanism p1, CudaLaunchMechanism p2) { - return static_cast(static_cast(p1) | static_cast(p2)); - } - constexpr inline CudaLaunchMechanism operator & (CudaLaunchMechanism p1, CudaLaunchMechanism p2) { - return static_cast(static_cast(p1) & static_cast(p2)); - } - - template - struct CudaDispatchProperties { - CudaLaunchMechanism launch_mechanism = l; - }; - } +namespace Experimental { +enum class CudaLaunchMechanism : unsigned { + Default = 0, + ConstantMemory = 1, + GlobalMemory = 2, + LocalMemory = 4 +}; + +constexpr inline CudaLaunchMechanism operator|(CudaLaunchMechanism p1, + CudaLaunchMechanism p2) { + return static_cast(static_cast(p1) | + static_cast(p2)); } +constexpr inline CudaLaunchMechanism operator&(CudaLaunchMechanism p1, + CudaLaunchMechanism p2) { + return static_cast(static_cast(p1) & + static_cast(p2)); +} + +template +struct CudaDispatchProperties { + CudaLaunchMechanism launch_mechanism = l; +}; +} // namespace Experimental +} // namespace Impl /// \class Cuda /// \brief Kokkos Execution Space that uses CUDA to run on GPUs. /// @@ -104,32 +113,32 @@ namespace Impl { /// sequentially. The Cuda execution space uses NVIDIA's CUDA programming /// model to execute kernels in parallel on GPUs. class Cuda { -public: + public: //! \name Type declarations that all Kokkos execution spaces must provide. //@{ //! Tag this class as a kokkos execution space - typedef Cuda execution_space ; + typedef Cuda execution_space; -#if defined( KOKKOS_ENABLE_CUDA_UVM ) +#if defined(KOKKOS_ENABLE_CUDA_UVM) //! This execution space's preferred memory space. - typedef CudaUVMSpace memory_space ; + typedef CudaUVMSpace memory_space; #else //! This execution space's preferred memory space. - typedef CudaSpace memory_space ; + typedef CudaSpace memory_space; #endif //! This execution space preferred device_type - typedef Kokkos::Device device_type; + typedef Kokkos::Device device_type; //! The size_type best suited for this execution space. - typedef memory_space::size_type size_type ; + typedef memory_space::size_type size_type; //! This execution space's preferred array layout. - typedef LayoutLeft array_layout ; + typedef LayoutLeft array_layout; //! - typedef ScratchMemorySpace< Cuda > scratch_memory_space ; + typedef ScratchMemorySpace scratch_memory_space; //@} //-------------------------------------------------- @@ -139,7 +148,7 @@ public: /// \brief True if and only if this method is being called in a /// thread-parallel function. KOKKOS_INLINE_FUNCTION static int in_parallel() { -#if defined( __CUDA_ARCH__ ) +#if defined(__CUDA_ARCH__) return true; #else return false; @@ -174,17 +183,17 @@ public: /// device have completed. static void impl_static_fence(); - #ifdef KOKKOS_ENABLE_DEPRECATED_CODE +#ifdef KOKKOS_ENABLE_DEPRECATED_CODE static void fence(); - #else +#else void fence() const; - #endif +#endif /** \brief Return the maximum amount of concurrency. */ static int concurrency(); //! Print configuration information to the given output stream. - static void print_configuration( std::ostream & , const bool detail = false ); + static void print_configuration(std::ostream&, const bool detail = false); //@} //-------------------------------------------------- @@ -195,10 +204,10 @@ public: Cuda(); - Cuda( Cuda && ) = default ; - Cuda( const Cuda & ) = default ; - Cuda & operator = ( Cuda && ) = default ; - Cuda & operator = ( const Cuda & ) = default ; + Cuda(Cuda&&) = default; + Cuda(const Cuda&) = default; + Cuda& operator=(Cuda&&) = default; + Cuda& operator=(const Cuda&) = default; Cuda(cudaStream_t stream); @@ -207,9 +216,9 @@ public: //@{ struct SelectDevice { - int cuda_device_id ; + int cuda_device_id; SelectDevice() : cuda_device_id(0) {} - explicit SelectDevice( int id ) : cuda_device_id( id ) {} + explicit SelectDevice(int id) : cuda_device_id(id) {} }; #ifdef KOKKOS_ENABLE_DEPRECATED_CODE @@ -220,8 +229,8 @@ public: static int is_initialized(); //! Initialize, telling the CUDA run-time library which device to use. - static void initialize( const SelectDevice = SelectDevice() - , const size_t num_instances = 1 ); + static void initialize(const SelectDevice = SelectDevice(), + const size_t num_instances = 1); #else //! Free any resources being consumed by the device. static void impl_finalize(); @@ -230,8 +239,8 @@ public: static int impl_is_initialized(); //! Initialize, telling the CUDA run-time library which device to use. - static void impl_initialize( const SelectDevice = SelectDevice() - , const size_t num_instances = 1 ); + static void impl_initialize(const SelectDevice = SelectDevice(), + const size_t num_instances = 1); #endif /// \brief Cuda device architecture of the selected device. @@ -248,20 +257,22 @@ public: static std::vector detect_device_arch(); cudaStream_t cuda_stream() const; - int cuda_device() const; + int cuda_device() const; //@} //-------------------------------------------------------------------------- static const char* name(); - inline Impl::CudaInternal* impl_internal_space_instance() const { return m_space_instance; } -private: + inline Impl::CudaInternal* impl_internal_space_instance() const { + return m_space_instance; + } + private: Impl::CudaInternal* m_space_instance; }; -} // namespace Kokkos +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -269,18 +280,15 @@ private: namespace Kokkos { namespace Impl { -template<> -struct MemorySpaceAccess - < Kokkos::CudaSpace - , Kokkos::Cuda::scratch_memory_space - > -{ +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = true }; - enum { deepcopy = false }; + enum { deepcopy = false }; }; -#if defined( KOKKOS_ENABLE_CUDA_UVM ) +#if defined(KOKKOS_ENABLE_CUDA_UVM) // If forcing use of UVM everywhere // then must assume that CudaUVMSpace @@ -288,44 +296,34 @@ struct MemorySpaceAccess // This will fail when a strange host-side execution space // that defines CudaUVMSpace as its preferredmemory space. -template<> -struct MemorySpaceAccess - < Kokkos::CudaUVMSpace - , Kokkos::Cuda::scratch_memory_space - > -{ +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = true }; - enum { deepcopy = false }; + enum { deepcopy = false }; }; #endif - -template<> -struct VerifyExecutionCanAccessMemorySpace - < Kokkos::CudaSpace - , Kokkos::Cuda::scratch_memory_space - > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = true }; - KOKKOS_INLINE_FUNCTION static void verify( void ) { } - KOKKOS_INLINE_FUNCTION static void verify( const void * ) { } + KOKKOS_INLINE_FUNCTION static void verify(void) {} + KOKKOS_INLINE_FUNCTION static void verify(const void*) {} }; -template<> -struct VerifyExecutionCanAccessMemorySpace - < Kokkos::HostSpace - , Kokkos::Cuda::scratch_memory_space - > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = false }; - inline static void verify( void ) { CudaSpace::access_error(); } - inline static void verify( const void * p ) { CudaSpace::access_error(p); } + inline static void verify(void) { CudaSpace::access_error(); } + inline static void verify(const void* p) { CudaSpace::access_error(p); } }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -343,4 +341,3 @@ struct VerifyExecutionCanAccessMemorySpace #endif /* #if defined( KOKKOS_ENABLE_CUDA ) */ #endif /* #ifndef KOKKOS_CUDA_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_CudaSpace.hpp b/lib/kokkos/core/src/Kokkos_CudaSpace.hpp index 4b32811bfc..a320aea2f8 100644 --- a/lib/kokkos/core/src/Kokkos_CudaSpace.hpp +++ b/lib/kokkos/core/src/Kokkos_CudaSpace.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,7 +46,7 @@ #define KOKKOS_CUDASPACE_HPP #include -#if defined( KOKKOS_ENABLE_CUDA ) +#if defined(KOKKOS_ENABLE_CUDA) #include @@ -57,6 +58,11 @@ #include +#ifdef KOKKOS_IMPL_DEBUG_CUDA_PIN_UVM_TO_HOST +extern "C" bool kokkos_impl_cuda_pin_uvm_to_host(); +extern "C" void kokkos_impl_cuda_set_pin_uvm_to_host(bool); +#endif + /*--------------------------------------------------------------------------*/ namespace Kokkos { @@ -64,30 +70,28 @@ namespace Kokkos { /** \brief Cuda on-device memory management */ class CudaSpace { -public: - + public: //! Tag this class as a kokkos memory space - typedef CudaSpace memory_space ; - typedef Kokkos::Cuda execution_space ; - typedef Kokkos::Device device_type; + typedef CudaSpace memory_space; + typedef Kokkos::Cuda execution_space; + typedef Kokkos::Device device_type; - typedef unsigned int size_type ; + typedef unsigned int size_type; /*--------------------------------*/ CudaSpace(); - CudaSpace( CudaSpace && rhs ) = default ; - CudaSpace( const CudaSpace & rhs ) = default ; - CudaSpace & operator = ( CudaSpace && rhs ) = default ; - CudaSpace & operator = ( const CudaSpace & rhs ) = default ; - ~CudaSpace() = default ; + CudaSpace(CudaSpace&& rhs) = default; + CudaSpace(const CudaSpace& rhs) = default; + CudaSpace& operator=(CudaSpace&& rhs) = default; + CudaSpace& operator=(const CudaSpace& rhs) = default; + ~CudaSpace() = default; /**\brief Allocate untracked memory in the cuda space */ - void * allocate( const size_t arg_alloc_size ) const ; + void* allocate(const size_t arg_alloc_size) const; /**\brief Deallocate untracked memory in the cuda space */ - void deallocate( void * const arg_alloc_ptr - , const size_t arg_alloc_size ) const ; + void deallocate(void* const arg_alloc_ptr, const size_t arg_alloc_size) const; /**\brief Return Name of the MemorySpace */ static constexpr const char* name() { return m_name; } @@ -95,14 +99,13 @@ public: /*--------------------------------*/ /** \brief Error reporting for HostSpace attempt to access CudaSpace */ static void access_error(); - static void access_error( const void * const ); - -private: + static void access_error(const void* const); - int m_device ; ///< Which Cuda device + private: + int m_device; ///< Which Cuda device static constexpr const char* m_name = "Cuda"; - friend class Kokkos::Impl::SharedAllocationRecord< Kokkos::CudaSpace , void > ; + friend class Kokkos::Impl::SharedAllocationRecord; }; namespace Impl { @@ -123,10 +126,11 @@ void init_lock_arrays_cuda_space(); /// If the array is not yet allocated it will do so. int* atomic_lock_array_cuda_space_ptr(bool deallocate = false); -/// \brief Retrieve the pointer to the scratch array for team and thread private global memory. +/// \brief Retrieve the pointer to the scratch array for team and thread private +/// global memory. /// /// Team and Thread private scratch allocations in -/// global memory are acquired via locks. +/// global memory are aquired via locks. /// This function retrieves the lock array pointer. /// If the array is not yet allocated it will do so. int* scratch_lock_array_cuda_space_ptr(bool deallocate = false); @@ -138,8 +142,8 @@ int* scratch_lock_array_cuda_space_ptr(bool deallocate = false); /// This function retrieves the lock array pointer. /// If the array is not yet allocated it will do so. int* threadid_lock_array_cuda_space_ptr(bool deallocate = false); -} -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -150,54 +154,56 @@ namespace Kokkos { * through Cuda's unified virtual memory (UVM) runtime. */ class CudaUVMSpace { -public: - + public: //! Tag this class as a kokkos memory space - typedef CudaUVMSpace memory_space ; - typedef Cuda execution_space ; - typedef Kokkos::Device device_type; - typedef unsigned int size_type ; + typedef CudaUVMSpace memory_space; + typedef Cuda execution_space; + typedef Kokkos::Device device_type; + typedef unsigned int size_type; /** \brief If UVM capability is available */ static bool available(); - /*--------------------------------*/ /** \brief CudaUVMSpace specific routine */ static int number_of_allocations(); /*--------------------------------*/ - /*--------------------------------*/ CudaUVMSpace(); - CudaUVMSpace( CudaUVMSpace && rhs ) = default ; - CudaUVMSpace( const CudaUVMSpace & rhs ) = default ; - CudaUVMSpace & operator = ( CudaUVMSpace && rhs ) = default ; - CudaUVMSpace & operator = ( const CudaUVMSpace & rhs ) = default ; - ~CudaUVMSpace() = default ; + CudaUVMSpace(CudaUVMSpace&& rhs) = default; + CudaUVMSpace(const CudaUVMSpace& rhs) = default; + CudaUVMSpace& operator=(CudaUVMSpace&& rhs) = default; + CudaUVMSpace& operator=(const CudaUVMSpace& rhs) = default; + ~CudaUVMSpace() = default; /**\brief Allocate untracked memory in the cuda space */ - void * allocate( const size_t arg_alloc_size ) const ; + void* allocate(const size_t arg_alloc_size) const; /**\brief Deallocate untracked memory in the cuda space */ - void deallocate( void * const arg_alloc_ptr - , const size_t arg_alloc_size ) const ; + void deallocate(void* const arg_alloc_ptr, const size_t arg_alloc_size) const; /**\brief Return Name of the MemorySpace */ static constexpr const char* name() { return m_name; } +#ifdef KOKKOS_IMPL_DEBUG_CUDA_PIN_UVM_TO_HOST + static bool cuda_pin_uvm_to_host(); + static void cuda_set_pin_uvm_to_host(bool val); +#endif /*--------------------------------*/ -private: - int m_device ; ///< Which Cuda device + private: + int m_device; ///< Which Cuda device +#ifdef KOKKOS_IMPL_DEBUG_CUDA_PIN_UVM_TO_HOST + static bool kokkos_impl_cuda_pin_uvm_to_host_v; +#endif static constexpr const char* m_name = "CudaUVM"; - }; -} // namespace Kokkos +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -208,42 +214,39 @@ namespace Kokkos { * through Cuda's host-pinned memory allocation. */ class CudaHostPinnedSpace { -public: - + public: //! Tag this class as a kokkos memory space /** \brief Memory is in HostSpace so use the HostSpace::execution_space */ - typedef HostSpace::execution_space execution_space ; - typedef CudaHostPinnedSpace memory_space ; - typedef Kokkos::Device device_type; - typedef unsigned int size_type ; + typedef HostSpace::execution_space execution_space; + typedef CudaHostPinnedSpace memory_space; + typedef Kokkos::Device device_type; + typedef unsigned int size_type; /*--------------------------------*/ CudaHostPinnedSpace(); - CudaHostPinnedSpace( CudaHostPinnedSpace && rhs ) = default ; - CudaHostPinnedSpace( const CudaHostPinnedSpace & rhs ) = default ; - CudaHostPinnedSpace & operator = ( CudaHostPinnedSpace && rhs ) = default ; - CudaHostPinnedSpace & operator = ( const CudaHostPinnedSpace & rhs ) = default ; - ~CudaHostPinnedSpace() = default ; + CudaHostPinnedSpace(CudaHostPinnedSpace&& rhs) = default; + CudaHostPinnedSpace(const CudaHostPinnedSpace& rhs) = default; + CudaHostPinnedSpace& operator=(CudaHostPinnedSpace&& rhs) = default; + CudaHostPinnedSpace& operator=(const CudaHostPinnedSpace& rhs) = default; + ~CudaHostPinnedSpace() = default; /**\brief Allocate untracked memory in the space */ - void * allocate( const size_t arg_alloc_size ) const ; + void* allocate(const size_t arg_alloc_size) const; /**\brief Deallocate untracked memory in the space */ - void deallocate( void * const arg_alloc_ptr - , const size_t arg_alloc_size ) const ; + void deallocate(void* const arg_alloc_ptr, const size_t arg_alloc_size) const; /**\brief Return Name of the MemorySpace */ static constexpr const char* name() { return m_name; } -private: - + private: static constexpr const char* m_name = "CudaHostPinned"; /*--------------------------------*/ }; -} // namespace Kokkos +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -251,119 +254,126 @@ private: namespace Kokkos { namespace Impl { -static_assert( Kokkos::Impl::MemorySpaceAccess< Kokkos::CudaSpace , Kokkos::CudaSpace >::assignable , "" ); -static_assert( Kokkos::Impl::MemorySpaceAccess< Kokkos::CudaUVMSpace , Kokkos::CudaUVMSpace >::assignable , "" ); -static_assert( Kokkos::Impl::MemorySpaceAccess< Kokkos::CudaHostPinnedSpace , Kokkos::CudaHostPinnedSpace >::assignable , "" ); +static_assert(Kokkos::Impl::MemorySpaceAccess::assignable, + ""); +static_assert(Kokkos::Impl::MemorySpaceAccess::assignable, + ""); +static_assert( + Kokkos::Impl::MemorySpaceAccess::assignable, + ""); //---------------------------------------- -template<> -struct MemorySpaceAccess< Kokkos::HostSpace , Kokkos::CudaSpace > { +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = false }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::HostSpace , Kokkos::CudaUVMSpace > { +template <> +struct MemorySpaceAccess { // HostSpace::execution_space != CudaUVMSpace::execution_space enum { assignable = false }; enum { accessible = true }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::HostSpace , Kokkos::CudaHostPinnedSpace > { +template <> +struct MemorySpaceAccess { // HostSpace::execution_space == CudaHostPinnedSpace::execution_space enum { assignable = true }; enum { accessible = true }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; //---------------------------------------- -template<> -struct MemorySpaceAccess< Kokkos::CudaSpace , Kokkos::HostSpace > { +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = false }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::CudaSpace , Kokkos::CudaUVMSpace > { +template <> +struct MemorySpaceAccess { // CudaSpace::execution_space == CudaUVMSpace::execution_space enum { assignable = true }; enum { accessible = true }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::CudaSpace , Kokkos::CudaHostPinnedSpace > { +template <> +struct MemorySpaceAccess { // CudaSpace::execution_space != CudaHostPinnedSpace::execution_space enum { assignable = false }; - enum { accessible = true }; // CudaSpace::execution_space - enum { deepcopy = true }; + enum { accessible = true }; // CudaSpace::execution_space + enum { deepcopy = true }; }; //---------------------------------------- // CudaUVMSpace::execution_space == Cuda // CudaUVMSpace accessible to both Cuda and Host -template<> -struct MemorySpaceAccess< Kokkos::CudaUVMSpace , Kokkos::HostSpace > { +template <> +struct MemorySpaceAccess { enum { assignable = false }; - enum { accessible = false }; // Cuda cannot access HostSpace - enum { deepcopy = true }; + enum { accessible = false }; // Cuda cannot access HostSpace + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::CudaUVMSpace , Kokkos::CudaSpace > { +template <> +struct MemorySpaceAccess { // CudaUVMSpace::execution_space == CudaSpace::execution_space // Can access CudaUVMSpace from Host but cannot access CudaSpace from Host enum { assignable = false }; // CudaUVMSpace::execution_space can access CudaSpace enum { accessible = true }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::CudaUVMSpace , Kokkos::CudaHostPinnedSpace > { +template <> +struct MemorySpaceAccess { // CudaUVMSpace::execution_space != CudaHostPinnedSpace::execution_space enum { assignable = false }; - enum { accessible = true }; // CudaUVMSpace::execution_space - enum { deepcopy = true }; + enum { accessible = true }; // CudaUVMSpace::execution_space + enum { deepcopy = true }; }; - //---------------------------------------- // CudaHostPinnedSpace::execution_space == HostSpace::execution_space // CudaHostPinnedSpace accessible to both Cuda and Host -template<> -struct MemorySpaceAccess< Kokkos::CudaHostPinnedSpace , Kokkos::HostSpace > { - enum { assignable = false }; // Cannot access from Cuda - enum { accessible = true }; // CudaHostPinnedSpace::execution_space - enum { deepcopy = true }; +template <> +struct MemorySpaceAccess { + enum { assignable = false }; // Cannot access from Cuda + enum { accessible = true }; // CudaHostPinnedSpace::execution_space + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::CudaHostPinnedSpace , Kokkos::CudaSpace > { - enum { assignable = false }; // Cannot access from Host +template <> +struct MemorySpaceAccess { + enum { assignable = false }; // Cannot access from Host enum { accessible = false }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::CudaHostPinnedSpace , Kokkos::CudaUVMSpace > { - enum { assignable = false }; // different execution_space - enum { accessible = true }; // same accessibility - enum { deepcopy = true }; +template <> +struct MemorySpaceAccess { + enum { assignable = false }; // different execution_space + enum { accessible = true }; // same accessibility + enum { deepcopy = true }; }; //---------------------------------------- -}} // namespace Kokkos::Impl +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -371,247 +381,223 @@ struct MemorySpaceAccess< Kokkos::CudaHostPinnedSpace , Kokkos::CudaUVMSpace > { namespace Kokkos { namespace Impl { -void DeepCopyAsyncCuda( void * dst , const void * src , size_t n); +void DeepCopyAsyncCuda(void* dst, const void* src, size_t n); -template<> struct DeepCopy< CudaSpace , CudaSpace , Cuda> -{ - DeepCopy( void * dst , const void * src , size_t ); - DeepCopy( const Cuda & , void * dst , const void * src , size_t ); +template <> +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t); + DeepCopy(const Cuda&, void* dst, const void* src, size_t); }; -template<> struct DeepCopy< CudaSpace , HostSpace , Cuda > -{ - DeepCopy( void * dst , const void * src , size_t ); - DeepCopy( const Cuda & , void * dst , const void * src , size_t ); +template <> +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t); + DeepCopy(const Cuda&, void* dst, const void* src, size_t); }; -template<> struct DeepCopy< HostSpace , CudaSpace , Cuda > -{ - DeepCopy( void * dst , const void * src , size_t ); - DeepCopy( const Cuda & , void * dst , const void * src , size_t ); +template <> +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t); + DeepCopy(const Cuda&, void* dst, const void* src, size_t); }; -template struct DeepCopy< CudaSpace , CudaSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< CudaSpace , CudaSpace , Cuda >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -template struct DeepCopy< CudaSpace , HostSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< CudaSpace , HostSpace , Cuda>( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -template -struct DeepCopy< HostSpace , CudaSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< HostSpace , CudaSpace , Cuda >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -template -struct DeepCopy< CudaSpace , CudaUVMSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< CudaSpace , CudaSpace , Cuda >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -template -struct DeepCopy< CudaSpace , CudaHostPinnedSpace , ExecutionSpace> -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< CudaSpace , HostSpace , Cuda >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } -template -struct DeepCopy< CudaUVMSpace , CudaSpace , ExecutionSpace> -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< CudaSpace , CudaSpace , Cuda >( dst , src , n ); } - - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -template -struct DeepCopy< CudaUVMSpace , CudaUVMSpace , ExecutionSpace> -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< CudaSpace , CudaSpace , Cuda >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -template -struct DeepCopy< CudaUVMSpace , CudaHostPinnedSpace , ExecutionSpace> -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< CudaSpace , HostSpace , Cuda >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -template struct DeepCopy< CudaUVMSpace , HostSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< CudaSpace , HostSpace , Cuda >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } -template struct DeepCopy< CudaHostPinnedSpace , CudaSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< HostSpace , CudaSpace , Cuda >( dst , src , n ); } - - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -template struct DeepCopy< CudaHostPinnedSpace , CudaUVMSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< HostSpace , CudaSpace , Cuda >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -template struct DeepCopy< CudaHostPinnedSpace , CudaHostPinnedSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< HostSpace , HostSpace , Cuda >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -template struct DeepCopy< CudaHostPinnedSpace , HostSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< HostSpace , HostSpace , Cuda >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } -template struct DeepCopy< HostSpace , CudaUVMSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< HostSpace , CudaSpace , Cuda >( dst , src , n ); } - - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -template struct DeepCopy< HostSpace , CudaHostPinnedSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< HostSpace , HostSpace , Cuda >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -620,79 +606,83 @@ namespace Kokkos { namespace Impl { /** Running in CudaSpace attempting to access HostSpace: error */ -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::CudaSpace , Kokkos::HostSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = false }; - KOKKOS_INLINE_FUNCTION static void verify( void ) - { Kokkos::abort("Cuda code attempted to access HostSpace memory"); } + KOKKOS_INLINE_FUNCTION static void verify(void) { + Kokkos::abort("Cuda code attempted to access HostSpace memory"); + } - KOKKOS_INLINE_FUNCTION static void verify( const void * ) - { Kokkos::abort("Cuda code attempted to access HostSpace memory"); } + KOKKOS_INLINE_FUNCTION static void verify(const void*) { + Kokkos::abort("Cuda code attempted to access HostSpace memory"); + } }; /** Running in CudaSpace accessing CudaUVMSpace: ok */ -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::CudaSpace , Kokkos::CudaUVMSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = true }; - KOKKOS_INLINE_FUNCTION static void verify( void ) { } - KOKKOS_INLINE_FUNCTION static void verify( const void * ) { } + KOKKOS_INLINE_FUNCTION static void verify(void) {} + KOKKOS_INLINE_FUNCTION static void verify(const void*) {} }; /** Running in CudaSpace accessing CudaHostPinnedSpace: ok */ -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::CudaSpace , Kokkos::CudaHostPinnedSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = true }; - KOKKOS_INLINE_FUNCTION static void verify( void ) { } - KOKKOS_INLINE_FUNCTION static void verify( const void * ) { } + KOKKOS_INLINE_FUNCTION static void verify(void) {} + KOKKOS_INLINE_FUNCTION static void verify(const void*) {} }; /** Running in CudaSpace attempting to access an unknown space: error */ -template< class OtherSpace > +template struct VerifyExecutionCanAccessMemorySpace< - typename enable_if< ! is_same::value , Kokkos::CudaSpace >::type , - OtherSpace > -{ + typename enable_if::value, + Kokkos::CudaSpace>::type, + OtherSpace> { enum { value = false }; - KOKKOS_INLINE_FUNCTION static void verify( void ) - { Kokkos::abort("Cuda code attempted to access unknown Space memory"); } + KOKKOS_INLINE_FUNCTION static void verify(void) { + Kokkos::abort("Cuda code attempted to access unknown Space memory"); + } - KOKKOS_INLINE_FUNCTION static void verify( const void * ) - { Kokkos::abort("Cuda code attempted to access unknown Space memory"); } + KOKKOS_INLINE_FUNCTION static void verify(const void*) { + Kokkos::abort("Cuda code attempted to access unknown Space memory"); + } }; //---------------------------------------------------------------------------- /** Running in HostSpace attempting to access CudaSpace */ -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::HostSpace , Kokkos::CudaSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = false }; - inline static void verify( void ) { CudaSpace::access_error(); } - inline static void verify( const void * p ) { CudaSpace::access_error(p); } + inline static void verify(void) { CudaSpace::access_error(); } + inline static void verify(const void* p) { CudaSpace::access_error(p); } }; /** Running in HostSpace accessing CudaUVMSpace is OK */ -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::HostSpace , Kokkos::CudaUVMSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = true }; - inline static void verify( void ) { } - inline static void verify( const void * ) { } + inline static void verify(void) {} + inline static void verify(const void*) {} }; /** Running in HostSpace accessing CudaHostPinnedSpace is OK */ -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::HostSpace , Kokkos::CudaHostPinnedSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = true }; - KOKKOS_INLINE_FUNCTION static void verify( void ) {} - KOKKOS_INLINE_FUNCTION static void verify( const void * ) {} + KOKKOS_INLINE_FUNCTION static void verify(void) {} + KOKKOS_INLINE_FUNCTION static void verify(const void*) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -700,248 +690,214 @@ struct VerifyExecutionCanAccessMemorySpace< Kokkos::HostSpace , Kokkos::CudaHost namespace Kokkos { namespace Impl { -template<> -class SharedAllocationRecord< Kokkos::CudaSpace , void > - : public SharedAllocationRecord< void , void > -{ -private: - - friend class SharedAllocationRecord< Kokkos::CudaUVMSpace , void > ; +template <> +class SharedAllocationRecord + : public SharedAllocationRecord { + private: + friend class SharedAllocationRecord; - typedef SharedAllocationRecord< void , void > RecordBase ; + typedef SharedAllocationRecord RecordBase; - SharedAllocationRecord( const SharedAllocationRecord & ) = delete ; - SharedAllocationRecord & operator = ( const SharedAllocationRecord & ) = delete ; + SharedAllocationRecord(const SharedAllocationRecord&) = delete; + SharedAllocationRecord& operator=(const SharedAllocationRecord&) = delete; - static void deallocate( RecordBase * ); + static void deallocate(RecordBase*); - static ::cudaTextureObject_t - attach_texture_object( const unsigned sizeof_alias - , void * const alloc_ptr - , const size_t alloc_size ); + static ::cudaTextureObject_t attach_texture_object( + const unsigned sizeof_alias, void* const alloc_ptr, + const size_t alloc_size); #ifdef KOKKOS_DEBUG - static RecordBase s_root_record ; + static RecordBase s_root_record; #endif - ::cudaTextureObject_t m_tex_obj ; - const Kokkos::CudaSpace m_space ; - -protected: + ::cudaTextureObject_t m_tex_obj; + const Kokkos::CudaSpace m_space; + protected: ~SharedAllocationRecord(); SharedAllocationRecord() : RecordBase(), m_tex_obj(0), m_space() {} - SharedAllocationRecord( const Kokkos::CudaSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - , const RecordBase::function_type arg_dealloc = & deallocate - ); - -public: + SharedAllocationRecord( + const Kokkos::CudaSpace& arg_space, const std::string& arg_label, + const size_t arg_alloc_size, + const RecordBase::function_type arg_dealloc = &deallocate); - std::string get_label() const ; + public: + std::string get_label() const; - static SharedAllocationRecord * allocate( const Kokkos::CudaSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size ); + static SharedAllocationRecord* allocate(const Kokkos::CudaSpace& arg_space, + const std::string& arg_label, + const size_t arg_alloc_size); /**\brief Allocate tracked memory in the space */ - static - void * allocate_tracked( const Kokkos::CudaSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size ); + static void* allocate_tracked(const Kokkos::CudaSpace& arg_space, + const std::string& arg_label, + const size_t arg_alloc_size); /**\brief Reallocate tracked memory in the space */ - static - void * reallocate_tracked( void * const arg_alloc_ptr - , const size_t arg_alloc_size ); + static void* reallocate_tracked(void* const arg_alloc_ptr, + const size_t arg_alloc_size); /**\brief Deallocate tracked memory in the space */ - static - void deallocate_tracked( void * const arg_alloc_ptr ); - - static SharedAllocationRecord * get_record( void * arg_alloc_ptr ); - - template< typename AliasType > - inline - ::cudaTextureObject_t attach_texture_object() - { - static_assert( ( std::is_same< AliasType , int >::value || - std::is_same< AliasType , ::int2 >::value || - std::is_same< AliasType , ::int4 >::value ) - , "Cuda texture fetch only supported for alias types of int, ::int2, or ::int4" ); - - if ( m_tex_obj == 0 ) { - m_tex_obj = attach_texture_object( sizeof(AliasType) - , (void*) RecordBase::m_alloc_ptr - , RecordBase::m_alloc_size ); - } - - return m_tex_obj ; + static void deallocate_tracked(void* const arg_alloc_ptr); + + static SharedAllocationRecord* get_record(void* arg_alloc_ptr); + + template + inline ::cudaTextureObject_t attach_texture_object() { + static_assert((std::is_same::value || + std::is_same::value || + std::is_same::value), + "Cuda texture fetch only supported for alias types of int, " + "::int2, or ::int4"); + + if (m_tex_obj == 0) { + m_tex_obj = attach_texture_object(sizeof(AliasType), + (void*)RecordBase::m_alloc_ptr, + RecordBase::m_alloc_size); } - template< typename AliasType > - inline - int attach_texture_object_offset( const AliasType * const ptr ) - { - // Texture object is attached to the entire allocation range - return ptr - reinterpret_cast( RecordBase::m_alloc_ptr ); - } - - static void print_records( std::ostream & , const Kokkos::CudaSpace & , bool detail = false ); -}; - + return m_tex_obj; + } -template<> -class SharedAllocationRecord< Kokkos::CudaUVMSpace , void > - : public SharedAllocationRecord< void , void > -{ -private: + template + inline int attach_texture_object_offset(const AliasType* const ptr) { + // Texture object is attached to the entire allocation range + return ptr - reinterpret_cast(RecordBase::m_alloc_ptr); + } - typedef SharedAllocationRecord< void , void > RecordBase ; + static void print_records(std::ostream&, const Kokkos::CudaSpace&, + bool detail = false); +}; - SharedAllocationRecord( const SharedAllocationRecord & ) = delete ; - SharedAllocationRecord & operator = ( const SharedAllocationRecord & ) = delete ; +template <> +class SharedAllocationRecord + : public SharedAllocationRecord { + private: + typedef SharedAllocationRecord RecordBase; - static void deallocate( RecordBase * ); + SharedAllocationRecord(const SharedAllocationRecord&) = delete; + SharedAllocationRecord& operator=(const SharedAllocationRecord&) = delete; - static RecordBase s_root_record ; + static void deallocate(RecordBase*); - ::cudaTextureObject_t m_tex_obj ; - const Kokkos::CudaUVMSpace m_space ; + static RecordBase s_root_record; -protected: + ::cudaTextureObject_t m_tex_obj; + const Kokkos::CudaUVMSpace m_space; + protected: ~SharedAllocationRecord(); SharedAllocationRecord() : RecordBase(), m_tex_obj(0), m_space() {} - SharedAllocationRecord( const Kokkos::CudaUVMSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - , const RecordBase::function_type arg_dealloc = & deallocate - ); + SharedAllocationRecord( + const Kokkos::CudaUVMSpace& arg_space, const std::string& arg_label, + const size_t arg_alloc_size, + const RecordBase::function_type arg_dealloc = &deallocate); -public: + public: + std::string get_label() const; - std::string get_label() const ; - - static SharedAllocationRecord * allocate( const Kokkos::CudaUVMSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - ); + static SharedAllocationRecord* allocate(const Kokkos::CudaUVMSpace& arg_space, + const std::string& arg_label, + const size_t arg_alloc_size); /**\brief Allocate tracked memory in the space */ - static - void * allocate_tracked( const Kokkos::CudaUVMSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size ); + static void* allocate_tracked(const Kokkos::CudaUVMSpace& arg_space, + const std::string& arg_label, + const size_t arg_alloc_size); /**\brief Reallocate tracked memory in the space */ - static - void * reallocate_tracked( void * const arg_alloc_ptr - , const size_t arg_alloc_size ); + static void* reallocate_tracked(void* const arg_alloc_ptr, + const size_t arg_alloc_size); /**\brief Deallocate tracked memory in the space */ - static - void deallocate_tracked( void * const arg_alloc_ptr ); - - static SharedAllocationRecord * get_record( void * arg_alloc_ptr ); - - - template< typename AliasType > - inline - ::cudaTextureObject_t attach_texture_object() - { - static_assert( ( std::is_same< AliasType , int >::value || - std::is_same< AliasType , ::int2 >::value || - std::is_same< AliasType , ::int4 >::value ) - , "Cuda texture fetch only supported for alias types of int, ::int2, or ::int4" ); - - if ( m_tex_obj == 0 ) { - m_tex_obj = SharedAllocationRecord< Kokkos::CudaSpace , void >:: - attach_texture_object( sizeof(AliasType) - , (void*) RecordBase::m_alloc_ptr - , RecordBase::m_alloc_size ); - } - - return m_tex_obj ; - } - - template< typename AliasType > - inline - int attach_texture_object_offset( const AliasType * const ptr ) - { - // Texture object is attached to the entire allocation range - return ptr - reinterpret_cast( RecordBase::m_alloc_ptr ); + static void deallocate_tracked(void* const arg_alloc_ptr); + + static SharedAllocationRecord* get_record(void* arg_alloc_ptr); + + template + inline ::cudaTextureObject_t attach_texture_object() { + static_assert((std::is_same::value || + std::is_same::value || + std::is_same::value), + "Cuda texture fetch only supported for alias types of int, " + "::int2, or ::int4"); + + if (m_tex_obj == 0) { + m_tex_obj = SharedAllocationRecord:: + attach_texture_object(sizeof(AliasType), + (void*)RecordBase::m_alloc_ptr, + RecordBase::m_alloc_size); } - static void print_records( std::ostream & , const Kokkos::CudaUVMSpace & , bool detail = false ); -}; + return m_tex_obj; + } -template<> -class SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void > - : public SharedAllocationRecord< void , void > -{ -private: + template + inline int attach_texture_object_offset(const AliasType* const ptr) { + // Texture object is attached to the entire allocation range + return ptr - reinterpret_cast(RecordBase::m_alloc_ptr); + } - typedef SharedAllocationRecord< void , void > RecordBase ; + static void print_records(std::ostream&, const Kokkos::CudaUVMSpace&, + bool detail = false); +}; - SharedAllocationRecord( const SharedAllocationRecord & ) = delete ; - SharedAllocationRecord & operator = ( const SharedAllocationRecord & ) = delete ; +template <> +class SharedAllocationRecord + : public SharedAllocationRecord { + private: + typedef SharedAllocationRecord RecordBase; - static void deallocate( RecordBase * ); + SharedAllocationRecord(const SharedAllocationRecord&) = delete; + SharedAllocationRecord& operator=(const SharedAllocationRecord&) = delete; - static RecordBase s_root_record ; + static void deallocate(RecordBase*); - const Kokkos::CudaHostPinnedSpace m_space ; + static RecordBase s_root_record; -protected: + const Kokkos::CudaHostPinnedSpace m_space; + protected: ~SharedAllocationRecord(); SharedAllocationRecord() : RecordBase(), m_space() {} - SharedAllocationRecord( const Kokkos::CudaHostPinnedSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - , const RecordBase::function_type arg_dealloc = & deallocate - ); + SharedAllocationRecord( + const Kokkos::CudaHostPinnedSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size, + const RecordBase::function_type arg_dealloc = &deallocate); -public: + public: + std::string get_label() const; - std::string get_label() const ; - - static SharedAllocationRecord * allocate( const Kokkos::CudaHostPinnedSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - ); + static SharedAllocationRecord* allocate( + const Kokkos::CudaHostPinnedSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size); /**\brief Allocate tracked memory in the space */ - static - void * allocate_tracked( const Kokkos::CudaHostPinnedSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size ); + static void* allocate_tracked(const Kokkos::CudaHostPinnedSpace& arg_space, + const std::string& arg_label, + const size_t arg_alloc_size); /**\brief Reallocate tracked memory in the space */ - static - void * reallocate_tracked( void * const arg_alloc_ptr - , const size_t arg_alloc_size ); + static void* reallocate_tracked(void* const arg_alloc_ptr, + const size_t arg_alloc_size); /**\brief Deallocate tracked memory in the space */ - static - void deallocate_tracked( void * const arg_alloc_ptr ); - + static void deallocate_tracked(void* const arg_alloc_ptr); - static SharedAllocationRecord * get_record( void * arg_alloc_ptr ); + static SharedAllocationRecord* get_record(void* arg_alloc_ptr); - static void print_records( std::ostream & , const Kokkos::CudaHostPinnedSpace & , bool detail = false ); + static void print_records(std::ostream&, const Kokkos::CudaHostPinnedSpace&, + bool detail = false); }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- #endif /* #if defined( KOKKOS_ENABLE_CUDA ) */ #endif /* #define KOKKOS_CUDASPACE_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_ExecPolicy.hpp b/lib/kokkos/core/src/Kokkos_ExecPolicy.hpp index 5c85850fda..bf3a134b64 100644 --- a/lib/kokkos/core/src/Kokkos_ExecPolicy.hpp +++ b/lib/kokkos/core/src/Kokkos_ExecPolicy.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -53,7 +54,7 @@ #include #if defined(KOKKOS_ENABLE_PROFILING) #include -#endif // KOKKOS_ENABLE_PROFILING +#endif // KOKKOS_ENABLE_PROFILING //---------------------------------------------------------------------------- @@ -65,7 +66,7 @@ struct ParallelReduceTag {}; struct ChunkSize { int value; - ChunkSize(int value_):value(value_) {} + ChunkSize(int value_) : value(value_) {} }; /** \brief Execution policy for work over a range of an integral type. @@ -89,210 +90,192 @@ struct ChunkSize { * * Blocking is the granularity of partitioning the range among threads. */ -template -class RangePolicy - : public Impl::PolicyTraits -{ -public: - typedef Impl::PolicyTraits traits; -private: - - typename traits::execution_space m_space ; - typename traits::index_type m_begin ; - typename traits::index_type m_end ; - typename traits::index_type m_granularity ; - typename traits::index_type m_granularity_mask ; - - template +template +class RangePolicy : public Impl::PolicyTraits { + public: + typedef Impl::PolicyTraits traits; + + private: + typename traits::execution_space m_space; + typename traits::index_type m_begin; + typename traits::index_type m_end; + typename traits::index_type m_granularity; + typename traits::index_type m_granularity_mask; + + template friend class RangePolicy; -public: + public: //! Tag this class as an execution policy typedef RangePolicy execution_policy; - typedef typename traits::index_type member_type ; + typedef typename traits::index_type member_type; typedef typename traits::index_type index_type; - KOKKOS_INLINE_FUNCTION const typename traits::execution_space & space() const { return m_space ; } - KOKKOS_INLINE_FUNCTION member_type begin() const { return m_begin ; } - KOKKOS_INLINE_FUNCTION member_type end() const { return m_end ; } - - //TODO: find a better workaround for Clangs weird instantiation order - // This thing is here because of an instantiation error, where the RangePolicy is inserted into FunctorValue Traits, which - // tries decltype on the operator. It tries to do this even though the first argument of parallel for clearly doesn't match. + KOKKOS_INLINE_FUNCTION const typename traits::execution_space& space() const { + return m_space; + } + KOKKOS_INLINE_FUNCTION member_type begin() const { return m_begin; } + KOKKOS_INLINE_FUNCTION member_type end() const { return m_end; } + + // TODO: find a better workaround for Clangs weird instantiation order + // This thing is here because of an instantiation error, where the RangePolicy + // is inserted into FunctorValue Traits, which tries decltype on the operator. + // It tries to do this even though the first argument of parallel for clearly + // doesn't match. void operator()(const int&) const {} RangePolicy(const RangePolicy&) = default; - RangePolicy(RangePolicy&&) = default; + RangePolicy(RangePolicy&&) = default; - template + template RangePolicy(const RangePolicy p) { - m_space = p.m_space; - m_begin = p.m_begin; - m_end = p.m_end; - m_granularity = p.m_granularity; + m_space = p.m_space; + m_begin = p.m_begin; + m_end = p.m_end; + m_granularity = p.m_granularity; m_granularity_mask = p.m_granularity_mask; } inline RangePolicy() : m_space(), m_begin(0), m_end(0) {} /** \brief Total range */ - inline - RangePolicy( const typename traits::execution_space & work_space - , const member_type work_begin - , const member_type work_end - ) - : m_space( work_space ) - , m_begin( work_begin < work_end ? work_begin : 0 ) - , m_end( work_begin < work_end ? work_end : 0 ) - , m_granularity(0) - , m_granularity_mask(0) - { - set_auto_chunk_size(); - } + inline RangePolicy(const typename traits::execution_space& work_space, + const member_type work_begin, const member_type work_end) + : m_space(work_space), + m_begin(work_begin < work_end ? work_begin : 0), + m_end(work_begin < work_end ? work_end : 0), + m_granularity(0), + m_granularity_mask(0) { + set_auto_chunk_size(); + } /** \brief Total range */ - inline - RangePolicy( const member_type work_begin - , const member_type work_end - ) - : RangePolicy( typename traits::execution_space() - , work_begin , work_end ) - { - set_auto_chunk_size(); - } + inline RangePolicy(const member_type work_begin, const member_type work_end) + : RangePolicy(typename traits::execution_space(), work_begin, work_end) { + set_auto_chunk_size(); + } /** \brief Total range */ - template - inline - RangePolicy( const typename traits::execution_space & work_space - , const member_type work_begin - , const member_type work_end - , Args ... args - ) - : m_space( work_space ) - , m_begin( work_begin < work_end ? work_begin : 0 ) - , m_end( work_begin < work_end ? work_end : 0 ) - , m_granularity(0) - , m_granularity_mask(0) - { - set_auto_chunk_size(); - set(args...); - } + template + inline RangePolicy(const typename traits::execution_space& work_space, + const member_type work_begin, const member_type work_end, + Args... args) + : m_space(work_space), + m_begin(work_begin < work_end ? work_begin : 0), + m_end(work_begin < work_end ? work_end : 0), + m_granularity(0), + m_granularity_mask(0) { + set_auto_chunk_size(); + set(args...); + } /** \brief Total range */ - template - inline - RangePolicy( const member_type work_begin - , const member_type work_end - , Args ... args - ) - : RangePolicy( typename traits::execution_space() - , work_begin , work_end ) - { - set_auto_chunk_size(); - set(args...); - } + template + inline RangePolicy(const member_type work_begin, const member_type work_end, + Args... args) + : RangePolicy(typename traits::execution_space(), work_begin, work_end) { + set_auto_chunk_size(); + set(args...); + } -private: + private: inline void set() {} -public: - template - inline void set(Args ...) { - static_assert( 0 == sizeof...(Args), "Kokkos::RangePolicy: unhandled constructor arguments encountered."); + public: + template + inline void set(Args...) { + static_assert( + 0 == sizeof...(Args), + "Kokkos::RangePolicy: unhandled constructor arguments encountered."); } - template - inline void set(const ChunkSize& chunksize, Args ... args) { - m_granularity = chunksize.value; + template + inline void set(const ChunkSize& chunksize, Args... args) { + m_granularity = chunksize.value; m_granularity_mask = m_granularity - 1; } -public: + public: /** \brief return chunk_size */ - inline member_type chunk_size() const { - return m_granularity; - } + inline member_type chunk_size() const { return m_granularity; } /** \brief set chunk_size to a discrete value*/ inline RangePolicy set_chunk_size(int chunk_size_) const { - RangePolicy p = *this; - p.m_granularity = chunk_size_; + RangePolicy p = *this; + p.m_granularity = chunk_size_; p.m_granularity_mask = p.m_granularity - 1; return p; } -private: + private: /** \brief finalize chunk_size if it was set to AUTO*/ inline void set_auto_chunk_size() { + typename traits::index_type concurrency = + traits::execution_space::concurrency(); + if (concurrency == 0) concurrency = 1; - typename traits::index_type concurrency = traits::execution_space::concurrency(); - if( concurrency==0 ) concurrency=1; - - if(m_granularity > 0) { - if(!Impl::is_integral_power_of_two( m_granularity )) - Kokkos::abort("RangePolicy blocking granularity must be power of two" ); - } + if (m_granularity > 0) { + if (!Impl::is_integral_power_of_two(m_granularity)) + Kokkos::abort("RangePolicy blocking granularity must be power of two"); + } - member_type new_chunk_size = 1; - while(new_chunk_size*100*concurrency < m_end-m_begin) - new_chunk_size *= 2; - if(new_chunk_size < 128) { - new_chunk_size = 1; - while( (new_chunk_size*40*concurrency < m_end-m_begin ) && (new_chunk_size<128) ) - new_chunk_size*=2; - } - m_granularity = new_chunk_size; - m_granularity_mask = m_granularity - 1; + member_type new_chunk_size = 1; + while (new_chunk_size * 100 * concurrency < m_end - m_begin) + new_chunk_size *= 2; + if (new_chunk_size < 128) { + new_chunk_size = 1; + while ((new_chunk_size * 40 * concurrency < m_end - m_begin) && + (new_chunk_size < 128)) + new_chunk_size *= 2; + } + m_granularity = new_chunk_size; + m_granularity_mask = m_granularity - 1; } -public: + public: /** \brief Subrange for a partition's rank and size. * * Typically used to partition a range over a group of threads. */ struct WorkRange { - typedef typename RangePolicy::work_tag work_tag ; - typedef typename RangePolicy::member_type member_type ; + typedef typename RangePolicy::work_tag work_tag; + typedef typename RangePolicy::member_type member_type; - KOKKOS_INLINE_FUNCTION member_type begin() const { return m_begin ; } - KOKKOS_INLINE_FUNCTION member_type end() const { return m_end ; } + KOKKOS_INLINE_FUNCTION member_type begin() const { return m_begin; } + KOKKOS_INLINE_FUNCTION member_type end() const { return m_end; } /** \brief Subrange for a partition's rank and size. * * Typically used to partition a range over a group of threads. */ KOKKOS_INLINE_FUNCTION - WorkRange( const RangePolicy & range - , const int part_rank - , const int part_size - ) - : m_begin(0), m_end(0) - { - if ( part_size ) { - - // Split evenly among partitions, then round up to the granularity. - const member_type work_part = - ( ( ( ( range.end() - range.begin() ) + ( part_size - 1 ) ) / part_size ) - + range.m_granularity_mask ) & ~member_type(range.m_granularity_mask); - - m_begin = range.begin() + work_part * part_rank ; - m_end = m_begin + work_part ; - - if ( range.end() < m_begin ) m_begin = range.end() ; - if ( range.end() < m_end ) m_end = range.end() ; - } + WorkRange(const RangePolicy& range, const int part_rank, + const int part_size) + : m_begin(0), m_end(0) { + if (part_size) { + // Split evenly among partitions, then round up to the granularity. + const member_type work_part = + ((((range.end() - range.begin()) + (part_size - 1)) / part_size) + + range.m_granularity_mask) & + ~member_type(range.m_granularity_mask); + + m_begin = range.begin() + work_part * part_rank; + m_end = m_begin + work_part; + + if (range.end() < m_begin) m_begin = range.end(); + if (range.end() < m_end) m_end = range.end(); } + } - private: - member_type m_begin ; - member_type m_end ; + private: + member_type m_begin; + member_type m_end; WorkRange(); - WorkRange & operator = ( const WorkRange & ); + WorkRange& operator=(const WorkRange&); }; }; -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -301,13 +284,12 @@ namespace Kokkos { namespace Impl { -template< class ExecSpace, class ... Properties> -class TeamPolicyInternal: public Impl::PolicyTraits { -private: - typedef Impl::PolicyTraits traits; +template +class TeamPolicyInternal : public Impl::PolicyTraits { + private: + typedef Impl::PolicyTraits traits; -public: - + public: typedef typename traits::index_type index_type; //---------------------------------------- @@ -321,8 +303,8 @@ public: * With multi-operator functors it cannot be determined * which operator will be called. */ - template< class FunctorType > - static int team_size_max( const FunctorType & ); + template + static int team_size_max(const FunctorType&); /** \brief Query recommended team size for a given functor. * @@ -334,48 +316,56 @@ public: * With multi-operator functors it cannot be determined * which operator will be called. */ - template< class FunctorType > - static int team_size_recommended( const FunctorType & ); + template + static int team_size_recommended(const FunctorType&); - template< class FunctorType > - static int team_size_recommended( const FunctorType & , const int&); + template + static int team_size_recommended(const FunctorType&, const int&); - template - int team_size_recommended( const FunctorType & functor , const int vector_length); + template + int team_size_recommended(const FunctorType& functor, + const int vector_length); //---------------------------------------- /** \brief Construct policy with the given instance of the execution space */ - TeamPolicyInternal( const typename traits::execution_space & , int league_size_request , int team_size_request , int vector_length_request = 1 ); + TeamPolicyInternal(const typename traits::execution_space&, + int league_size_request, int team_size_request, + int vector_length_request = 1); - TeamPolicyInternal( const typename traits::execution_space & , int league_size_request , const Kokkos::AUTO_t & , int vector_length_request = 1 ); + TeamPolicyInternal(const typename traits::execution_space&, + int league_size_request, const Kokkos::AUTO_t&, + int vector_length_request = 1); - /** \brief Construct policy with the default instance of the execution space */ - TeamPolicyInternal( int league_size_request , int team_size_request , int vector_length_request = 1 ); + /** \brief Construct policy with the default instance of the execution space + */ + TeamPolicyInternal(int league_size_request, int team_size_request, + int vector_length_request = 1); - TeamPolicyInternal( int league_size_request , const Kokkos::AUTO_t & , int vector_length_request = 1 ); + TeamPolicyInternal(int league_size_request, const Kokkos::AUTO_t&, + int vector_length_request = 1); -/* TeamPolicyInternal( int league_size_request , int team_size_request ); + /* TeamPolicyInternal( int league_size_request , int team_size_request ); - TeamPolicyInternal( int league_size_request , const Kokkos::AUTO_t & );*/ + TeamPolicyInternal( int league_size_request , const Kokkos::AUTO_t & );*/ /** \brief The actual league size (number of teams) of the policy. * * This may be smaller than the requested league size due to limitations * of the execution space. */ - KOKKOS_INLINE_FUNCTION int league_size() const ; + KOKKOS_INLINE_FUNCTION int league_size() const; /** \brief The actual team size (number of threads per team) of the policy. * * This may be smaller than the requested team size due to limitations * of the execution space. */ - KOKKOS_INLINE_FUNCTION int team_size() const ; + KOKKOS_INLINE_FUNCTION int team_size() const; - inline typename traits::index_type chunk_size() const ; + inline typename traits::index_type chunk_size() const; #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - inline TeamPolicyInternal set_chunk_size(int chunk_size) const ; + inline TeamPolicyInternal set_chunk_size(int chunk_size) const; #else inline TeamPolicyInternal& set_chunk_size(int chunk_size); #endif @@ -384,39 +374,38 @@ public: * each member of the execution policy. */ struct member_type { - /** \brief Handle to the currently executing team shared scratch memory */ KOKKOS_INLINE_FUNCTION - typename traits::execution_space::scratch_memory_space team_shmem() const ; + typename traits::execution_space::scratch_memory_space team_shmem() const; /** \brief Rank of this team within the league of teams */ - KOKKOS_INLINE_FUNCTION int league_rank() const ; + KOKKOS_INLINE_FUNCTION int league_rank() const; /** \brief Number of teams in the league */ - KOKKOS_INLINE_FUNCTION int league_size() const ; + KOKKOS_INLINE_FUNCTION int league_size() const; /** \brief Rank of this thread within this team */ - KOKKOS_INLINE_FUNCTION int team_rank() const ; + KOKKOS_INLINE_FUNCTION int team_rank() const; /** \brief Number of threads in this team */ - KOKKOS_INLINE_FUNCTION int team_size() const ; + KOKKOS_INLINE_FUNCTION int team_size() const; /** \brief Barrier among the threads of this team */ - KOKKOS_INLINE_FUNCTION void team_barrier() const ; + KOKKOS_INLINE_FUNCTION void team_barrier() const; - /** \brief Intra-team reduction. Returns join of all values of the team members. */ - template< class JoinOp > - KOKKOS_INLINE_FUNCTION - typename JoinOp::value_type team_reduce( const typename JoinOp::value_type - , const JoinOp & ) const ; + /** \brief Intra-team reduction. Returns join of all values of the team + * members. */ + template + KOKKOS_INLINE_FUNCTION typename JoinOp::value_type team_reduce( + const typename JoinOp::value_type, const JoinOp&) const; /** \brief Intra-team exclusive prefix sum with team_rank() ordering. * * The highest rank thread can compute the reduction total as * reduction_total = dev.team_scan( value ) + value ; */ - template< typename Type > - KOKKOS_INLINE_FUNCTION Type team_scan( const Type & value ) const ; + template + KOKKOS_INLINE_FUNCTION Type team_scan(const Type& value) const; /** \brief Intra-team exclusive prefix sum with team_rank() ordering * with intra-team non-deterministic ordering accumulation. @@ -427,44 +416,52 @@ public: * As such the base value for each team's scan operation is similarly * non-deterministic. */ - template< typename Type > - KOKKOS_INLINE_FUNCTION Type team_scan( const Type & value , Type * const global_accum ) const ; + template + KOKKOS_INLINE_FUNCTION Type team_scan(const Type& value, + Type* const global_accum) const; }; }; +struct PerTeamValue { + int value; + PerTeamValue(int arg); +}; - struct PerTeamValue { - int value; - PerTeamValue(int arg); - }; - - struct PerThreadValue { - int value; - PerThreadValue(int arg); - }; - - template - struct ExtractVectorLength { - static inline iType value(typename std::enable_if::value,iType>::type val, Args...) { - return val; - } - static inline typename std::enable_if::value,int>::type value(typename std::enable_if::value,iType>::type, Args...) { - return 1; - } - }; +struct PerThreadValue { + int value; + PerThreadValue(int arg); +}; - template - inline typename std::enable_if::value,iType>::type extract_vector_length(iType val, Args...) { +template +struct ExtractVectorLength { + static inline iType value( + typename std::enable_if::value, iType>::type val, + Args...) { return val; } - - template - inline typename std::enable_if::value,int>::type extract_vector_length(iType, Args...) { + static inline + typename std::enable_if::value, int>::type + value( + typename std::enable_if::value, iType>::type, + Args...) { return 1; } +}; + +template +inline typename std::enable_if::value, iType>::type +extract_vector_length(iType val, Args...) { + return val; +} +template +inline typename std::enable_if::value, int>::type +extract_vector_length(iType, Args...) { + return 1; } +} // namespace Impl + Impl::PerTeamValue PerTeam(const int& arg); Impl::PerThreadValue PerThread(const int& arg); @@ -474,38 +471,41 @@ struct ScratchRequest { int per_team; int per_thread; - inline - ScratchRequest(const int& level_, const Impl::PerTeamValue& team_value) { - level = level_; - per_team = team_value.value; + inline ScratchRequest(const int& level_, + const Impl::PerTeamValue& team_value) { + level = level_; + per_team = team_value.value; per_thread = 0; } - inline - ScratchRequest(const int& level_, const Impl::PerThreadValue& thread_value) { - level = level_; - per_team = 0; - per_thread = thread_value.value;; + inline ScratchRequest(const int& level_, + const Impl::PerThreadValue& thread_value) { + level = level_; + per_team = 0; + per_thread = thread_value.value; + ; } - inline - ScratchRequest(const int& level_, const Impl::PerTeamValue& team_value, const Impl::PerThreadValue& thread_value) { - level = level_; - per_team = team_value.value; - per_thread = thread_value.value;; + inline ScratchRequest(const int& level_, const Impl::PerTeamValue& team_value, + const Impl::PerThreadValue& thread_value) { + level = level_; + per_team = team_value.value; + per_thread = thread_value.value; + ; } - inline - ScratchRequest(const int& level_, const Impl::PerThreadValue& thread_value, const Impl::PerTeamValue& team_value) { - level = level_; - per_team = team_value.value; - per_thread = thread_value.value;; + inline ScratchRequest(const int& level_, + const Impl::PerThreadValue& thread_value, + const Impl::PerTeamValue& team_value) { + level = level_; + per_team = team_value.value; + per_thread = thread_value.value; + ; } - }; - -/** \brief Execution policy for parallel work over a league of teams of threads. +/** \brief Execution policy for parallel work over a league of teams of + * threads. * * The work functor is called for each thread of each team such that * the team's member threads are guaranteed to be concurrent. @@ -522,162 +522,197 @@ struct ScratchRequest { * be omitted. * * Possible Template arguments and their default values: - * ExecutionSpace (DefaultExecutionSpace): where to execute code. Must be enabled. - * WorkTag (none): Tag which is used as the first argument for the functor operator. - * Schedule (Schedule): Scheduling Policy (Dynamic, or Static). - * IndexType (IndexType: Integer Index type used to iterate over the Index space. + * ExecutionSpace (DefaultExecutionSpace): where to execute code. Must be + * enabled. WorkTag (none): Tag which is used as the first argument for the + * functor operator. Schedule (Schedule): Scheduling Policy + * (Dynamic, or Static). IndexType (IndexType: + * Integer Index type used to iterate over the Index space. * LaunchBounds Launch Bounds for CUDA compilation, * default of LaunchBounds<0,0> indicates no launch bounds specified. */ -template< class ... Properties> -class TeamPolicy: public - Impl::TeamPolicyInternal< - typename Impl::PolicyTraits::execution_space, - Properties ...> { +template +class TeamPolicy + : public Impl::TeamPolicyInternal< + typename Impl::PolicyTraits::execution_space, + Properties...> { typedef Impl::TeamPolicyInternal< - typename Impl::PolicyTraits::execution_space, - Properties ...> internal_policy; + typename Impl::PolicyTraits::execution_space, + Properties...> + internal_policy; - template + template friend class TeamPolicy; -public: - typedef Impl::PolicyTraits traits; + public: + typedef Impl::PolicyTraits traits; typedef TeamPolicy execution_policy; - TeamPolicy& operator = (const TeamPolicy&) = default; + TeamPolicy& operator=(const TeamPolicy&) = default; /** \brief Construct policy with the given instance of the execution space */ - TeamPolicy( const typename traits::execution_space & space_ , int league_size_request , int team_size_request , int vector_length_request = 1 ) - : internal_policy(space_,league_size_request,team_size_request, vector_length_request) {first_arg = false;} + TeamPolicy(const typename traits::execution_space& space_, + int league_size_request, int team_size_request, + int vector_length_request = 1) + : internal_policy(space_, league_size_request, team_size_request, + vector_length_request) { + first_arg = false; + } - TeamPolicy( const typename traits::execution_space & space_, int league_size_request , const Kokkos::AUTO_t & , int vector_length_request = 1 ) - : internal_policy(space_,league_size_request,Kokkos::AUTO(), vector_length_request) {first_arg = false;} + TeamPolicy(const typename traits::execution_space& space_, + int league_size_request, const Kokkos::AUTO_t&, + int vector_length_request = 1) + : internal_policy(space_, league_size_request, Kokkos::AUTO(), + vector_length_request) { + first_arg = false; + } - /** \brief Construct policy with the default instance of the execution space */ - TeamPolicy( int league_size_request , int team_size_request , int vector_length_request = 1 ) - : internal_policy(league_size_request,team_size_request, vector_length_request) {first_arg = false;} + /** \brief Construct policy with the default instance of the execution space + */ + TeamPolicy(int league_size_request, int team_size_request, + int vector_length_request = 1) + : internal_policy(league_size_request, team_size_request, + vector_length_request) { + first_arg = false; + } - TeamPolicy( int league_size_request , const Kokkos::AUTO_t & , int vector_length_request = 1 ) - : internal_policy(league_size_request,Kokkos::AUTO(), vector_length_request) {first_arg = false;} + TeamPolicy(int league_size_request, const Kokkos::AUTO_t&, + int vector_length_request = 1) + : internal_policy(league_size_request, Kokkos::AUTO(), + vector_length_request) { + first_arg = false; + } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE /** \brief Construct policy with the given instance of the execution space */ - template - TeamPolicy( const typename traits::execution_space & , int league_size_request , int team_size_request , int vector_length_request, - Args ... args) - : internal_policy(typename traits::execution_space(),league_size_request,team_size_request, vector_length_request) { + template + TeamPolicy(const typename traits::execution_space&, int league_size_request, + int team_size_request, int vector_length_request, Args... args) + : internal_policy(typename traits::execution_space(), league_size_request, + team_size_request, vector_length_request) { first_arg = false; set(args...); } - template - TeamPolicy( const typename traits::execution_space & , int league_size_request , const Kokkos::AUTO_t & , int vector_length_request , - Args ... args) - : internal_policy(typename traits::execution_space(),league_size_request,Kokkos::AUTO(), vector_length_request) { + template + TeamPolicy(const typename traits::execution_space&, int league_size_request, + const Kokkos::AUTO_t&, int vector_length_request, Args... args) + : internal_policy(typename traits::execution_space(), league_size_request, + Kokkos::AUTO(), vector_length_request) { first_arg = false; set(args...); } - /** \brief Construct policy with the default instance of the execution space */ - template - TeamPolicy( int league_size_request , int team_size_request , int vector_length_request , - Args ... args) - : internal_policy(league_size_request,team_size_request, vector_length_request) { + /** \brief Construct policy with the default instance of the execution space + */ + template + TeamPolicy(int league_size_request, int team_size_request, + int vector_length_request, Args... args) + : internal_policy(league_size_request, team_size_request, + vector_length_request) { first_arg = false; set(args...); } - template - TeamPolicy( int league_size_request , const Kokkos::AUTO_t & , int vector_length_request , - Args ... args) - : internal_policy(league_size_request,Kokkos::AUTO(), vector_length_request) { + template + TeamPolicy(int league_size_request, const Kokkos::AUTO_t&, + int vector_length_request, Args... args) + : internal_policy(league_size_request, Kokkos::AUTO(), + vector_length_request) { first_arg = false; set(args...); } /** \brief Construct policy with the given instance of the execution space */ - template - TeamPolicy( const typename traits::execution_space & , int league_size_request , int team_size_request , - Args ... args) - : internal_policy(typename traits::execution_space(),league_size_request,team_size_request, - Kokkos::Impl::extract_vector_length(args...)) { + template + TeamPolicy(const typename traits::execution_space&, int league_size_request, + int team_size_request, Args... args) + : internal_policy(typename traits::execution_space(), league_size_request, + team_size_request, + Kokkos::Impl::extract_vector_length(args...)) { first_arg = true; set(args...); } - template - TeamPolicy( const typename traits::execution_space & , int league_size_request , const Kokkos::AUTO_t & , - Args ... args) - : internal_policy(typename traits::execution_space(),league_size_request,Kokkos::AUTO(), - Kokkos::Impl::extract_vector_length(args...)) { + template + TeamPolicy(const typename traits::execution_space&, int league_size_request, + const Kokkos::AUTO_t&, Args... args) + : internal_policy(typename traits::execution_space(), league_size_request, + Kokkos::AUTO(), + Kokkos::Impl::extract_vector_length(args...)) { first_arg = true; set(args...); } - /** \brief Construct policy with the default instance of the execution space */ - template - TeamPolicy( int league_size_request , int team_size_request , - Args ... args) - : internal_policy(league_size_request,team_size_request, - Kokkos::Impl::extract_vector_length(args...)) { + /** \brief Construct policy with the default instance of the execution space + */ + template + TeamPolicy(int league_size_request, int team_size_request, Args... args) + : internal_policy(league_size_request, team_size_request, + Kokkos::Impl::extract_vector_length(args...)) { first_arg = true; set(args...); } - template - TeamPolicy( int league_size_request , const Kokkos::AUTO_t & , - Args ... args) - : internal_policy(league_size_request,Kokkos::AUTO(), - Kokkos::Impl::extract_vector_length(args...)) { + template + TeamPolicy(int league_size_request, const Kokkos::AUTO_t&, Args... args) + : internal_policy(league_size_request, Kokkos::AUTO(), + Kokkos::Impl::extract_vector_length(args...)) { first_arg = true; set(args...); } #endif - template - TeamPolicy(const TeamPolicy p):internal_policy(p) { + template + TeamPolicy(const TeamPolicy p) : internal_policy(p) { first_arg = p.first_arg; } -private: + private: bool first_arg; - TeamPolicy(const internal_policy& p):internal_policy(p) {first_arg = false;} + TeamPolicy(const internal_policy& p) : internal_policy(p) { + first_arg = false; + } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE inline void set() {} #endif -public: + public: #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - template - inline void set(Args ...) { - static_assert( 0 == sizeof...(Args), "Kokkos::TeamPolicy: unhandled constructor arguments encountered."); + template + inline void set(Args...) { + static_assert( + 0 == sizeof...(Args), + "Kokkos::TeamPolicy: unhandled constructor arguments encountered."); } - template - inline typename std::enable_if::value>::type set(iType, Args ... args) { - if(first_arg) { + template + inline typename std::enable_if::value>::type set( + iType, Args... args) { + if (first_arg) { first_arg = false; set(args...); } else { first_arg = false; - Kokkos::Impl::throw_runtime_exception("Kokkos::TeamPolicy: integer argument to constructor in illegal place."); + Kokkos::Impl::throw_runtime_exception( + "Kokkos::TeamPolicy: integer argument to constructor in illegal " + "place."); } } - template - inline void set(const ChunkSize& chunksize, Args ... args) { + template + inline void set(const ChunkSize& chunksize, Args... args) { first_arg = false; internal_policy::internal_set_chunk_size(chunksize.value); set(args...); } - template - inline void set(const ScratchRequest& scr_request, Args ... args) { + template + inline void set(const ScratchRequest& scr_request, Args... args) { first_arg = false; - internal_policy::internal_set_scratch_size(scr_request.level,Impl::PerTeamValue(scr_request.per_team), + internal_policy::internal_set_scratch_size( + scr_request.level, Impl::PerTeamValue(scr_request.per_team), Impl::PerThreadValue(scr_request.per_thread)); set(args...); } @@ -686,267 +721,287 @@ public: return TeamPolicy(internal_policy::set_chunk_size(chunk)); } - inline TeamPolicy set_scratch_size(const int& level, const Impl::PerTeamValue& per_team) const { - return TeamPolicy(internal_policy::set_scratch_size(level,per_team)); + inline TeamPolicy set_scratch_size(const int& level, + const Impl::PerTeamValue& per_team) const { + return TeamPolicy(internal_policy::set_scratch_size(level, per_team)); } - inline TeamPolicy set_scratch_size(const int& level, const Impl::PerThreadValue& per_thread) const { - return TeamPolicy(internal_policy::set_scratch_size(level,per_thread)); + inline TeamPolicy set_scratch_size( + const int& level, const Impl::PerThreadValue& per_thread) const { + return TeamPolicy(internal_policy::set_scratch_size(level, per_thread)); } - inline TeamPolicy set_scratch_size(const int& level, const Impl::PerTeamValue& per_team, const Impl::PerThreadValue& per_thread) const { - return TeamPolicy(internal_policy::set_scratch_size(level, per_team, per_thread)); + inline TeamPolicy set_scratch_size( + const int& level, const Impl::PerTeamValue& per_team, + const Impl::PerThreadValue& per_thread) const { + return TeamPolicy( + internal_policy::set_scratch_size(level, per_team, per_thread)); } - inline TeamPolicy set_scratch_size(const int& level, const Impl::PerThreadValue& per_thread, const Impl::PerTeamValue& per_team) const { - return TeamPolicy(internal_policy::set_scratch_size(level, per_team, per_thread)); + inline TeamPolicy set_scratch_size(const int& level, + const Impl::PerThreadValue& per_thread, + const Impl::PerTeamValue& per_team) const { + return TeamPolicy( + internal_policy::set_scratch_size(level, per_team, per_thread)); } #else inline TeamPolicy& set_chunk_size(int chunk) { - static_assert(std::is_same::value, "internal set_chunk_size should return a reference"); + static_assert(std::is_same::value, + "internal set_chunk_size should return a reference"); return static_cast(internal_policy::set_chunk_size(chunk)); } - inline TeamPolicy& set_scratch_size(const int& level, const Impl::PerTeamValue& per_team) { - static_assert(std::is_same::value, "internal set_chunk_size should return a reference"); - return static_cast(internal_policy::set_scratch_size(level,per_team)); + inline TeamPolicy& set_scratch_size(const int& level, + const Impl::PerTeamValue& per_team) { + static_assert(std::is_same::value, + "internal set_chunk_size should return a reference"); + return static_cast( + internal_policy::set_scratch_size(level, per_team)); } - inline TeamPolicy& set_scratch_size(const int& level, const Impl::PerThreadValue& per_thread) { - return static_cast(internal_policy::set_scratch_size(level,per_thread)); + inline TeamPolicy& set_scratch_size(const int& level, + const Impl::PerThreadValue& per_thread) { + return static_cast( + internal_policy::set_scratch_size(level, per_thread)); } - inline TeamPolicy& set_scratch_size(const int& level, const Impl::PerTeamValue& per_team, const Impl::PerThreadValue& per_thread) { - return static_cast(internal_policy::set_scratch_size(level, per_team, per_thread)); + inline TeamPolicy& set_scratch_size(const int& level, + const Impl::PerTeamValue& per_team, + const Impl::PerThreadValue& per_thread) { + return static_cast( + internal_policy::set_scratch_size(level, per_team, per_thread)); } - inline TeamPolicy& set_scratch_size(const int& level, const Impl::PerThreadValue& per_thread, const Impl::PerTeamValue& per_team) { - return static_cast(internal_policy::set_scratch_size(level, per_team, per_thread)); + inline TeamPolicy& set_scratch_size(const int& level, + const Impl::PerThreadValue& per_thread, + const Impl::PerTeamValue& per_team) { + return static_cast( + internal_policy::set_scratch_size(level, per_team, per_thread)); } #endif - }; namespace Impl { -template +template struct TeamThreadRangeBoundariesStruct { -private: - - KOKKOS_INLINE_FUNCTION static - iType ibegin( const iType & arg_begin - , const iType & arg_end - , const iType & arg_rank - , const iType & arg_size - ) - { - return arg_begin + ( ( arg_end - arg_begin + arg_size - 1 ) / arg_size ) * arg_rank ; - } - - KOKKOS_INLINE_FUNCTION static - iType iend( const iType & arg_begin - , const iType & arg_end - , const iType & arg_rank - , const iType & arg_size - ) - { - const iType end_ = arg_begin + ( ( arg_end - arg_begin + arg_size - 1 ) / arg_size ) * ( arg_rank + 1 ); - return end_ < arg_end ? end_ : arg_end ; - } + private: + KOKKOS_INLINE_FUNCTION static iType ibegin(const iType& arg_begin, + const iType& arg_end, + const iType& arg_rank, + const iType& arg_size) { + return arg_begin + + ((arg_end - arg_begin + arg_size - 1) / arg_size) * arg_rank; + } -public: + KOKKOS_INLINE_FUNCTION static iType iend(const iType& arg_begin, + const iType& arg_end, + const iType& arg_rank, + const iType& arg_size) { + const iType end_ = + arg_begin + + ((arg_end - arg_begin + arg_size - 1) / arg_size) * (arg_rank + 1); + return end_ < arg_end ? end_ : arg_end; + } + public: typedef iType index_type; const iType start; const iType end; - enum {increment = 1}; + enum { increment = 1 }; const TeamMemberType& thread; KOKKOS_INLINE_FUNCTION - TeamThreadRangeBoundariesStruct( const TeamMemberType& arg_thread - , const iType& arg_end - ) - : start( ibegin( 0 , arg_end , arg_thread.team_rank() , arg_thread.team_size() ) ) - , end( iend( 0 , arg_end , arg_thread.team_rank() , arg_thread.team_size() ) ) - , thread( arg_thread ) - {} + TeamThreadRangeBoundariesStruct(const TeamMemberType& arg_thread, + const iType& arg_end) + : start( + ibegin(0, arg_end, arg_thread.team_rank(), arg_thread.team_size())), + end(iend(0, arg_end, arg_thread.team_rank(), arg_thread.team_size())), + thread(arg_thread) {} KOKKOS_INLINE_FUNCTION - TeamThreadRangeBoundariesStruct( const TeamMemberType& arg_thread - , const iType& arg_begin - , const iType& arg_end - ) - : start( ibegin( arg_begin , arg_end , arg_thread.team_rank() , arg_thread.team_size() ) ) - , end( iend( arg_begin , arg_end , arg_thread.team_rank() , arg_thread.team_size() ) ) - , thread( arg_thread ) - {} + TeamThreadRangeBoundariesStruct(const TeamMemberType& arg_thread, + const iType& arg_begin, const iType& arg_end) + : start(ibegin(arg_begin, arg_end, arg_thread.team_rank(), + arg_thread.team_size())), + end(iend(arg_begin, arg_end, arg_thread.team_rank(), + arg_thread.team_size())), + thread(arg_thread) {} }; -template +template struct TeamVectorRangeBoundariesStruct { -private: - - KOKKOS_INLINE_FUNCTION static - iType ibegin( const iType & arg_begin - , const iType & arg_end - , const iType & arg_rank - , const iType & arg_size - ) - { - return arg_begin + ( ( arg_end - arg_begin + arg_size - 1 ) / arg_size ) * arg_rank ; - } - - KOKKOS_INLINE_FUNCTION static - iType iend( const iType & arg_begin - , const iType & arg_end - , const iType & arg_rank - , const iType & arg_size - ) - { - const iType end_ = arg_begin + ( ( arg_end - arg_begin + arg_size - 1 ) / arg_size ) * ( arg_rank + 1 ); - return end_ < arg_end ? end_ : arg_end ; - } + private: + KOKKOS_INLINE_FUNCTION static iType ibegin(const iType& arg_begin, + const iType& arg_end, + const iType& arg_rank, + const iType& arg_size) { + return arg_begin + + ((arg_end - arg_begin + arg_size - 1) / arg_size) * arg_rank; + } -public: + KOKKOS_INLINE_FUNCTION static iType iend(const iType& arg_begin, + const iType& arg_end, + const iType& arg_rank, + const iType& arg_size) { + const iType end_ = + arg_begin + + ((arg_end - arg_begin + arg_size - 1) / arg_size) * (arg_rank + 1); + return end_ < arg_end ? end_ : arg_end; + } + public: typedef iType index_type; const iType start; const iType end; - enum {increment = 1}; + enum { increment = 1 }; const TeamMemberType& thread; KOKKOS_INLINE_FUNCTION - TeamVectorRangeBoundariesStruct( const TeamMemberType& arg_thread - , const iType& arg_end - ) - : start( ibegin( 0 , arg_end , arg_thread.team_rank() , arg_thread.team_size() ) ) - , end( iend( 0 , arg_end , arg_thread.team_rank() , arg_thread.team_size() ) ) - , thread( arg_thread ) - {} + TeamVectorRangeBoundariesStruct(const TeamMemberType& arg_thread, + const iType& arg_end) + : start( + ibegin(0, arg_end, arg_thread.team_rank(), arg_thread.team_size())), + end(iend(0, arg_end, arg_thread.team_rank(), arg_thread.team_size())), + thread(arg_thread) {} KOKKOS_INLINE_FUNCTION - TeamVectorRangeBoundariesStruct( const TeamMemberType& arg_thread - , const iType& arg_begin - , const iType& arg_end - ) - : start( ibegin( arg_begin , arg_end , arg_thread.team_rank() , arg_thread.team_size() ) ) - , end( iend( arg_begin , arg_end , arg_thread.team_rank() , arg_thread.team_size() ) ) - , thread( arg_thread ) - {} + TeamVectorRangeBoundariesStruct(const TeamMemberType& arg_thread, + const iType& arg_begin, const iType& arg_end) + : start(ibegin(arg_begin, arg_end, arg_thread.team_rank(), + arg_thread.team_size())), + end(iend(arg_begin, arg_end, arg_thread.team_rank(), + arg_thread.team_size())), + thread(arg_thread) {} }; -template +template struct ThreadVectorRangeBoundariesStruct { typedef iType index_type; const index_type start; const index_type end; - enum {increment = 1}; + enum { increment = 1 }; KOKKOS_INLINE_FUNCTION - constexpr ThreadVectorRangeBoundariesStruct ( const TeamMemberType, const index_type& count ) noexcept - : start( static_cast(0) ) - , end( count ) {} + constexpr ThreadVectorRangeBoundariesStruct(const TeamMemberType, + const index_type& count) noexcept + : start(static_cast(0)), end(count) {} KOKKOS_INLINE_FUNCTION - constexpr ThreadVectorRangeBoundariesStruct ( const index_type& count ) noexcept - : start( static_cast(0) ) - , end( count ) {} + constexpr ThreadVectorRangeBoundariesStruct(const index_type& count) noexcept + : start(static_cast(0)), end(count) {} KOKKOS_INLINE_FUNCTION - constexpr ThreadVectorRangeBoundariesStruct ( const TeamMemberType, const index_type& arg_begin, const index_type& arg_end ) noexcept - : start( static_cast(arg_begin) ) - , end( arg_end ) {} + constexpr ThreadVectorRangeBoundariesStruct( + const TeamMemberType, const index_type& arg_begin, + const index_type& arg_end) noexcept + : start(static_cast(arg_begin)), end(arg_end) {} KOKKOS_INLINE_FUNCTION - constexpr ThreadVectorRangeBoundariesStruct ( const index_type& arg_begin, const index_type& arg_end ) noexcept - : start( static_cast(arg_begin) ) - , end( arg_end ) {} + constexpr ThreadVectorRangeBoundariesStruct( + const index_type& arg_begin, const index_type& arg_end) noexcept + : start(static_cast(arg_begin)), end(arg_end) {} }; -template +template struct ThreadSingleStruct { const TeamMemberType& team_member; KOKKOS_INLINE_FUNCTION - ThreadSingleStruct( const TeamMemberType& team_member_ ) : team_member( team_member_ ) {} + ThreadSingleStruct(const TeamMemberType& team_member_) + : team_member(team_member_) {} }; -template +template struct VectorSingleStruct { const TeamMemberType& team_member; KOKKOS_INLINE_FUNCTION - VectorSingleStruct( const TeamMemberType& team_member_ ) : team_member( team_member_ ) {} + VectorSingleStruct(const TeamMemberType& team_member_) + : team_member(team_member_) {} }; -} // namespace Impl +} // namespace Impl /** \brief Execution policy for parallel work over a threads within a team. * - * The range is split over all threads in a team. The Mapping scheme depends on the architecture. - * This policy is used together with a parallel pattern as a nested layer within a kernel launched - * with the TeamPolicy. This variant expects a single count. So the range is (0,count]. + * The range is split over all threads in a team. The Mapping scheme depends on + * the architecture. This policy is used together with a parallel pattern as a + * nested layer within a kernel launched with the TeamPolicy. This variant + * expects a single count. So the range is (0,count]. */ -template +template KOKKOS_INLINE_FUNCTION_DELETED -Impl::TeamThreadRangeBoundariesStruct -TeamThreadRange( const TeamMemberType&, const iType& count ) = delete; + Impl::TeamThreadRangeBoundariesStruct + TeamThreadRange(const TeamMemberType&, const iType& count) = delete; /** \brief Execution policy for parallel work over a threads within a team. * - * The range is split over all threads in a team. The Mapping scheme depends on the architecture. - * This policy is used together with a parallel pattern as a nested layer within a kernel launched - * with the TeamPolicy. This variant expects a begin and end. So the range is (begin,end]. + * The range is split over all threads in a team. The Mapping scheme depends on + * the architecture. This policy is used together with a parallel pattern as a + * nested layer within a kernel launched with the TeamPolicy. This variant + * expects a begin and end. So the range is (begin,end]. */ -template -KOKKOS_INLINE_FUNCTION_DELETED -Impl::TeamThreadRangeBoundariesStruct::type, TeamMemberType> -TeamThreadRange( const TeamMemberType&, const iType1& begin, const iType2& end ) = delete; +template +KOKKOS_INLINE_FUNCTION_DELETED Impl::TeamThreadRangeBoundariesStruct< + typename std::common_type::type, TeamMemberType> +TeamThreadRange(const TeamMemberType&, const iType1& begin, + const iType2& end) = delete; /** \brief Execution policy for parallel work over a threads within a team. * - * The range is split over all threads in a team. The Mapping scheme depends on the architecture. - * This policy is used together with a parallel pattern as a nested layer within a kernel launched - * with the TeamPolicy. This variant expects a single count. So the range is (0,count]. + * The range is split over all threads in a team. The Mapping scheme depends on + * the architecture. This policy is used together with a parallel pattern as a + * nested layer within a kernel launched with the TeamPolicy. This variant + * expects a single count. So the range is (0,count]. */ -template +template KOKKOS_INLINE_FUNCTION_DELETED -Impl::TeamThreadRangeBoundariesStruct -TeamVectorRange( const TeamMemberType&, const iType& count ) = delete; + Impl::TeamThreadRangeBoundariesStruct + TeamVectorRange(const TeamMemberType&, const iType& count) = delete; /** \brief Execution policy for parallel work over a threads within a team. * - * The range is split over all threads in a team. The Mapping scheme depends on the architecture. - * This policy is used together with a parallel pattern as a nested layer within a kernel launched - * with the TeamPolicy. This variant expects a begin and end. So the range is (begin,end]. + * The range is split over all threads in a team. The Mapping scheme depends on + * the architecture. This policy is used together with a parallel pattern as a + * nested layer within a kernel launched with the TeamPolicy. This variant + * expects a begin and end. So the range is (begin,end]. */ -template -KOKKOS_INLINE_FUNCTION_DELETED -Impl::TeamThreadRangeBoundariesStruct::type, TeamMemberType> -TeamVectorRange( const TeamMemberType&, const iType1& begin, const iType2& end ) = delete; +template +KOKKOS_INLINE_FUNCTION_DELETED Impl::TeamThreadRangeBoundariesStruct< + typename std::common_type::type, TeamMemberType> +TeamVectorRange(const TeamMemberType&, const iType1& begin, + const iType2& end) = delete; /** \brief Execution policy for a vector parallel loop. * - * The range is split over all vector lanes in a thread. The Mapping scheme depends on the architecture. - * This policy is used together with a parallel pattern as a nested layer within a kernel launched - * with the TeamPolicy. This variant expects a single count. So the range is (0,count]. + * The range is split over all vector lanes in a thread. The Mapping scheme + * depends on the architecture. This policy is used together with a parallel + * pattern as a nested layer within a kernel launched with the TeamPolicy. This + * variant expects a single count. So the range is (0,count]. */ -template +template KOKKOS_INLINE_FUNCTION_DELETED -Impl::ThreadVectorRangeBoundariesStruct -ThreadVectorRange( const TeamMemberType&, const iType& count ) = delete; + Impl::ThreadVectorRangeBoundariesStruct + ThreadVectorRange(const TeamMemberType&, const iType& count) = delete; -template +template KOKKOS_INLINE_FUNCTION_DELETED -Impl::ThreadVectorRangeBoundariesStruct -ThreadVectorRange( const TeamMemberType&, const iType& arg_begin, const iType& arg_end ) = delete; + Impl::ThreadVectorRangeBoundariesStruct + ThreadVectorRange(const TeamMemberType&, const iType& arg_begin, + const iType& arg_end) = delete; #if defined(KOKKOS_ENABLE_PROFILING) namespace Impl { -template::value > +template ::value> struct ParallelConstructName; -template +template struct ParallelConstructName { - ParallelConstructName(std::string const& label):label_ref(label) { + ParallelConstructName(std::string const& label) : label_ref(label) { if (label.empty()) { default_name = std::string(typeid(FunctorType).name()) + "/" + - typeid(TagType).name(); + typeid(TagType).name(); } } std::string const& get() { @@ -956,9 +1011,9 @@ struct ParallelConstructName { std::string default_name; }; -template +template struct ParallelConstructName { - ParallelConstructName(std::string const& label):label_ref(label) { + ParallelConstructName(std::string const& label) : label_ref(label) { if (label.empty()) { default_name = std::string(typeid(FunctorType).name()); } @@ -970,49 +1025,54 @@ struct ParallelConstructName { std::string default_name; }; -} // namespace Impl +} // namespace Impl #endif /* defined KOKKOS_ENABLE_PROFILING */ -} // namespace Kokkos +} // namespace Kokkos namespace Kokkos { namespace Experimental { namespace Impl { - template - struct PolicyPropertyAdaptor; - - template - struct PolicyPropertyAdaptor,RangePolicy> { - typedef RangePolicy policy_in_t; - typedef RangePolicy> policy_out_t; - }; - - template - struct PolicyPropertyAdaptor,TeamPolicy> { - typedef TeamPolicy policy_in_t; - typedef TeamPolicy> policy_out_t; - }; -} +template +struct PolicyPropertyAdaptor; + +template +struct PolicyPropertyAdaptor, + RangePolicy> { + typedef RangePolicy policy_in_t; + typedef RangePolicy> + policy_out_t; +}; -template -constexpr typename Impl::PolicyPropertyAdaptor,PolicyType>::policy_out_t - require(const PolicyType p, WorkItemProperty::ImplWorkItemProperty

    ){ - return typename Impl::PolicyPropertyAdaptor,PolicyType>::policy_out_t(p); +template +struct PolicyPropertyAdaptor, + TeamPolicy> { + typedef TeamPolicy policy_in_t; + typedef TeamPolicy> + policy_out_t; +}; +} // namespace Impl + +template +constexpr typename Impl::PolicyPropertyAdaptor< + WorkItemProperty::ImplWorkItemProperty

    , PolicyType>::policy_out_t +require(const PolicyType p, WorkItemProperty::ImplWorkItemProperty

    ) { + return typename Impl::PolicyPropertyAdaptor< + WorkItemProperty::ImplWorkItemProperty

    , PolicyType>::policy_out_t(p); } -} //Experimental -} //Kokkos +} // namespace Experimental +} // namespace Kokkos #endif /* #define KOKKOS_EXECPOLICY_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_Extents.hpp b/lib/kokkos/core/src/Kokkos_Extents.hpp index c8b9110485..2e07e8b76b 100644 --- a/lib/kokkos/core/src/Kokkos_Extents.hpp +++ b/lib/kokkos/core/src/Kokkos_Extents.hpp @@ -2,10 +2,10 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 +// Kokkos v. 3.0 // Copyright (2019) Sandia Corporation // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -60,9 +60,7 @@ template struct PrependExtent; template -struct PrependExtent< - Extents, NewExtent -> { +struct PrependExtent, NewExtent> { using type = Extents; }; @@ -70,117 +68,101 @@ template struct AppendExtent; template -struct AppendExtent< - Extents, NewExtent -> { +struct AppendExtent, NewExtent> { using type = Extents; }; -} // end namespace Experimental +} // end namespace Experimental namespace Impl { namespace _parse_view_extents_impl { template -struct _all_remaining_extents_dynamic : std::true_type { }; +struct _all_remaining_extents_dynamic : std::true_type {}; template -struct _all_remaining_extents_dynamic - : _all_remaining_extents_dynamic -{ }; +struct _all_remaining_extents_dynamic : _all_remaining_extents_dynamic { +}; template -struct _all_remaining_extents_dynamic - : std::false_type -{ }; +struct _all_remaining_extents_dynamic : std::false_type {}; -template +template struct _parse_impl { using type = Result; }; -// We have to treat the case of int**[x] specially, since it *doesn't* go backwards +// We have to treat the case of int**[x] specially, since it *doesn't* go +// backwards template struct _parse_impl< - T*, Experimental::Extents, - typename std::enable_if<_all_remaining_extents_dynamic::value>::type -> - : _parse_impl< - T, Experimental::Extents - > -{ }; + T*, Experimental::Extents, + typename std::enable_if<_all_remaining_extents_dynamic::value>::type> + : _parse_impl> {}; // int*(*[x])[y] should still work also (meaning int[][x][][y]) template -struct _parse_impl< - T*, Experimental::Extents, - typename std::enable_if::value>::type -> -{ +struct _parse_impl, + typename std::enable_if< + not _all_remaining_extents_dynamic::value>::type> { using _next = Kokkos::Experimental::AppendExtent< - typename _parse_impl, void>::type, - Experimental::dynamic_extent - >; + typename _parse_impl, void>::type, + Experimental::dynamic_extent>; using type = typename _next::type; }; template -struct _parse_impl< - T[N], Experimental::Extents, void -> - : _parse_impl< - T, Experimental::Extents // TODO @pedantic this could be a narrowing cast - > -{ }; +struct _parse_impl, void> + : _parse_impl // TODO @pedantic this + // could be a + // narrowing cast + > {}; -} // end namespace _parse_view_extents_impl +} // end namespace _parse_view_extents_impl template struct ParseViewExtents { - using type = - typename _parse_view_extents_impl - ::_parse_impl>::type; + using type = typename _parse_view_extents_impl ::_parse_impl< + DataType, Experimental::Extents<>>::type; }; template -struct ApplyExtent -{ +struct ApplyExtent { using type = ValueType[Ext]; }; template -struct ApplyExtent -{ +struct ApplyExtent { using type = ValueType*; }; template -struct ApplyExtent -{ +struct ApplyExtent { using type = typename ApplyExtent::type[N]; }; template -struct ApplyExtent -{ - using type = ValueType*[Ext]; +struct ApplyExtent { + using type = ValueType * [Ext]; }; template -struct ApplyExtent -{ - using type = typename ApplyExtent::type*; +struct ApplyExtent { + using type = + typename ApplyExtent::type*; }; template -struct ApplyExtent -{ - using type = typename ApplyExtent::type[N]; +struct ApplyExtent { + using type = + typename ApplyExtent::type[N]; }; -} // end namespace Impl +} // end namespace Impl -} // end namespace Kokkos +} // end namespace Kokkos -#endif //KOKKOS_KOKKOS_EXTENTS_HPP +#endif // KOKKOS_KOKKOS_EXTENTS_HPP diff --git a/lib/kokkos/core/src/Kokkos_Future.hpp b/lib/kokkos/core/src/Kokkos_Future.hpp index 665ce71cf5..15a5d39aad 100644 --- a/lib/kokkos/core/src/Kokkos_Future.hpp +++ b/lib/kokkos/core/src/Kokkos_Future.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -47,7 +48,7 @@ //---------------------------------------------------------------------------- #include -#if defined( KOKKOS_ENABLE_TASKDAG ) +#if defined(KOKKOS_ENABLE_TASKDAG) #include #include @@ -58,7 +59,7 @@ #include #include -#include // is_space +#include // is_space //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -66,202 +67,165 @@ namespace Kokkos { // For now, hack this in as a partial specialization -// TODO @tasking @cleanup Make this the "normal" class template and make the old code the specialization +// TODO @tasking @cleanup Make this the "normal" class template and make the old +// code the specialization template -class BasicFuture> -{ -public: - - using value_type = ValueType; +class BasicFuture> { + public: + using value_type = ValueType; using execution_space = ExecutionSpace; - using scheduler_type = SimpleTaskScheduler; - using queue_type = typename scheduler_type::task_queue_type; - - -private: + using scheduler_type = SimpleTaskScheduler; + using queue_type = typename scheduler_type::task_queue_type; + private: template friend class SimpleTaskScheduler; template friend class BasicFuture; - using task_base_type = typename scheduler_type::task_base_type; + using task_base_type = typename scheduler_type::task_base_type; using task_queue_type = typename scheduler_type::task_queue_type; using task_queue_traits = typename scheduler_type::task_queue_traits; - using task_scheduling_info_type = typename scheduler_type::task_scheduling_info_type; + using task_scheduling_info_type = + typename scheduler_type::task_scheduling_info_type; - using result_storage_type = - Impl::TaskResultStorage< + using result_storage_type = Impl::TaskResultStorage< ValueType, - Impl::SchedulingInfoStorage< - Impl::RunnableTaskBase, - task_scheduling_info_type - > - >; - - + Impl::SchedulingInfoStorage, + task_scheduling_info_type>>; OwningRawPtr m_task = nullptr; KOKKOS_INLINE_FUNCTION - explicit - BasicFuture(task_base_type* task) - : m_task(task) - { + explicit BasicFuture(task_base_type* task) : m_task(task) { // Note: reference count starts at 2 to account for initial increment - // TODO @tasking @minor DSH verify reference count here and/or encapsulate starting reference count closer to here + // TODO @tasking @minor DSH verify reference count here and/or encapsulate + // starting reference count closer to here } -public: - + public: KOKKOS_INLINE_FUNCTION - BasicFuture() noexcept : m_task(nullptr) { } + BasicFuture() noexcept : m_task(nullptr) {} KOKKOS_INLINE_FUNCTION - BasicFuture(BasicFuture&& rhs) noexcept - : m_task(std::move(rhs.m_task)) - { + BasicFuture(BasicFuture&& rhs) noexcept : m_task(std::move(rhs.m_task)) { rhs.m_task = nullptr; } KOKKOS_INLINE_FUNCTION BasicFuture(BasicFuture const& rhs) - // : m_task(rhs.m_task) - : m_task(nullptr) - { + // : m_task(rhs.m_task) + : m_task(nullptr) { *static_cast(&m_task) = rhs.m_task; - if(m_task) m_task->increment_reference_count(); + if (m_task) m_task->increment_reference_count(); } KOKKOS_INLINE_FUNCTION - BasicFuture& operator=(BasicFuture&& rhs) noexcept - { - if(m_task != rhs.m_task) { + BasicFuture& operator=(BasicFuture&& rhs) noexcept { + if (m_task != rhs.m_task) { clear(); - //m_task = std::move(rhs.m_task); + // m_task = std::move(rhs.m_task); *static_cast(&m_task) = rhs.m_task; // rhs.m_task reference count is unchanged, since this is a move - } - else { + } else { // They're the same, but this is a move, so 1 fewer references now rhs.clear(); } rhs.m_task = nullptr; - return *this ; + return *this; } KOKKOS_INLINE_FUNCTION - BasicFuture& operator=(BasicFuture const& rhs) - { - if(m_task != rhs.m_task) { + BasicFuture& operator=(BasicFuture const& rhs) { + if (m_task != rhs.m_task) { clear(); - //m_task = rhs.m_task; + // m_task = rhs.m_task; *static_cast(&m_task) = rhs.m_task; } - if(m_task != nullptr) { m_task->increment_reference_count(); } + if (m_task != nullptr) { + m_task->increment_reference_count(); + } return *this; } //---------------------------------------- template - KOKKOS_INLINE_FUNCTION - BasicFuture(BasicFuture&& rhs) noexcept // NOLINT(google-explicit-constructor) - : m_task(std::move(rhs.m_task)) - { - static_assert( - std::is_same::value || - std::is_same::value, - "Moved Futures must have the same scheduler" - ); - - static_assert( - std::is_same::value || - std::is_same::value, - "Moved Futures must have the same value_type" - ); + KOKKOS_INLINE_FUNCTION BasicFuture( + BasicFuture&& rhs) noexcept // NOLINT(google-explicit-constructor) + : m_task(std::move(rhs.m_task)) { + static_assert(std::is_same::value || + std::is_same::value, + "Moved Futures must have the same scheduler"); + + static_assert(std::is_same::value || + std::is_same::value, + "Moved Futures must have the same value_type"); // reference counts are unchanged, since this is a move rhs.m_task = nullptr; } template - KOKKOS_INLINE_FUNCTION - BasicFuture(BasicFuture const& rhs) // NOLINT(google-explicit-constructor) - //: m_task(rhs.m_task) - : m_task(nullptr) - { - static_assert( - std::is_same::value || - std::is_same::value, - "Copied Futures must have the same scheduler" - ); - - static_assert( - std::is_same::value || - std::is_same::value, - "Copied Futures must have the same value_type" - ); + KOKKOS_INLINE_FUNCTION BasicFuture( + BasicFuture const& rhs) // NOLINT(google-explicit-constructor) + //: m_task(rhs.m_task) + : m_task(nullptr) { + static_assert(std::is_same::value || + std::is_same::value, + "Copied Futures must have the same scheduler"); + + static_assert(std::is_same::value || + std::is_same::value, + "Copied Futures must have the same value_type"); *static_cast(&m_task) = rhs.m_task; - if(m_task) m_task->increment_reference_count(); + if (m_task) m_task->increment_reference_count(); } template - KOKKOS_INLINE_FUNCTION - BasicFuture& - operator=(BasicFuture const& rhs) - { - static_assert( - std::is_same::value || - std::is_same::value, - "Assigned Futures must have the same scheduler" - ); - - static_assert( - std::is_same::value || - std::is_same::value, - "Assigned Futures must have the same value_type" - ); - - if(m_task != rhs.m_task) { + KOKKOS_INLINE_FUNCTION BasicFuture& operator=(BasicFuture const& rhs) { + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same scheduler"); + + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same value_type"); + + if (m_task != rhs.m_task) { clear(); - //m_task = rhs.m_task; + // m_task = rhs.m_task; *static_cast(&m_task) = rhs.m_task; - if(m_task != nullptr) { m_task->increment_reference_count(); } + if (m_task != nullptr) { + m_task->increment_reference_count(); + } } return *this; } - template - KOKKOS_INLINE_FUNCTION - BasicFuture& operator=(BasicFuture&& rhs) - { - static_assert( - std::is_same::value || - std::is_same::value, - "Assigned Futures must have the same scheduler" - ); - - static_assert( - std::is_same::value || - std::is_same::value, - "Assigned Futures must have the same value_type" - ); - - if(m_task != rhs.m_task) { + template + KOKKOS_INLINE_FUNCTION BasicFuture& operator=(BasicFuture&& rhs) { + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same scheduler"); + + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same value_type"); + + if (m_task != rhs.m_task) { clear(); - //m_task = std::move(rhs.m_task); + // m_task = std::move(rhs.m_task); *static_cast(&m_task) = rhs.m_task; // rhs.m_task reference count is unchanged, since this is a move - } - else { + } else { // They're the same, but this is a move, so 1 fewer references now rhs.clear(); } rhs.m_task = nullptr; - return *this ; + return *this; } KOKKOS_INLINE_FUNCTION @@ -271,22 +235,19 @@ public: KOKKOS_INLINE_FUNCTION void clear() noexcept { - if(m_task) { + if (m_task) { bool should_delete = m_task->decrement_and_check_reference_count(); - if(should_delete) { + if (should_delete) { static_cast(m_task->ready_queue_base_ptr()) - ->deallocate(std::move(*m_task)); + ->deallocate(std::move(*m_task)); } } - //m_task = nullptr; + // m_task = nullptr; *static_cast(&m_task) = nullptr; } KOKKOS_INLINE_FUNCTION - bool is_null() const noexcept { - return m_task == nullptr; - } - + bool is_null() const noexcept { return m_task == nullptr; } KOKKOS_INLINE_FUNCTION bool is_ready() const noexcept { @@ -294,14 +255,11 @@ public: } KOKKOS_INLINE_FUNCTION - const typename Impl::TaskResult< ValueType >::reference_type - get() const - { + const typename Impl::TaskResult::reference_type get() const { KOKKOS_EXPECTS(is_ready()); return static_cast(m_task)->value_reference(); - //return Impl::TaskResult::get(m_task); + // return Impl::TaskResult::get(m_task); } - }; //////////////////////////////////////////////////////////////////////////////// @@ -310,57 +268,57 @@ public: template class BasicFuture { -private: - - template< typename , typename > friend class BasicTaskScheduler ; - template< typename , typename > friend class BasicFuture ; - friend class Impl::TaskBase ; - template< typename , typename , typename > friend class Impl::Task ; - + private: + template + friend class BasicTaskScheduler; + template + friend class BasicFuture; + friend class Impl::TaskBase; + template + friend class Impl::Task; //---------------------------------------- -public: - + public: //---------------------------------------- - using scheduler_type = Scheduler; - using queue_type = typename scheduler_type::queue_type; + using scheduler_type = Scheduler; + using queue_type = typename scheduler_type::queue_type; using execution_space = typename scheduler_type::execution_space; - using value_type = ValueType; + using value_type = ValueType; //---------------------------------------- -private: - + private: //---------------------------------------- - using task_base = Impl::TaskBase; + using task_base = Impl::TaskBase; - task_base * m_task ; + task_base* m_task; - KOKKOS_INLINE_FUNCTION explicit - BasicFuture( task_base * task ) : m_task(0) - { if ( task ) queue_type::assign( & m_task , task ); } + KOKKOS_INLINE_FUNCTION explicit BasicFuture(task_base* task) : m_task(0) { + if (task) queue_type::assign(&m_task, task); + } //---------------------------------------- -public: - + public: //---------------------------------------- KOKKOS_INLINE_FUNCTION - bool is_null() const { return 0 == m_task ; } + bool is_null() const { return 0 == m_task; } KOKKOS_INLINE_FUNCTION - int reference_count() const - { return 0 != m_task ? m_task->reference_count() : 0 ; } + int reference_count() const { + return 0 != m_task ? m_task->reference_count() : 0; + } //---------------------------------------- KOKKOS_INLINE_FUNCTION - void clear() - { if ( m_task ) queue_type::assign( & m_task , (task_base*)0 ); } + void clear() { + if (m_task) queue_type::assign(&m_task, (task_base*)0); + } //---------------------------------------- @@ -370,141 +328,121 @@ public: //---------------------------------------- KOKKOS_INLINE_FUNCTION - BasicFuture() noexcept : m_task(nullptr) { } + BasicFuture() noexcept : m_task(nullptr) {} KOKKOS_INLINE_FUNCTION - BasicFuture( BasicFuture && rhs ) noexcept - : m_task( rhs.m_task ) - { + BasicFuture(BasicFuture&& rhs) noexcept : m_task(rhs.m_task) { rhs.m_task = 0; } KOKKOS_INLINE_FUNCTION - BasicFuture( const BasicFuture & rhs ) - : m_task(0) - { if ( rhs.m_task ) queue_type::assign( & m_task , rhs.m_task ); } + BasicFuture(const BasicFuture& rhs) : m_task(0) { + if (rhs.m_task) queue_type::assign(&m_task, rhs.m_task); + } KOKKOS_INLINE_FUNCTION - BasicFuture& operator=(BasicFuture&& rhs) noexcept - { + BasicFuture& operator=(BasicFuture&& rhs) noexcept { clear(); - m_task = rhs.m_task ; - rhs.m_task = 0 ; - return *this ; + m_task = rhs.m_task; + rhs.m_task = 0; + return *this; } KOKKOS_INLINE_FUNCTION - BasicFuture& operator=(BasicFuture const& rhs) - { - if ( m_task || rhs.m_task ) queue_type::assign( & m_task , rhs.m_task ); - return *this ; + BasicFuture& operator=(BasicFuture const& rhs) { + if (m_task || rhs.m_task) queue_type::assign(&m_task, rhs.m_task); + return *this; } //---------------------------------------- template - KOKKOS_INLINE_FUNCTION - BasicFuture(BasicFuture&& rhs) noexcept // NOLINT(google-explicit-constructor) - : m_task( rhs.m_task ) - { - static_assert - ( std::is_same::value || - std::is_same::value - , "Assigned Futures must have the same scheduler" ); - - static_assert - ( std::is_same< value_type , void >::value || - std::is_same::value - , "Assigned Futures must have the same value_type" ); - - rhs.m_task = 0 ; + KOKKOS_INLINE_FUNCTION BasicFuture( + BasicFuture&& rhs) noexcept // NOLINT(google-explicit-constructor) + : m_task(rhs.m_task) { + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same scheduler"); + + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same value_type"); + + rhs.m_task = 0; } template - KOKKOS_INLINE_FUNCTION - BasicFuture(BasicFuture const& rhs) // NOLINT(google-explicit-constructor) - : m_task(nullptr) - { - static_assert - ( std::is_same::value || - std::is_same::value - , "Assigned Futures must have the same scheduler" ); - - static_assert - ( std::is_same< value_type , void >::value || - std::is_same::value - , "Assigned Futures must have the same value_type" ); - - if ( rhs.m_task ) queue_type::assign( & m_task , rhs.m_task ); + KOKKOS_INLINE_FUNCTION BasicFuture( + BasicFuture const& rhs) // NOLINT(google-explicit-constructor) + : m_task(nullptr) { + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same scheduler"); + + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same value_type"); + + if (rhs.m_task) queue_type::assign(&m_task, rhs.m_task); } template - KOKKOS_INLINE_FUNCTION - BasicFuture& - operator=(BasicFuture const& rhs) - { - static_assert - ( std::is_same::value || - std::is_same::value - , "Assigned Futures must have the same scheduler" ); - - static_assert - ( std::is_same< value_type , void >::value || - std::is_same::value - , "Assigned Futures must have the same value_type" ); - - if ( m_task || rhs.m_task ) queue_type::assign( & m_task , rhs.m_task ); - return *this ; + KOKKOS_INLINE_FUNCTION BasicFuture& operator=(BasicFuture const& rhs) { + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same scheduler"); + + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same value_type"); + + if (m_task || rhs.m_task) queue_type::assign(&m_task, rhs.m_task); + return *this; } - template - KOKKOS_INLINE_FUNCTION - BasicFuture& operator=(BasicFuture&& rhs) - { - static_assert - ( std::is_same::value || - std::is_same::value - , "Assigned Futures must have the same scheduler" ); - - static_assert - ( std::is_same< value_type , void >::value || - std::is_same::value - , "Assigned Futures must have the same value_type" ); + template + KOKKOS_INLINE_FUNCTION BasicFuture& operator=(BasicFuture&& rhs) { + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same scheduler"); + + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same value_type"); clear(); - m_task = rhs.m_task ; - rhs.m_task = 0 ; - return *this ; + m_task = rhs.m_task; + rhs.m_task = 0; + return *this; } //---------------------------------------- KOKKOS_INLINE_FUNCTION - int is_ready() const noexcept - { return ( 0 == m_task ) || ( ((task_base*) task_base::LockTag) == m_task->m_wait ); } + int is_ready() const noexcept { + return (0 == m_task) || + (((task_base*)task_base::LockTag) == m_task->m_wait); + } KOKKOS_INLINE_FUNCTION - const typename Impl::TaskResult< ValueType >::reference_type - get() const - { - if ( 0 == m_task ) { - Kokkos::abort( "Kokkos:::Future::get ERROR: is_null()"); + const typename Impl::TaskResult::reference_type get() const { + if (0 == m_task) { + Kokkos::abort("Kokkos:::Future::get ERROR: is_null()"); } - return Impl::TaskResult< ValueType >::get( m_task ); + return Impl::TaskResult::get(m_task); } }; // Is a Future with the given execution space -template< typename , typename ExecSpace = void > +template struct is_future : public std::false_type {}; -template +template struct is_future, ExecSpace> - : std::integral_constant::value - || std::is_void::value - > -{}; + : std::integral_constant< + bool, + std::is_same::value || + std::is_void::value> {}; //////////////////////////////////////////////////////////////////////////////// // END OLD CODE @@ -514,39 +452,32 @@ namespace Impl { template class ResolveFutureArgOrder { -private: + private: enum { Arg1_is_space = Kokkos::is_space::value }; enum { Arg2_is_space = Kokkos::is_space::value }; enum { Arg1_is_value = !Arg1_is_space && !std::is_same::value }; enum { Arg2_is_value = !Arg2_is_space && !std::is_same::value }; - static_assert( - ! ( Arg1_is_space && Arg2_is_space ), - "Future cannot be given two spaces" - ); - - static_assert( - ! ( Arg1_is_value && Arg2_is_value ), - "Future cannot be given two value types" - ); + static_assert(!(Arg1_is_space && Arg2_is_space), + "Future cannot be given two spaces"); - using value_type = - typename std::conditional::type - >::type; + static_assert(!(Arg1_is_value && Arg2_is_value), + "Future cannot be given two value types"); - using execution_space = - typename std::conditional::type - >::type::execution_space; + using value_type = typename std::conditional< + Arg1_is_value, Arg1, + typename std::conditional::type>::type; -public: + using execution_space = typename std::conditional< + Arg1_is_space, Arg1, + typename std::conditional::type>::type::execution_space; + public: using type = BasicFuture>; - }; -} // end namespace Impl +} // end namespace Impl /** * @@ -558,7 +489,7 @@ public: template using Future = typename Impl::ResolveFutureArgOrder::type; -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- diff --git a/lib/kokkos/core/src/Kokkos_HBWSpace.hpp b/lib/kokkos/core/src/Kokkos_HBWSpace.hpp index aaac7cd7f9..357dcc9014 100644 --- a/lib/kokkos/core/src/Kokkos_HBWSpace.hpp +++ b/lib/kokkos/core/src/Kokkos_HBWSpace.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -63,26 +64,26 @@ namespace Impl { /// This function initializes the locks to zero (unset). void init_lock_array_hbw_space(); -/// \brief Acquire a lock for the address +/// \brief Aquire a lock for the address /// -/// This function tries to acquire the lock for the hash value derived -/// from the provided ptr. If the lock is successfully acquired the +/// This function tries to aquire the lock for the hash value derived +/// from the provided ptr. If the lock is successfully aquired the /// function returns true. Otherwise it returns false. -bool lock_address_hbw_space( void* ptr ); +bool lock_address_hbw_space(void* ptr); /// \brief Release lock for the address /// /// This function releases the lock for the hash value derived /// from the provided ptr. This function should only be called -/// after previously successfully acquiring a lock with +/// after previously successfully aquiring a lock with /// lock_address. -void unlock_address_hbw_space( void* ptr ); +void unlock_address_hbw_space(void* ptr); -} // namespace Impl +} // namespace Impl -} // namespace Experimental +} // namespace Experimental -} // namespace Kokkos +} // namespace Kokkos namespace Kokkos { @@ -94,10 +95,10 @@ namespace Experimental { /// HBWSpace is a memory space that governs host memory. "Host" /// memory means the usual CPU-accessible memory. class HBWSpace { -public: + public: //! Tag this class as a kokkos memory space - typedef HBWSpace memory_space; - typedef size_t size_type; + typedef HBWSpace memory_space; + typedef size_t size_type; /// \typedef execution_space /// \brief Default execution space for this memory space. @@ -105,59 +106,64 @@ public: /// Every memory space has a default execution space. This is /// useful for things like initializing a View (which happens in /// parallel using the View's default execution space). -#if defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP ) - typedef Kokkos::OpenMP execution_space; -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS ) - typedef Kokkos::Threads execution_space; +#if defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP) + typedef Kokkos::OpenMP execution_space; +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS) + typedef Kokkos::Threads execution_space; //#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_QTHREADS ) // typedef Kokkos::Qthreads execution_space; -#elif defined( KOKKOS_ENABLE_OPENMP ) - typedef Kokkos::OpenMP execution_space; -#elif defined( KOKKOS_ENABLE_THREADS ) - typedef Kokkos::Threads execution_space; +#elif defined(KOKKOS_ENABLE_OPENMP) + typedef Kokkos::OpenMP execution_space; +#elif defined(KOKKOS_ENABLE_THREADS) + typedef Kokkos::Threads execution_space; //#elif defined( KOKKOS_ENABLE_QTHREADS ) // typedef Kokkos::Qthreads execution_space; -#elif defined( KOKKOS_ENABLE_SERIAL ) - typedef Kokkos::Serial execution_space; +#elif defined(KOKKOS_ENABLE_SERIAL) + typedef Kokkos::Serial execution_space; #else -# error "At least one of the following host execution spaces must be defined: Kokkos::OpenMP, Kokkos::Threads, Kokkos::Qhreads, or Kokkos::Serial. You might be seeing this message if you disabled the Kokkos::Serial device explicitly using the Kokkos_ENABLE_Serial:BOOL=OFF CMake option, but did not enable any of the other host execution space devices." +#error \ + "At least one of the following host execution spaces must be defined: Kokkos::OpenMP, Kokkos::Threads, Kokkos::Qhreads, or Kokkos::Serial. You might be seeing this message if you disabled the Kokkos::Serial device explicitly using the Kokkos_ENABLE_Serial:BOOL=OFF CMake option, but did not enable any of the other host execution space devices." #endif //! This memory space preferred device_type - typedef Kokkos::Device< execution_space, memory_space > device_type; + typedef Kokkos::Device device_type; /**\brief Default memory space instance */ HBWSpace(); - HBWSpace( const HBWSpace & rhs ) = default; - HBWSpace & operator = ( const HBWSpace & ) = default; - ~HBWSpace() = default; + HBWSpace(const HBWSpace& rhs) = default; + HBWSpace& operator=(const HBWSpace&) = default; + ~HBWSpace() = default; - /**\brief Non-default memory space instance to choose allocation mechansim, if available */ + /**\brief Non-default memory space instance to choose allocation mechansim, + * if available */ - enum AllocationMechanism { STD_MALLOC, POSIX_MEMALIGN, POSIX_MMAP, INTEL_MM_ALLOC }; + enum AllocationMechanism { + STD_MALLOC, + POSIX_MEMALIGN, + POSIX_MMAP, + INTEL_MM_ALLOC + }; - explicit - HBWSpace( const AllocationMechanism & ); + explicit HBWSpace(const AllocationMechanism&); /**\brief Allocate untracked memory in the space */ - void * allocate( const size_t arg_alloc_size ) const; + void* allocate(const size_t arg_alloc_size) const; /**\brief Deallocate untracked memory in the space */ - void deallocate( void * const arg_alloc_ptr - , const size_t arg_alloc_size ) const; + void deallocate(void* const arg_alloc_ptr, const size_t arg_alloc_size) const; /**\brief Return Name of the MemorySpace */ static constexpr const char* name() { return "HBW"; } -private: - - AllocationMechanism m_alloc_mech; - friend class Kokkos::Impl::SharedAllocationRecord< Kokkos::Experimental::HBWSpace, void >; + private: + AllocationMechanism m_alloc_mech; + friend class Kokkos::Impl::SharedAllocationRecord< + Kokkos::Experimental::HBWSpace, void>; }; -} // namespace Experimental +} // namespace Experimental -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- @@ -165,20 +171,18 @@ namespace Kokkos { namespace Impl { -template<> -class SharedAllocationRecord< Kokkos::Experimental::HBWSpace, void > - : public SharedAllocationRecord< void, void > -{ -private: - +template <> +class SharedAllocationRecord + : public SharedAllocationRecord { + private: friend Kokkos::Experimental::HBWSpace; - typedef SharedAllocationRecord< void, void > RecordBase; + typedef SharedAllocationRecord RecordBase; - SharedAllocationRecord( const SharedAllocationRecord & ) = delete; - SharedAllocationRecord & operator = ( const SharedAllocationRecord & ) = delete; + SharedAllocationRecord(const SharedAllocationRecord&) = delete; + SharedAllocationRecord& operator=(const SharedAllocationRecord&) = delete; - static void deallocate( RecordBase * ); + static void deallocate(RecordBase*); #ifdef KOKKOS_DEBUG /**\brief Root record for tracked allocations from this HBWSpace instance */ @@ -187,61 +191,52 @@ private: const Kokkos::Experimental::HBWSpace m_space; -protected: - + protected: ~SharedAllocationRecord(); SharedAllocationRecord() = default; - SharedAllocationRecord( const Kokkos::Experimental::HBWSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - , const RecordBase::function_type arg_dealloc = & deallocate - ); - -public: - - inline - std::string get_label() const - { - return std::string( RecordBase::head()->m_label ); - } - - KOKKOS_INLINE_FUNCTION static - SharedAllocationRecord * allocate( const Kokkos::Experimental::HBWSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - ) - { -#if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) - return new SharedAllocationRecord( arg_space, arg_label, arg_alloc_size ); + SharedAllocationRecord( + const Kokkos::Experimental::HBWSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size, + const RecordBase::function_type arg_dealloc = &deallocate); + + public: + inline std::string get_label() const { + return std::string(RecordBase::head()->m_label); + } + + KOKKOS_INLINE_FUNCTION static SharedAllocationRecord* allocate( + const Kokkos::Experimental::HBWSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size) { +#if defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST) + return new SharedAllocationRecord(arg_space, arg_label, arg_alloc_size); #else - return (SharedAllocationRecord *) 0; + return (SharedAllocationRecord*)0; #endif - } + } /**\brief Allocate tracked memory in the space */ - static - void * allocate_tracked( const Kokkos::Experimental::HBWSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size ); + static void* allocate_tracked(const Kokkos::Experimental::HBWSpace& arg_space, + const std::string& arg_label, + const size_t arg_alloc_size); /**\brief Reallocate tracked memory in the space */ - static - void * reallocate_tracked( void * const arg_alloc_ptr - , const size_t arg_alloc_size ); + static void* reallocate_tracked(void* const arg_alloc_ptr, + const size_t arg_alloc_size); /**\brief Deallocate tracked memory in the space */ - static - void deallocate_tracked( void * const arg_alloc_ptr ); + static void deallocate_tracked(void* const arg_alloc_ptr); - static SharedAllocationRecord * get_record( void * arg_alloc_ptr ); + static SharedAllocationRecord* get_record(void* arg_alloc_ptr); - static void print_records( std::ostream &, const Kokkos::Experimental::HBWSpace &, bool detail = false ); + static void print_records(std::ostream&, + const Kokkos::Experimental::HBWSpace&, + bool detail = false); }; -} // namespace Impl +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- @@ -249,25 +244,28 @@ namespace Kokkos { namespace Impl { -static_assert( Kokkos::Impl::MemorySpaceAccess< Kokkos::Experimental::HBWSpace, Kokkos::Experimental::HBWSpace >::assignable, "" ); +static_assert( + Kokkos::Impl::MemorySpaceAccess::assignable, + ""); -template<> -struct MemorySpaceAccess< Kokkos::HostSpace, Kokkos::Experimental::HBWSpace > { +template <> +struct MemorySpaceAccess { enum { assignable = true }; enum { accessible = true }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::Experimental::HBWSpace, Kokkos::HostSpace > { +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = true }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -} // namespace Impl +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- @@ -275,70 +273,64 @@ namespace Kokkos { namespace Impl { -template< class ExecutionSpace > -struct DeepCopy< Experimental::HBWSpace, Experimental::HBWSpace, ExecutionSpace > { - DeepCopy( void * dst, const void * src, size_t n ) { - memcpy( dst, src, n ); - } +template +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t n) { memcpy(dst, src, n); } - DeepCopy( const ExecutionSpace& exec, void * dst, const void * src, size_t n ) { + DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, size_t n) { exec.fence(); - memcpy( dst, src, n ); + memcpy(dst, src, n); } }; -template< class ExecutionSpace > -struct DeepCopy< HostSpace, Experimental::HBWSpace, ExecutionSpace > { - DeepCopy( void * dst, const void * src, size_t n ) { - memcpy( dst, src, n ); - } +template +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t n) { memcpy(dst, src, n); } - DeepCopy( const ExecutionSpace& exec, void * dst, const void * src, size_t n ) { + DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, size_t n) { exec.fence(); - memcpy( dst, src, n ); + memcpy(dst, src, n); } }; -template< class ExecutionSpace > -struct DeepCopy< Experimental::HBWSpace, HostSpace, ExecutionSpace > { - DeepCopy( void * dst, const void * src, size_t n ) { - memcpy( dst, src, n ); - } +template +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t n) { memcpy(dst, src, n); } - DeepCopy( const ExecutionSpace& exec, void * dst, const void * src, size_t n ) { + DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, size_t n) { exec.fence(); - memcpy( dst, src, n ); + memcpy(dst, src, n); } }; -} // namespace Impl +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos namespace Kokkos { namespace Impl { -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::HostSpace, Kokkos::Experimental::HBWSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = true }; - inline static void verify( void ) { } - inline static void verify( const void * ) { } + inline static void verify(void) {} + inline static void verify(const void*) {} }; -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::Experimental::HBWSpace, Kokkos::HostSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = true }; - inline static void verify( void ) { } - inline static void verify( const void * ) { } + inline static void verify(void) {} + inline static void verify(const void*) {} }; -} // namespace Impl +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos #endif -#endif // #define KOKKOS_HBWSPACE_HPP - +#endif // #define KOKKOS_HBWSPACE_HPP diff --git a/lib/kokkos/core/src/Kokkos_HPX.hpp b/lib/kokkos/core/src/Kokkos_HPX.hpp index 79a2b74da4..46101c824f 100644 --- a/lib/kokkos/core/src/Kokkos_HPX.hpp +++ b/lib/kokkos/core/src/Kokkos_HPX.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -57,6 +58,7 @@ #include #endif +#include #include #include #include @@ -74,7 +76,7 @@ #include #include #include -#include +#include #include #include #include @@ -97,6 +99,7 @@ // - 1: The manual way. This way is more verbose and does not take advantage of // e.g. parallel::for_loop in HPX but it is significantly faster in many // benchmarks. +// - 2: Like 1, but spawn tasks using for_loop and a custom executor. // // In the long run 0 should be the preferred implementation, but until HPX is // improved 1 will be the default. @@ -104,7 +107,7 @@ #define KOKKOS_HPX_IMPLEMENTATION 1 #endif -#if (KOKKOS_HPX_IMPLEMENTATION < 0) || (KOKKOS_HPX_IMPLEMENTATION > 1) +#if (KOKKOS_HPX_IMPLEMENTATION < 0) || (KOKKOS_HPX_IMPLEMENTATION > 2) #error "You have chosen an invalid value for KOKKOS_HPX_IMPLEMENTATION" #endif @@ -123,9 +126,11 @@ class thread_buffer { m_cache_line_size; } -public: + public: thread_buffer() - : m_num_threads(0), m_size_per_thread(0), m_size_total(0), + : m_num_threads(0), + m_size_per_thread(0), + m_size_total(0), m_data(nullptr) {} thread_buffer(const std::size_t num_threads, const std::size_t size_per_thread) { @@ -134,13 +139,13 @@ public: ~thread_buffer() { delete[] m_data; } thread_buffer(const thread_buffer &) = delete; - thread_buffer(thread_buffer &&) = delete; + thread_buffer(thread_buffer &&) = delete; thread_buffer &operator=(const thread_buffer &) = delete; thread_buffer &operator=(thread_buffer) = delete; void resize(const std::size_t num_threads, const std::size_t size_per_thread) { - m_num_threads = num_threads; + m_num_threads = num_threads; m_size_per_thread = size_per_thread; pad_to_cache_line(m_size_per_thread); @@ -149,7 +154,7 @@ public: if (m_size_total < size_total_new) { delete[] m_data; - m_data = new char[size_total_new]; + m_data = new char[size_total_new]; m_size_total = size_total_new; } } @@ -165,23 +170,23 @@ public: std::size_t size_per_thread() const noexcept { return m_size_per_thread; } std::size_t size_total() const noexcept { return m_size_total; } }; -} // namespace Impl +} // namespace Impl namespace Experimental { class HPX { -private: + private: static bool m_hpx_initialized; static Kokkos::Impl::thread_buffer m_buffer; #if defined(KOKKOS_ENABLE_HPX_ASYNC_DISPATCH) static hpx::future m_future; #endif -public: - using execution_space = HPX; - using memory_space = HostSpace; - using device_type = Kokkos::Device; - using array_layout = LayoutRight; - using size_type = memory_space::size_type; + public: + using execution_space = HPX; + using memory_space = HostSpace; + using device_type = Kokkos::Device; + using array_layout = LayoutRight; + using size_type = memory_space::size_type; using scratch_memory_space = ScratchMemorySpace; HPX() noexcept {} @@ -192,26 +197,20 @@ public: static bool in_parallel(HPX const & = HPX()) noexcept { return false; } static void impl_static_fence(HPX const & = HPX()) - #if defined(KOKKOS_ENABLE_HPX_ASYNC_DISPATCH) - { - if (hpx::threads::get_self_ptr() == nullptr) { - hpx::threads::run_as_hpx_thread([]() { impl_get_future().wait(); }); - } else { - impl_get_future().wait(); - } - } - #else - noexcept { +#if defined(KOKKOS_ENABLE_HPX_ASYNC_DISPATCH) + { + if (hpx::threads::get_self_ptr() == nullptr) { + hpx::threads::run_as_hpx_thread([]() { impl_get_future().wait(); }); + } else { + impl_get_future().wait(); } - #endif - - #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - static void fence(HPX const & = HPX()) { - #else - void fence() const { - #endif - impl_static_fence(); } +#else + noexcept { + } +#endif + + void fence() const { impl_static_fence(); } static bool is_asynchronous(HPX const & = HPX()) noexcept { #if defined(KOKKOS_ENABLE_HPX_ASYNC_DISPATCH) @@ -222,8 +221,9 @@ public: } static std::vector partition(...) { - Kokkos::abort("Kokkos::Experimental::HPX::partition_master: can't partition an HPX " - "instance\n"); + Kokkos::abort( + "Kokkos::Experimental::HPX::partition_master: can't partition an HPX " + "instance\n"); return std::vector(); } @@ -231,8 +231,9 @@ public: static void partition_master(F const &f, int requested_num_partitions = 0, int requested_partition_size = 0) { if (requested_num_partitions > 1) { - Kokkos::abort("Kokkos::Experimental::HPX::partition_master: can't partition an " - "HPX instance\n"); + Kokkos::abort( + "Kokkos::Experimental::HPX::partition_master: can't partition an " + "HPX instance\n"); } } @@ -287,13 +288,14 @@ public: static Kokkos::Impl::thread_buffer &impl_get_buffer() noexcept { return m_buffer; } + #if defined(KOKKOS_ENABLE_HPX_ASYNC_DISPATCH) static hpx::future &impl_get_future() noexcept { return m_future; } #endif static constexpr const char *name() noexcept { return "HPX"; } }; -} // namespace Experimental +} // namespace Experimental namespace Impl { template @@ -302,15 +304,15 @@ inline void dispatch_execute_task(Closure *closure) { if (hpx::threads::get_self_ptr() == nullptr) { hpx::threads::run_as_hpx_thread([closure]() { hpx::future &fut = Kokkos::Experimental::HPX::impl_get_future(); - Closure closure_copy = *closure; - fut = fut.then([closure_copy](hpx::future &&) { + Closure closure_copy = *closure; + fut = fut.then([closure_copy](hpx::future &&) { closure_copy.execute_task(); }); }); } else { hpx::future &fut = Kokkos::Experimental::HPX::impl_get_future(); - Closure closure_copy = *closure; - fut = fut.then( + Closure closure_copy = *closure; + fut = fut.then( [closure_copy](hpx::future &&) { closure_copy.execute_task(); }); } #else @@ -321,8 +323,8 @@ inline void dispatch_execute_task(Closure *closure) { } #endif } -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos namespace Kokkos { namespace Impl { @@ -342,15 +344,16 @@ struct VerifyExecutionCanAccessMemorySpace< inline static void verify(void) {} inline static void verify(const void *) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos namespace Kokkos { namespace Experimental { -template <> class UniqueToken { -public: +template <> +class UniqueToken { + public: using execution_space = HPX; - using size_type = int; + using size_type = int; UniqueToken(execution_space const & = execution_space()) noexcept {} // NOTE: Currently this assumes that there is no oversubscription. @@ -361,10 +364,11 @@ public: void release(int) const noexcept {} }; -template <> class UniqueToken { -public: +template <> +class UniqueToken { + public: using execution_space = HPX; - using size_type = int; + using size_type = int; UniqueToken(execution_space const & = execution_space()) noexcept {} // NOTE: Currently this assumes that there is no oversubscription. @@ -374,28 +378,27 @@ public: int acquire() const noexcept { return HPX::impl_hardware_thread_id(); } void release(int) const noexcept {} }; -} // namespace Experimental -} // namespace Kokkos +} // namespace Experimental +} // namespace Kokkos namespace Kokkos { namespace Impl { struct HPXTeamMember { -public: + public: using execution_space = Kokkos::Experimental::HPX; using scratch_memory_space = Kokkos::ScratchMemorySpace; -private: + private: scratch_memory_space m_team_shared; - std::size_t m_team_shared_size; int m_league_size; int m_league_rank; int m_team_size; int m_team_rank; -public: + public: KOKKOS_INLINE_FUNCTION const scratch_memory_space &team_shmem() const { return m_team_shared.set_team_thread_mode(0, 1, 0); @@ -423,14 +426,15 @@ public: KOKKOS_INLINE_FUNCTION int team_size() const noexcept { return m_team_size; } template - constexpr KOKKOS_INLINE_FUNCTION - HPXTeamMember(const TeamPolicyInternal &policy, - const int team_rank, const int league_rank, void *scratch, - int scratch_size) noexcept + constexpr KOKKOS_INLINE_FUNCTION HPXTeamMember( + const TeamPolicyInternal + &policy, + const int team_rank, const int league_rank, void *scratch, + int scratch_size) noexcept : m_team_shared(scratch, scratch_size, scratch, scratch_size), - m_team_shared_size(scratch_size), m_league_size(policy.league_size()), - m_league_rank(league_rank), m_team_size(policy.team_size()), + m_league_size(policy.league_size()), + m_league_rank(league_rank), + m_team_size(policy.team_size()), m_team_rank(team_rank) {} KOKKOS_INLINE_FUNCTION @@ -482,7 +486,7 @@ class TeamPolicyInternal std::size_t m_thread_scratch_size[2]; int m_chunk_size; -public: + public: using member_type = HPXTeamMember; // NOTE: Max size is 1 for simplicity. In most cases more than 1 is not @@ -511,21 +515,35 @@ public: int team_size_max(const FunctorType &, const ParallelReduceTag &) const { return 1; } + + template + int team_size_max(const FunctorType &, const ReducerType &, + const ParallelReduceTag &) const { + return 1; + } + template int team_size_recommended(const FunctorType &, const ParallelForTag &) const { return 1; } + template int team_size_recommended(const FunctorType &, const ParallelReduceTag &) const { return 1; } -private: + template + int team_size_recommended(const FunctorType &, const ReducerType &, + const ParallelReduceTag &) const { + return 1; + } + + private: inline void init(const int league_size_request, const int team_size_request) { - m_league_size = league_size_request; - const int max_team_size = 1; // TODO: Can't use team_size_max(...) because - // it requires a functor as argument. + m_league_size = league_size_request; + const int max_team_size = 1; // TODO: Can't use team_size_max(...) because + // it requires a functor as argument. m_team_size = team_size_request > max_team_size ? max_team_size : team_size_request; @@ -551,7 +569,7 @@ private: } } -public: + public: inline int team_size() const { return m_team_size; } inline int league_size() const { return m_league_size; } @@ -563,26 +581,32 @@ public: team_size_ * m_thread_scratch_size[level]; } -public: + inline static int scratch_size_max(int level) { + return (level == 0 ? 1024 * 32 : // Roughly L1 size + 20 * 1024 * 1024); // Limit to keep compatibility with CUDA + } + + public: template friend class TeamPolicyInternal; template - TeamPolicyInternal( - const TeamPolicyInternal &p) { - m_league_size = p.m_league_size; - m_team_size = p.m_team_size; - m_team_scratch_size[0] = p.m_team_scratch_size[0]; + TeamPolicyInternal(const TeamPolicyInternal &p) { + m_league_size = p.m_league_size; + m_team_size = p.m_team_size; + m_team_scratch_size[0] = p.m_team_scratch_size[0]; m_thread_scratch_size[0] = p.m_thread_scratch_size[0]; - m_team_scratch_size[1] = p.m_team_scratch_size[1]; + m_team_scratch_size[1] = p.m_team_scratch_size[1]; m_thread_scratch_size[1] = p.m_thread_scratch_size[1]; - m_chunk_size = p.m_chunk_size; + m_chunk_size = p.m_chunk_size; } TeamPolicyInternal(const typename traits::execution_space &, int league_size_request, int team_size_request, int /* vector_length_request */ = 1) - : m_team_scratch_size{0, 0}, m_thread_scratch_size{0, 0}, + : m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, m_chunk_size(0) { init(league_size_request, team_size_request); } @@ -591,14 +615,16 @@ public: int league_size_request, const Kokkos::AUTO_t &team_size_request, int /* vector_length_request */ = 1) - : m_team_scratch_size{0, 0}, m_thread_scratch_size{0, 0}, + : m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, m_chunk_size(0) { init(league_size_request, 1); } TeamPolicyInternal(int league_size_request, int team_size_request, int /* vector_length_request */ = 1) - : m_team_scratch_size{0, 0}, m_thread_scratch_size{0, 0}, + : m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, m_chunk_size(0) { init(league_size_request, team_size_request); } @@ -606,15 +632,16 @@ public: TeamPolicyInternal(int league_size_request, const Kokkos::AUTO_t &team_size_request, int /* vector_length_request */ = 1) - : m_team_scratch_size{0, 0}, m_thread_scratch_size{0, 0}, + : m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, m_chunk_size(0) { init(league_size_request, 1); } inline int chunk_size() const { return m_chunk_size; } - inline TeamPolicyInternal & - set_chunk_size(typename traits::index_type chunk_size_) { + inline TeamPolicyInternal &set_chunk_size( + typename traits::index_type chunk_size_) { m_chunk_size = chunk_size_; return *this; } @@ -625,22 +652,22 @@ public: return *this; } - inline TeamPolicyInternal & - set_scratch_size(const int &level, const PerThreadValue &per_thread) { + inline TeamPolicyInternal &set_scratch_size( + const int &level, const PerThreadValue &per_thread) { m_thread_scratch_size[level] = per_thread.value; return *this; } - inline TeamPolicyInternal & - set_scratch_size(const int &level, const PerTeamValue &per_team, - const PerThreadValue &per_thread) { - m_team_scratch_size[level] = per_team.value; + inline TeamPolicyInternal &set_scratch_size( + const int &level, const PerTeamValue &per_team, + const PerThreadValue &per_thread) { + m_team_scratch_size[level] = per_team.value; m_thread_scratch_size[level] = per_thread.value; return *this; } }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos namespace Kokkos { namespace Impl { @@ -648,11 +675,11 @@ namespace Impl { template class ParallelFor, Kokkos::Experimental::HPX> { -private: - using Policy = Kokkos::RangePolicy; - using WorkTag = typename Policy::work_tag; + private: + using Policy = Kokkos::RangePolicy; + using WorkTag = typename Policy::work_tag; using WorkRange = typename Policy::WorkRange; - using Member = typename Policy::member_type; + using Member = typename Policy::member_type; const FunctorType m_functor; const Policy m_policy; @@ -689,7 +716,7 @@ private: } } -public: + public: void execute() const { Kokkos::Impl::dispatch_execute_task(this); } void execute_task() const { @@ -705,25 +732,44 @@ public: #elif KOKKOS_HPX_IMPLEMENTATION == 1 using hpx::apply; - using hpx::lcos::local::counting_semaphore; + using hpx::lcos::local::latch; - counting_semaphore sem(0); - std::size_t num_tasks = 0; + const int num_tasks = + (m_policy.end() - m_policy.begin() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + latch num_tasks_remaining(num_tasks); + ChunkedRoundRobinExecutor exec(num_tasks); for (Member i_begin = m_policy.begin(); i_begin < m_policy.end(); i_begin += m_policy.chunk_size()) { - apply([this, &sem, i_begin]() { + apply(exec, [this, &num_tasks_remaining, i_begin]() { const Member i_end = (std::min)(i_begin + m_policy.chunk_size(), m_policy.end()); execute_functor_range(m_functor, i_begin, i_end); - sem.signal(1); + num_tasks_remaining.count_down(1); }); - - ++num_tasks; } - sem.wait(num_tasks); + num_tasks_remaining.wait(); + +#elif KOKKOS_HPX_IMPLEMENTATION == 2 + using hpx::parallel::for_loop_strided; + using hpx::parallel::execution::par; + using hpx::parallel::execution::static_chunk_size; + + const int num_tasks = + (m_policy.end() - m_policy.begin() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + ChunkedRoundRobinExecutor exec(num_tasks); + + for_loop_strided( + par.on(exec).with(static_chunk_size(1)), m_policy.begin(), + m_policy.end(), m_policy.chunk_size(), [this](const Member i_begin) { + const Member i_end = + (std::min)(i_begin + m_policy.chunk_size(), m_policy.end()); + execute_functor_range(m_functor, i_begin, i_end); + }); #endif } @@ -734,12 +780,12 @@ public: template class ParallelFor, Kokkos::Experimental::HPX> { -private: + private: using MDRangePolicy = Kokkos::MDRangePolicy; - using Policy = typename MDRangePolicy::impl_range_policy; - using WorkTag = typename MDRangePolicy::work_tag; - using WorkRange = typename Policy::WorkRange; - using Member = typename Policy::member_type; + using Policy = typename MDRangePolicy::impl_range_policy; + using WorkTag = typename MDRangePolicy::work_tag; + using WorkRange = typename Policy::WorkRange; + using Member = typename Policy::member_type; using iterate_type = typename Kokkos::Impl::HostIterateTile; @@ -748,7 +794,7 @@ private: const MDRangePolicy m_mdr_policy; const Policy m_policy; -public: + public: void execute() const { dispatch_execute_task(this); } inline void execute_task() const { @@ -764,47 +810,69 @@ public: #elif KOKKOS_HPX_IMPLEMENTATION == 1 using hpx::apply; - using hpx::lcos::local::counting_semaphore; + using hpx::lcos::local::latch; - counting_semaphore sem(0); - std::size_t num_tasks = 0; + const int num_tasks = + (m_policy.end() - m_policy.begin() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + latch num_tasks_remaining(num_tasks); + ChunkedRoundRobinExecutor exec(num_tasks); for (Member i_begin = m_policy.begin(); i_begin < m_policy.end(); i_begin += m_policy.chunk_size()) { - apply([this, &sem, i_begin]() { + apply(exec, [this, &num_tasks_remaining, i_begin]() { const Member i_end = (std::min)(i_begin + m_policy.chunk_size(), m_policy.end()); for (Member i = i_begin; i < i_end; ++i) { iterate_type(m_mdr_policy, m_functor)(i); } - sem.signal(1); + num_tasks_remaining.count_down(1); }); - - ++num_tasks; } - sem.wait(num_tasks); + num_tasks_remaining.wait(); + +#elif KOKKOS_HPX_IMPLEMENTATION == 2 + using hpx::parallel::for_loop_strided; + using hpx::parallel::execution::par; + using hpx::parallel::execution::static_chunk_size; + + const int num_tasks = + (m_policy.end() - m_policy.begin() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + ChunkedRoundRobinExecutor exec(num_tasks); + + for_loop_strided( + par.on(exec).with(static_chunk_size(1)), m_policy.begin(), + m_policy.end(), m_policy.chunk_size(), [this](const Member i_begin) { + const Member i_end = + (std::min)(i_begin + m_policy.chunk_size(), m_policy.end()); + for (Member i = i_begin; i < i_end; ++i) { + iterate_type(m_mdr_policy, m_functor)(i); + } + }); #endif } inline ParallelFor(const FunctorType &arg_functor, MDRangePolicy arg_policy) - : m_functor(arg_functor), m_mdr_policy(arg_policy), + : m_functor(arg_functor), + m_mdr_policy(arg_policy), m_policy(Policy(0, m_mdr_policy.m_num_tiles).set_chunk_size(1)) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos namespace Kokkos { namespace Impl { template class ParallelReduce, ReducerType, Kokkos::Experimental::HPX> { -private: - using Policy = Kokkos::RangePolicy; - using WorkTag = typename Policy::work_tag; + private: + using Policy = Kokkos::RangePolicy; + using WorkTag = typename Policy::work_tag; using WorkRange = typename Policy::WorkRange; - using Member = typename Policy::member_type; + using Member = typename Policy::member_type; using Analysis = FunctorAnalysis; using ReducerConditional = @@ -814,11 +882,11 @@ private: using WorkTagFwd = typename Kokkos::Impl::if_c::value, WorkTag, void>::type; - using ValueInit = Kokkos::Impl::FunctorValueInit; - using ValueJoin = Kokkos::Impl::FunctorValueJoin; - using ValueOps = Kokkos::Impl::FunctorValueOps; + using ValueInit = Kokkos::Impl::FunctorValueInit; + using ValueJoin = Kokkos::Impl::FunctorValueJoin; + using ValueOps = Kokkos::Impl::FunctorValueOps; using value_type = typename Analysis::value_type; - using pointer_type = typename Analysis::pointer_type; + using pointer_type = typename Analysis::pointer_type; using reference_type = typename Analysis::reference_type; const FunctorType m_functor; @@ -866,11 +934,11 @@ private: } class value_type_wrapper { - private: + private: std::size_t m_value_size; char *m_value_buffer; - public: + public: value_type_wrapper() : m_value_size(0), m_value_buffer(nullptr) {} value_type_wrapper(const std::size_t value_size) @@ -880,7 +948,7 @@ private: : m_value_size(0), m_value_buffer(nullptr) { if (this != &other) { m_value_buffer = new char[other.m_value_size]; - m_value_size = other.m_value_size; + m_value_size = other.m_value_size; std::copy(other.m_value_buffer, other.m_value_buffer + m_value_size, m_value_buffer); @@ -893,10 +961,10 @@ private: : m_value_size(0), m_value_buffer(nullptr) { if (this != &other) { m_value_buffer = other.m_value_buffer; - m_value_size = other.m_value_size; + m_value_size = other.m_value_size; other.m_value_buffer = nullptr; - other.m_value_size = 0; + other.m_value_size = 0; } } @@ -904,7 +972,7 @@ private: if (this != &other) { delete[] m_value_buffer; m_value_buffer = new char[other.m_value_size]; - m_value_size = other.m_value_size; + m_value_size = other.m_value_size; std::copy(other.m_value_buffer, other.m_value_buffer + m_value_size, m_value_buffer); @@ -917,10 +985,10 @@ private: if (this != &other) { delete[] m_value_buffer; m_value_buffer = other.m_value_buffer; - m_value_size = other.m_value_size; + m_value_size = other.m_value_size; other.m_value_buffer = nullptr; - other.m_value_size = 0; + other.m_value_size = 0; } return *this; @@ -936,26 +1004,21 @@ private: } }; -public: - void execute() const { - dispatch_execute_task(this); - } + public: + void execute() const { dispatch_execute_task(this); } inline void execute_task() const { - const int num_worker_threads = Kokkos::Experimental::HPX::concurrency(); - - std::size_t value_size = + const std::size_t value_size = Analysis::value_size(ReducerConditional::select(m_functor, m_reducer)); - using hpx::parallel::for_loop; - using hpx::parallel::execution::par; - #if KOKKOS_HPX_IMPLEMENTATION == 0 // NOTE: This version makes the most use of HPX functionality, but // requires the struct value_type_wrapper to handle different // reference_types. It is also significantly slower than the version // below due to not reusing the buffer used by other functions. + using hpx::parallel::for_loop; using hpx::parallel::reduction; + using hpx::parallel::execution::par; using hpx::parallel::execution::static_chunk_size; value_type_wrapper final_value(value_size); @@ -983,37 +1046,99 @@ public: pointer_type final_value_ptr = final_value.pointer(); #elif KOKKOS_HPX_IMPLEMENTATION == 1 + const int num_worker_threads = Kokkos::Experimental::HPX::concurrency(); + thread_buffer &buffer = Kokkos::Experimental::HPX::impl_get_buffer(); buffer.resize(num_worker_threads, value_size); - for_loop(par, 0, num_worker_threads, [this, &buffer](std::size_t t) { - ValueInit::init(ReducerConditional::select(m_functor, m_reducer), - reinterpret_cast(buffer.get(t))); - }); - using hpx::apply; - using hpx::lcos::local::counting_semaphore; + using hpx::lcos::local::latch; + + { + latch num_tasks_remaining(num_worker_threads); + ChunkedRoundRobinExecutor exec(num_worker_threads); + + for (int t = 0; t < num_worker_threads; ++t) { + apply(exec, [this, &num_tasks_remaining, &buffer, t]() { + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), + reinterpret_cast(buffer.get(t))); + + num_tasks_remaining.count_down(1); + }); + } + + num_tasks_remaining.wait(); + } - counting_semaphore sem(0); - std::size_t num_tasks = 0; + const int num_tasks = + (m_policy.end() - m_policy.begin() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + latch num_tasks_remaining(num_tasks); + ChunkedRoundRobinExecutor exec(num_tasks); for (Member i_begin = m_policy.begin(); i_begin < m_policy.end(); i_begin += m_policy.chunk_size()) { - apply([this, &buffer, &sem, i_begin]() { + apply(exec, [this, &num_tasks_remaining, &buffer, i_begin]() { reference_type update = - ValueOps::reference(reinterpret_cast( - buffer.get(Kokkos::Experimental::HPX::impl_hardware_thread_id()))); + ValueOps::reference(reinterpret_cast(buffer.get( + Kokkos::Experimental::HPX::impl_hardware_thread_id()))); const Member i_end = (std::min)(i_begin + m_policy.chunk_size(), m_policy.end()); execute_functor_range(update, i_begin, i_end); - sem.signal(1); + num_tasks_remaining.count_down(1); }); + } + + num_tasks_remaining.wait(); - ++num_tasks; + for (int i = 1; i < num_worker_threads; ++i) { + ValueJoin::join(ReducerConditional::select(m_functor, m_reducer), + reinterpret_cast(buffer.get(0)), + reinterpret_cast(buffer.get(i))); } - sem.wait(num_tasks); + pointer_type final_value_ptr = + reinterpret_cast(buffer.get(0)); + +#elif KOKKOS_HPX_IMPLEMENTATION == 2 + const int num_worker_threads = Kokkos::Experimental::HPX::concurrency(); + + thread_buffer &buffer = Kokkos::Experimental::HPX::impl_get_buffer(); + buffer.resize(num_worker_threads, value_size); + + using hpx::parallel::for_loop; + using hpx::parallel::for_loop_strided; + using hpx::parallel::execution::par; + using hpx::parallel::execution::static_chunk_size; + + { + ChunkedRoundRobinExecutor exec(num_worker_threads); + + for_loop(par.on(exec).with(static_chunk_size(1)), std::size_t(0), + num_worker_threads, [this, &buffer](const std::size_t t) { + ValueInit::init( + ReducerConditional::select(m_functor, m_reducer), + reinterpret_cast(buffer.get(t))); + }); + } + + const int num_tasks = + (m_policy.end() - m_policy.begin() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + ChunkedRoundRobinExecutor exec(num_tasks); + + for_loop_strided( + par.on(exec).with(static_chunk_size(1)), m_policy.begin(), + m_policy.end(), m_policy.chunk_size(), + [this, &buffer](const Member i_begin) { + reference_type update = + ValueOps::reference(reinterpret_cast(buffer.get( + Kokkos::Experimental::HPX::impl_hardware_thread_id()))); + const Member i_end = + (std::min)(i_begin + m_policy.chunk_size(), m_policy.end()); + execute_functor_range(update, i_begin, i_end); + }); for (int i = 1; i < num_worker_threads; ++i) { ValueJoin::join(ReducerConditional::select(m_functor, m_reducer), @@ -1045,13 +1170,17 @@ public: typename std::enable_if::value && !Kokkos::is_reducer_type::value, void *>::type = NULL) - : m_functor(arg_functor), m_policy(arg_policy), m_reducer(InvalidType()), + : m_functor(arg_functor), + m_policy(arg_policy), + m_reducer(InvalidType()), m_result_ptr(arg_view.data()), m_force_synchronous(!arg_view.impl_track().has_record()) {} inline ParallelReduce(const FunctorType &arg_functor, Policy arg_policy, const ReducerType &reducer) - : m_functor(arg_functor), m_policy(arg_policy), m_reducer(reducer), + : m_functor(arg_functor), + m_policy(arg_policy), + m_reducer(reducer), m_result_ptr(reducer.view().data()), m_force_synchronous(!reducer.view().impl_track().has_record()) {} }; @@ -1059,13 +1188,13 @@ public: template class ParallelReduce, ReducerType, Kokkos::Experimental::HPX> { -private: + private: using MDRangePolicy = Kokkos::MDRangePolicy; - using Policy = typename MDRangePolicy::impl_range_policy; - using WorkTag = typename MDRangePolicy::work_tag; - using WorkRange = typename Policy::WorkRange; - using Member = typename Policy::member_type; - using Analysis = FunctorAnalysis; using ReducerConditional = Kokkos::Impl::if_c::value, @@ -1076,9 +1205,9 @@ private: WorkTag, void>::type; using ValueInit = Kokkos::Impl::FunctorValueInit; using ValueJoin = Kokkos::Impl::FunctorValueJoin; - using ValueOps = Kokkos::Impl::FunctorValueOps; - using pointer_type = typename Analysis::pointer_type; - using value_type = typename Analysis::value_type; + using ValueOps = Kokkos::Impl::FunctorValueOps; + using pointer_type = typename Analysis::pointer_type; + using value_type = typename Analysis::value_type; using reference_type = typename Analysis::reference_type; using iterate_type = typename Kokkos::Impl::HostIterateTile(buffer.get(t))); }); -#if KOKKOS_HPX_IMPLEMENTATION == 0 - using hpx::parallel::execution::static_chunk_size; - for_loop(par.with(static_chunk_size(m_policy.chunk_size())), m_policy.begin(), m_policy.end(), [this, &buffer](const Member i) { reference_type update = ValueOps::reference( @@ -1126,17 +1252,36 @@ public: #elif KOKKOS_HPX_IMPLEMENTATION == 1 using hpx::apply; - using hpx::lcos::local::counting_semaphore; + using hpx::lcos::local::latch; + + { + latch num_tasks_remaining(num_worker_threads); + ChunkedRoundRobinExecutor exec(num_worker_threads); + + for (int t = 0; t < num_worker_threads; ++t) { + apply(exec, [this, &buffer, &num_tasks_remaining, t]() { + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), + reinterpret_cast(buffer.get(t))); + + num_tasks_remaining.count_down(1); + }); + } - counting_semaphore sem(0); - std::size_t num_tasks = 0; + num_tasks_remaining.wait(); + } + + const int num_tasks = + (m_policy.end() - m_policy.begin() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + latch num_tasks_remaining(num_tasks); + ChunkedRoundRobinExecutor exec(num_tasks); for (Member i_begin = m_policy.begin(); i_begin < m_policy.end(); i_begin += m_policy.chunk_size()) { - apply([this, &buffer, &sem, i_begin]() { + apply(exec, [this, &num_tasks_remaining, &buffer, i_begin]() { reference_type update = - ValueOps::reference(reinterpret_cast( - buffer.get(Kokkos::Experimental::HPX::impl_hardware_thread_id()))); + ValueOps::reference(reinterpret_cast(buffer.get( + Kokkos::Experimental::HPX::impl_hardware_thread_id()))); const Member i_end = (std::min)(i_begin + m_policy.chunk_size(), m_policy.end()); @@ -1144,13 +1289,48 @@ public: iterate_type(m_mdr_policy, m_functor, update)(i); } - sem.signal(1); + num_tasks_remaining.count_down(1); }); + } + + num_tasks_remaining.wait(); + +#elif KOKKOS_HPX_IMPLEMENTATION == 2 + using hpx::parallel::for_loop; + using hpx::parallel::for_loop_strided; + using hpx::parallel::execution::par; + using hpx::parallel::execution::static_chunk_size; - ++num_tasks; + { + ChunkedRoundRobinExecutor exec(num_worker_threads); + + for_loop(par.on(exec).with(static_chunk_size(1)), std::size_t(0), + num_worker_threads, [this, &buffer](const std::size_t t) { + ValueInit::init( + ReducerConditional::select(m_functor, m_reducer), + reinterpret_cast(buffer.get(t))); + }); } - sem.wait(num_tasks); + const int num_tasks = + (m_policy.end() - m_policy.begin() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + ChunkedRoundRobinExecutor exec(num_tasks); + + for_loop_strided( + par.on(exec).with(static_chunk_size(1)), m_policy.begin(), + m_policy.end(), m_policy.chunk_size(), + [this, &buffer](const Member i_begin) { + reference_type update = + ValueOps::reference(reinterpret_cast(buffer.get( + Kokkos::Experimental::HPX::impl_hardware_thread_id()))); + const Member i_end = + (std::min)(i_begin + m_policy.chunk_size(), m_policy.end()); + + for (Member i = i_begin; i < i_end; ++i) { + iterate_type(m_mdr_policy, m_functor, update)(i); + } + }); #endif for (int i = 1; i < num_worker_threads; ++i) { @@ -1180,20 +1360,24 @@ public: typename std::enable_if::value && !Kokkos::is_reducer_type::value, void *>::type = NULL) - : m_functor(arg_functor), m_mdr_policy(arg_policy), + : m_functor(arg_functor), + m_mdr_policy(arg_policy), m_policy(Policy(0, m_mdr_policy.m_num_tiles).set_chunk_size(1)), - m_reducer(InvalidType()), m_result_ptr(arg_view.data()), + m_reducer(InvalidType()), + m_result_ptr(arg_view.data()), m_force_synchronous(!arg_view.impl_track().has_record()) {} inline ParallelReduce(const FunctorType &arg_functor, MDRangePolicy arg_policy, const ReducerType &reducer) - : m_functor(arg_functor), m_mdr_policy(arg_policy), + : m_functor(arg_functor), + m_mdr_policy(arg_policy), m_policy(Policy(0, m_mdr_policy.m_num_tiles).set_chunk_size(1)), - m_reducer(reducer), m_result_ptr(reducer.view().data()), + m_reducer(reducer), + m_result_ptr(reducer.view().data()), m_force_synchronous(!reducer.view().impl_track().has_record()) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos namespace Kokkos { namespace Impl { @@ -1201,19 +1385,19 @@ namespace Impl { template class ParallelScan, Kokkos::Experimental::HPX> { -private: - using Policy = Kokkos::RangePolicy; - using WorkTag = typename Policy::work_tag; + private: + using Policy = Kokkos::RangePolicy; + using WorkTag = typename Policy::work_tag; using WorkRange = typename Policy::WorkRange; - using Member = typename Policy::member_type; + using Member = typename Policy::member_type; using Analysis = FunctorAnalysis; - using ValueInit = Kokkos::Impl::FunctorValueInit; - using ValueJoin = Kokkos::Impl::FunctorValueJoin; - using ValueOps = Kokkos::Impl::FunctorValueOps; - using pointer_type = typename Analysis::pointer_type; + using ValueInit = Kokkos::Impl::FunctorValueInit; + using ValueJoin = Kokkos::Impl::FunctorValueJoin; + using ValueOps = Kokkos::Impl::FunctorValueOps; + using pointer_type = typename Analysis::pointer_type; using reference_type = typename Analysis::reference_type; - using value_type = typename Analysis::value_type; + using value_type = typename Analysis::value_type; const FunctorType m_functor; const Policy m_policy; @@ -1241,64 +1425,70 @@ private: } } -public: + public: void execute() const { dispatch_execute_task(this); } inline void execute_task() const { const int num_worker_threads = Kokkos::Experimental::HPX::concurrency(); - const int value_count = Analysis::value_count(m_functor); + const int value_count = Analysis::value_count(m_functor); const std::size_t value_size = Analysis::value_size(m_functor); thread_buffer &buffer = Kokkos::Experimental::HPX::impl_get_buffer(); buffer.resize(num_worker_threads, 2 * value_size); + using hpx::apply; using hpx::lcos::local::barrier; - using hpx::parallel::for_loop; - using hpx::parallel::execution::par; - using hpx::parallel::execution::static_chunk_size; + using hpx::lcos::local::latch; barrier bar(num_worker_threads); + latch num_tasks_remaining(num_worker_threads); + ChunkedRoundRobinExecutor exec(num_worker_threads); + + for (int t = 0; t < num_worker_threads; ++t) { + apply(exec, [this, &bar, &buffer, &num_tasks_remaining, + num_worker_threads, value_count, value_size, t]() { + reference_type update_sum = ValueInit::init( + m_functor, reinterpret_cast(buffer.get(t))); + + const WorkRange range(m_policy, t, num_worker_threads); + execute_functor_range(m_functor, range.begin(), range.end(), + update_sum, false); + + bar.wait(); + + if (t == 0) { + ValueInit::init(m_functor, reinterpret_cast( + buffer.get(0) + value_size)); + + for (int i = 1; i < num_worker_threads; ++i) { + pointer_type ptr_1_prev = + reinterpret_cast(buffer.get(i - 1)); + pointer_type ptr_2_prev = + reinterpret_cast(buffer.get(i - 1) + value_size); + pointer_type ptr_2 = + reinterpret_cast(buffer.get(i) + value_size); + + for (int j = 0; j < value_count; ++j) { + ptr_2[j] = ptr_2_prev[j]; + } + + ValueJoin::join(m_functor, ptr_2, ptr_1_prev); + } + } - for_loop(par.with(static_chunk_size(1)), 0, num_worker_threads, - [this, &buffer, &bar, num_worker_threads, value_count, - value_size](std::size_t const t) { - reference_type update_sum = ValueInit::init( - m_functor, reinterpret_cast(buffer.get(t))); - - const WorkRange range(m_policy, t, num_worker_threads); - execute_functor_range(m_functor, range.begin(), - range.end(), update_sum, false); - - bar.wait(); - - if (t == 0) { - ValueInit::init(m_functor, reinterpret_cast( - buffer.get(0) + value_size)); - - for (int i = 1; i < num_worker_threads; ++i) { - pointer_type ptr_1_prev = - reinterpret_cast(buffer.get(i - 1)); - pointer_type ptr_2_prev = reinterpret_cast( - buffer.get(i - 1) + value_size); - pointer_type ptr_2 = reinterpret_cast( - buffer.get(i) + value_size); - - for (int j = 0; j < value_count; ++j) { - ptr_2[j] = ptr_2_prev[j]; - } + bar.wait(); - ValueJoin::join(m_functor, ptr_2, ptr_1_prev); - } - } + reference_type update_base = ValueOps::reference( + reinterpret_cast(buffer.get(t) + value_size)); - bar.wait(); + execute_functor_range(m_functor, range.begin(), range.end(), + update_base, true); - reference_type update_base = ValueOps::reference( - reinterpret_cast(buffer.get(t) + value_size)); + num_tasks_remaining.count_down(1); + }); + } - execute_functor_range(m_functor, range.begin(), - range.end(), update_base, true); - }); + num_tasks_remaining.wait(); } inline ParallelScan(const FunctorType &arg_functor, const Policy &arg_policy) @@ -1308,19 +1498,19 @@ public: template class ParallelScanWithTotal, ReturnType, Kokkos::Experimental::HPX> { -private: - using Policy = Kokkos::RangePolicy; - using WorkTag = typename Policy::work_tag; + private: + using Policy = Kokkos::RangePolicy; + using WorkTag = typename Policy::work_tag; using WorkRange = typename Policy::WorkRange; - using Member = typename Policy::member_type; + using Member = typename Policy::member_type; using Analysis = FunctorAnalysis; - using ValueInit = Kokkos::Impl::FunctorValueInit; - using ValueJoin = Kokkos::Impl::FunctorValueJoin; - using ValueOps = Kokkos::Impl::FunctorValueOps; - using pointer_type = typename Analysis::pointer_type; + using ValueInit = Kokkos::Impl::FunctorValueInit; + using ValueJoin = Kokkos::Impl::FunctorValueJoin; + using ValueOps = Kokkos::Impl::FunctorValueOps; + using pointer_type = typename Analysis::pointer_type; using reference_type = typename Analysis::reference_type; - using value_type = typename Analysis::value_type; + using value_type = typename Analysis::value_type; const FunctorType m_functor; const Policy m_policy; @@ -1349,88 +1539,95 @@ private: } } -public: + public: void execute() const { dispatch_execute_task(this); } inline void execute_task() const { const int num_worker_threads = Kokkos::Experimental::HPX::concurrency(); - const int value_count = Analysis::value_count(m_functor); + const int value_count = Analysis::value_count(m_functor); const std::size_t value_size = Analysis::value_size(m_functor); thread_buffer &buffer = Kokkos::Experimental::HPX::impl_get_buffer(); buffer.resize(num_worker_threads, 2 * value_size); + using hpx::apply; using hpx::lcos::local::barrier; - using hpx::parallel::for_loop; - using hpx::parallel::execution::par; - using hpx::parallel::execution::static_chunk_size; + using hpx::lcos::local::latch; barrier bar(num_worker_threads); + latch num_tasks_remaining(num_worker_threads); + ChunkedRoundRobinExecutor exec(num_worker_threads); + + for (int t = 0; t < num_worker_threads; ++t) { + apply(exec, [this, &bar, &buffer, &num_tasks_remaining, + num_worker_threads, value_count, value_size, t]() { + reference_type update_sum = ValueInit::init( + m_functor, reinterpret_cast(buffer.get(t))); + + const WorkRange range(m_policy, t, num_worker_threads); + execute_functor_range(m_functor, range.begin(), range.end(), + update_sum, false); + + bar.wait(); + + if (t == 0) { + ValueInit::init(m_functor, reinterpret_cast( + buffer.get(0) + value_size)); + + for (int i = 1; i < num_worker_threads; ++i) { + pointer_type ptr_1_prev = + reinterpret_cast(buffer.get(i - 1)); + pointer_type ptr_2_prev = + reinterpret_cast(buffer.get(i - 1) + value_size); + pointer_type ptr_2 = + reinterpret_cast(buffer.get(i) + value_size); + + for (int j = 0; j < value_count; ++j) { + ptr_2[j] = ptr_2_prev[j]; + } + + ValueJoin::join(m_functor, ptr_2, ptr_1_prev); + } + } - for_loop(par.with(static_chunk_size(1)), 0, num_worker_threads, - [this, &buffer, &bar, num_worker_threads, value_count, - value_size](std::size_t const t) { - reference_type update_sum = ValueInit::init( - m_functor, reinterpret_cast(buffer.get(t))); - - const WorkRange range(m_policy, t, num_worker_threads); - execute_functor_range(m_functor, range.begin(), - range.end(), update_sum, false); - - bar.wait(); - - if (t == 0) { - ValueInit::init(m_functor, reinterpret_cast( - buffer.get(0) + value_size)); - - for (int i = 1; i < num_worker_threads; ++i) { - pointer_type ptr_1_prev = - reinterpret_cast(buffer.get(i - 1)); - pointer_type ptr_2_prev = reinterpret_cast( - buffer.get(i - 1) + value_size); - pointer_type ptr_2 = reinterpret_cast( - buffer.get(i) + value_size); - - for (int j = 0; j < value_count; ++j) { - ptr_2[j] = ptr_2_prev[j]; - } + bar.wait(); - ValueJoin::join(m_functor, ptr_2, ptr_1_prev); - } - } + reference_type update_base = ValueOps::reference( + reinterpret_cast(buffer.get(t) + value_size)); - bar.wait(); + execute_functor_range(m_functor, range.begin(), range.end(), + update_base, true); - reference_type update_base = ValueOps::reference( - reinterpret_cast(buffer.get(t) + value_size)); + if (t == num_worker_threads - 1) { + m_returnvalue = update_base; + } - execute_functor_range(m_functor, range.begin(), - range.end(), update_base, true); + num_tasks_remaining.count_down(1); + }); + } - if (t == std::size_t(num_worker_threads - 1)) { - m_returnvalue = update_base; - } - }); + num_tasks_remaining.wait(); } inline ParallelScanWithTotal(const FunctorType &arg_functor, const Policy &arg_policy, ReturnType &arg_returnvalue) - : m_functor(arg_functor), m_policy(arg_policy), + : m_functor(arg_functor), + m_policy(arg_policy), m_returnvalue(arg_returnvalue) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos namespace Kokkos { namespace Impl { template class ParallelFor, Kokkos::Experimental::HPX> { -private: - using Policy = TeamPolicyInternal; + private: + using Policy = TeamPolicyInternal; using WorkTag = typename Policy::work_tag; - using Member = typename Policy::member_type; + using Member = typename Policy::member_type; using memory_space = Kokkos::HostSpace; const FunctorType m_functor; @@ -1485,7 +1682,7 @@ private: } } -public: + public: void execute() const { dispatch_execute_task(this); } inline void execute_task() const { @@ -1499,42 +1696,66 @@ public: using hpx::parallel::execution::par; using hpx::parallel::execution::static_chunk_size; - for_loop(par.with(static_chunk_size(m_policy.chunk_size())), 0, - m_policy.league_size(), [this, &buffer](const int league_rank) { - execute_functor( - m_functor, m_policy, league_rank, - buffer.get(Kokkos::Experimental::HPX::impl_hardware_thread_id()), - m_shared); - }); + for_loop( + par.with(static_chunk_size(m_policy.chunk_size())), 0, + m_policy.league_size(), [this, &buffer](const int league_rank) { + execute_functor( + m_functor, m_policy, league_rank, + buffer.get(Kokkos::Experimental::HPX::impl_hardware_thread_id()), + m_shared); + }); #elif KOKKOS_HPX_IMPLEMENTATION == 1 using hpx::apply; - using hpx::lcos::local::counting_semaphore; + using hpx::lcos::local::latch; - counting_semaphore sem(0); - std::size_t num_tasks = 0; + const int num_tasks = (m_policy.league_size() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + latch num_tasks_remaining(num_tasks); + ChunkedRoundRobinExecutor exec(num_tasks); for (int league_rank_begin = 0; league_rank_begin < m_policy.league_size(); league_rank_begin += m_policy.chunk_size()) { - apply([this, &buffer, &sem, league_rank_begin]() { + apply(exec, [this, &buffer, &num_tasks_remaining, league_rank_begin]() { const int league_rank_end = (std::min)( league_rank_begin + m_policy.chunk_size(), m_policy.league_size()); execute_functor_range( m_functor, m_policy, league_rank_begin, league_rank_end, - buffer.get(Kokkos::Experimental::HPX::impl_hardware_thread_id()), m_shared); + buffer.get(Kokkos::Experimental::HPX::impl_hardware_thread_id()), + m_shared); - sem.signal(1); + num_tasks_remaining.count_down(1); }); - - ++num_tasks; } - sem.wait(num_tasks); + num_tasks_remaining.wait(); + +#elif KOKKOS_HPX_IMPLEMENTATION == 2 + using hpx::parallel::for_loop_strided; + using hpx::parallel::execution::par; + using hpx::parallel::execution::static_chunk_size; + + const int num_tasks = (m_policy.league_size() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + ChunkedRoundRobinExecutor exec(num_tasks); + + for_loop_strided( + par.on(exec).with(static_chunk_size(1)), 0, m_policy.league_size(), + m_policy.chunk_size(), [this, &buffer](const int league_rank_begin) { + const int league_rank_end = + (std::min)(league_rank_begin + m_policy.chunk_size(), + m_policy.league_size()); + execute_functor_range( + m_functor, m_policy, league_rank_begin, league_rank_end, + buffer.get(Kokkos::Experimental::HPX::impl_hardware_thread_id()), + m_shared); + }); #endif } ParallelFor(const FunctorType &arg_functor, const Policy &arg_policy) - : m_functor(arg_functor), m_policy(arg_policy), + : m_functor(arg_functor), + m_policy(arg_policy), m_league(arg_policy.league_size()), m_shared(arg_policy.scratch_size(0) + arg_policy.scratch_size(1) + FunctorTeamShmemSize::value( @@ -1544,11 +1765,11 @@ public: template class ParallelReduce, ReducerType, Kokkos::Experimental::HPX> { -private: + private: using Policy = TeamPolicyInternal; using Analysis = FunctorAnalysis; - using Member = typename Policy::member_type; + using Member = typename Policy::member_type; using WorkTag = typename Policy::work_tag; using ReducerConditional = Kokkos::Impl::if_c::value, @@ -1559,10 +1780,10 @@ private: WorkTag, void>::type; using ValueInit = Kokkos::Impl::FunctorValueInit; using ValueJoin = Kokkos::Impl::FunctorValueJoin; - using ValueOps = Kokkos::Impl::FunctorValueOps; - using pointer_type = typename Analysis::pointer_type; + using ValueOps = Kokkos::Impl::FunctorValueOps; + using pointer_type = typename Analysis::pointer_type; using reference_type = typename Analysis::reference_type; - using value_type = typename Analysis::value_type; + using value_type = typename Analysis::value_type; const FunctorType m_functor; const int m_league; @@ -1628,10 +1849,8 @@ private: } } -public: - void execute() const { - dispatch_execute_task(this); - } + public: + void execute() const { dispatch_execute_task(this); } inline void execute_task() const { const int num_worker_threads = Kokkos::Experimental::HPX::concurrency(); @@ -1641,15 +1860,15 @@ public: thread_buffer &buffer = Kokkos::Experimental::HPX::impl_get_buffer(); buffer.resize(num_worker_threads, value_size + m_shared); +#if KOKKOS_HPX_IMPLEMENTATION == 0 using hpx::parallel::for_loop; using hpx::parallel::execution::par; - for_loop(par, 0, num_worker_threads, [this, &buffer](std::size_t t) { + for_loop(par, 0, num_worker_threads, [this, &buffer](const std::size_t t) { ValueInit::init(ReducerConditional::select(m_functor, m_reducer), reinterpret_cast(buffer.get(t))); }); -#if KOKKOS_HPX_IMPLEMENTATION == 0 using hpx::parallel::execution::static_chunk_size; hpx::parallel::for_loop( @@ -1667,14 +1886,33 @@ public: #elif KOKKOS_HPX_IMPLEMENTATION == 1 using hpx::apply; - using hpx::lcos::local::counting_semaphore; + using hpx::lcos::local::latch; - counting_semaphore sem(0); - std::size_t num_tasks = 0; + { + latch num_tasks_remaining(num_worker_threads); + ChunkedRoundRobinExecutor exec(num_worker_threads); + + for (int t = 0; t < num_worker_threads; ++t) { + apply(exec, [this, &buffer, &num_tasks_remaining, t]() { + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), + reinterpret_cast(buffer.get(t))); + + num_tasks_remaining.count_down(1); + }); + } + + num_tasks_remaining.wait(); + } + + const int num_tasks = (m_policy.league_size() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + latch num_tasks_remaining(num_tasks); + ChunkedRoundRobinExecutor exec(num_tasks); for (int league_rank_begin = 0; league_rank_begin < m_policy.league_size(); league_rank_begin += m_policy.chunk_size()) { - apply([this, &buffer, &sem, league_rank_begin, value_size]() { + apply(exec, [this, &buffer, &num_tasks_remaining, league_rank_begin, + value_size]() { std::size_t t = Kokkos::Experimental::HPX::impl_hardware_thread_id(); reference_type update = ValueOps::reference(reinterpret_cast(buffer.get(t))); @@ -1684,13 +1922,47 @@ public: m_functor, m_policy, league_rank_begin, league_rank_end, buffer.get(t) + value_size, m_shared, update); - sem.signal(1); + num_tasks_remaining.count_down(1); }); + } + + num_tasks_remaining.wait(); - ++num_tasks; +#elif KOKKOS_HPX_IMPLEMENTATION == 2 + using hpx::parallel::for_loop; + using hpx::parallel::for_loop_strided; + using hpx::parallel::execution::par; + using hpx::parallel::execution::static_chunk_size; + + { + ChunkedRoundRobinExecutor exec(num_worker_threads); + + for_loop(par.on(exec).with(static_chunk_size(1)), 0, num_worker_threads, + [this, &buffer](std::size_t const t) { + ValueInit::init( + ReducerConditional::select(m_functor, m_reducer), + reinterpret_cast(buffer.get(t))); + }); } - sem.wait(num_tasks); + const int num_tasks = (m_policy.league_size() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + ChunkedRoundRobinExecutor exec(num_tasks); + + for_loop_strided( + par.on(exec).with(static_chunk_size(1)), 0, m_policy.league_size(), + m_policy.chunk_size(), + [this, &buffer, value_size](int const league_rank_begin) { + std::size_t t = Kokkos::Experimental::HPX::impl_hardware_thread_id(); + reference_type update = ValueOps::reference( + reinterpret_cast(buffer.get(t))); + const int league_rank_end = + (std::min)(league_rank_begin + m_policy.chunk_size(), + m_policy.league_size()); + execute_functor_range( + m_functor, m_policy, league_rank_begin, league_rank_end, + buffer.get(t) + value_size, m_shared, update); + }); #endif const pointer_type ptr = reinterpret_cast(buffer.get(0)); @@ -1719,8 +1991,10 @@ public: typename std::enable_if::value && !Kokkos::is_reducer_type::value, void *>::type = NULL) - : m_functor(arg_functor), m_league(arg_policy.league_size()), - m_policy(arg_policy), m_reducer(InvalidType()), + : m_functor(arg_functor), + m_league(arg_policy.league_size()), + m_policy(arg_policy), + m_reducer(InvalidType()), m_result_ptr(arg_result.data()), m_shared(arg_policy.scratch_size(0) + arg_policy.scratch_size(1) + FunctorTeamShmemSize::value( @@ -1729,16 +2003,18 @@ public: inline ParallelReduce(const FunctorType &arg_functor, Policy arg_policy, const ReducerType &reducer) - : m_functor(arg_functor), m_league(arg_policy.league_size()), - m_policy(arg_policy), m_reducer(reducer), + : m_functor(arg_functor), + m_league(arg_policy.league_size()), + m_policy(arg_policy), + m_reducer(reducer), m_result_ptr(reducer.view().data()), m_shared(arg_policy.scratch_size(0) + arg_policy.scratch_size(1) + FunctorTeamShmemSize::value( arg_functor, arg_policy.team_size())), m_force_synchronous(!reducer.view().impl_track().has_record()) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos namespace Kokkos { @@ -1796,14 +2072,14 @@ KOKKOS_INLINE_FUNCTION } KOKKOS_INLINE_FUNCTION -Impl::ThreadSingleStruct -PerTeam(const Impl::HPXTeamMember &thread) { +Impl::ThreadSingleStruct PerTeam( + const Impl::HPXTeamMember &thread) { return Impl::ThreadSingleStruct(thread); } KOKKOS_INLINE_FUNCTION -Impl::VectorSingleStruct -PerThread(const Impl::HPXTeamMember &thread) { +Impl::VectorSingleStruct PerThread( + const Impl::HPXTeamMember &thread) { return Impl::VectorSingleStruct(thread); } @@ -1950,7 +2226,7 @@ KOKKOS_INLINE_FUNCTION void parallel_scan( &loop_boundaries, const FunctorType &lambda) { using ValueTraits = Kokkos::Impl::FunctorValueTraits; - using value_type = typename ValueTraits::value_type; + using value_type = typename ValueTraits::value_type; value_type scan_val = value_type(); @@ -1964,34 +2240,34 @@ KOKKOS_INLINE_FUNCTION void parallel_scan( } template -KOKKOS_INLINE_FUNCTION void -single(const Impl::VectorSingleStruct &single_struct, - const FunctorType &lambda) { +KOKKOS_INLINE_FUNCTION void single( + const Impl::VectorSingleStruct &single_struct, + const FunctorType &lambda) { lambda(); } template -KOKKOS_INLINE_FUNCTION void -single(const Impl::ThreadSingleStruct &single_struct, - const FunctorType &lambda) { +KOKKOS_INLINE_FUNCTION void single( + const Impl::ThreadSingleStruct &single_struct, + const FunctorType &lambda) { lambda(); } template -KOKKOS_INLINE_FUNCTION void -single(const Impl::VectorSingleStruct &single_struct, - const FunctorType &lambda, ValueType &val) { +KOKKOS_INLINE_FUNCTION void single( + const Impl::VectorSingleStruct &single_struct, + const FunctorType &lambda, ValueType &val) { lambda(val); } template -KOKKOS_INLINE_FUNCTION void -single(const Impl::ThreadSingleStruct &single_struct, - const FunctorType &lambda, ValueType &val) { +KOKKOS_INLINE_FUNCTION void single( + const Impl::ThreadSingleStruct &single_struct, + const FunctorType &lambda, ValueType &val) { lambda(val); } -} // namespace Kokkos +} // namespace Kokkos #include diff --git a/lib/kokkos/core/src/Kokkos_HostSpace.hpp b/lib/kokkos/core/src/Kokkos_HostSpace.hpp index 06ccf63987..974ca1e5ef 100644 --- a/lib/kokkos/core/src/Kokkos_HostSpace.hpp +++ b/lib/kokkos/core/src/Kokkos_HostSpace.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -73,10 +74,10 @@ namespace Impl { /// This function initializes the locks to zero (unset). void init_lock_array_host_space(); -/// \brief Acquire a lock for the address +/// \brief Aquire a lock for the address /// -/// This function tries to acquire the lock for the hash value derived -/// from the provided ptr. If the lock is successfully acquired the +/// This function tries to aquire the lock for the hash value derived +/// from the provided ptr. If the lock is successfully aquired the /// function returns true. Otherwise it returns false. bool lock_address_host_space(void* ptr); @@ -84,13 +85,13 @@ bool lock_address_host_space(void* ptr); /// /// This function releases the lock for the hash value derived /// from the provided ptr. This function should only be called -/// after previously successfully acquiring a lock with +/// after previously successfully aquiring a lock with /// lock_address. -void unlock_address_host_space( void* ptr ); +void unlock_address_host_space(void* ptr); -} // namespace Impl +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos namespace Kokkos { @@ -100,10 +101,10 @@ namespace Kokkos { /// HostSpace is a memory space that governs host memory. "Host" /// memory means the usual CPU-accessible memory. class HostSpace { -public: + public: //! Tag this class as a kokkos memory space - typedef HostSpace memory_space; - typedef size_t size_type; + typedef HostSpace memory_space; + typedef size_t size_type; /// \typedef execution_space /// \brief Default execution space for this memory space. @@ -111,63 +112,68 @@ public: /// Every memory space has a default execution space. This is /// useful for things like initializing a View (which happens in /// parallel using the View's default execution space). -#if defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP ) - typedef Kokkos::OpenMP execution_space; -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS ) - typedef Kokkos::Threads execution_space; -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX ) +#if defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP) + typedef Kokkos::OpenMP execution_space; +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS) + typedef Kokkos::Threads execution_space; +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX) typedef Kokkos::Experimental::HPX execution_space; //#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_QTHREADS ) // typedef Kokkos::Qthreads execution_space; -#elif defined( KOKKOS_ENABLE_OPENMP ) - typedef Kokkos::OpenMP execution_space; -#elif defined( KOKKOS_ENABLE_THREADS ) - typedef Kokkos::Threads execution_space; +#elif defined(KOKKOS_ENABLE_OPENMP) + typedef Kokkos::OpenMP execution_space; +#elif defined(KOKKOS_ENABLE_THREADS) + typedef Kokkos::Threads execution_space; //#elif defined( KOKKOS_ENABLE_QTHREADS ) // typedef Kokkos::Qthreads execution_space; -#elif defined( KOKKOS_ENABLE_HPX ) +#elif defined(KOKKOS_ENABLE_HPX) typedef Kokkos::Experimental::HPX execution_space; -#elif defined( KOKKOS_ENABLE_SERIAL ) - typedef Kokkos::Serial execution_space; +#elif defined(KOKKOS_ENABLE_SERIAL) + typedef Kokkos::Serial execution_space; #else -# error "At least one of the following host execution spaces must be defined: Kokkos::OpenMP, Kokkos::Threads, Kokkos::Qthreads, or Kokkos::Serial. You might be seeing this message if you disabled the Kokkos::Serial device explicitly using the Kokkos_ENABLE_Serial:BOOL=OFF CMake option, but did not enable any of the other host execution space devices." +#error \ + "At least one of the following host execution spaces must be defined: Kokkos::OpenMP, Kokkos::Threads, Kokkos::Qthreads, or Kokkos::Serial. You might be seeing this message if you disabled the Kokkos::Serial device explicitly using the Kokkos_ENABLE_Serial:BOOL=OFF CMake option, but did not enable any of the other host execution space devices." #endif //! This memory space preferred device_type - typedef Kokkos::Device< execution_space, memory_space > device_type; + typedef Kokkos::Device device_type; /**\brief Default memory space instance */ HostSpace(); - HostSpace( HostSpace && rhs ) = default; - HostSpace( const HostSpace & rhs ) = default; - HostSpace & operator = ( HostSpace && ) = default; - HostSpace & operator = ( const HostSpace & ) = default; - ~HostSpace() = default; + HostSpace(HostSpace&& rhs) = default; + HostSpace(const HostSpace& rhs) = default; + HostSpace& operator=(HostSpace&&) = default; + HostSpace& operator=(const HostSpace&) = default; + ~HostSpace() = default; - /**\brief Non-default memory space instance to choose allocation mechansim, if available */ + /**\brief Non-default memory space instance to choose allocation mechansim, + * if available */ - enum AllocationMechanism { STD_MALLOC, POSIX_MEMALIGN, POSIX_MMAP, INTEL_MM_ALLOC }; + enum AllocationMechanism { + STD_MALLOC, + POSIX_MEMALIGN, + POSIX_MMAP, + INTEL_MM_ALLOC + }; - explicit - HostSpace( const AllocationMechanism & ); + explicit HostSpace(const AllocationMechanism&); /**\brief Allocate untracked memory in the space */ - void * allocate( const size_t arg_alloc_size ) const; + void* allocate(const size_t arg_alloc_size) const; /**\brief Deallocate untracked memory in the space */ - void deallocate( void * const arg_alloc_ptr - , const size_t arg_alloc_size ) const; + void deallocate(void* const arg_alloc_ptr, const size_t arg_alloc_size) const; /**\brief Return Name of the MemorySpace */ static constexpr const char* name() { return m_name; } -private: - AllocationMechanism m_alloc_mech; + private: + AllocationMechanism m_alloc_mech; static constexpr const char* m_name = "Host"; - friend class Kokkos::Impl::SharedAllocationRecord< Kokkos::HostSpace, void >; + friend class Kokkos::Impl::SharedAllocationRecord; }; -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- @@ -175,38 +181,45 @@ namespace Kokkos { namespace Impl { -static_assert( Kokkos::Impl::MemorySpaceAccess< Kokkos::HostSpace, Kokkos::HostSpace >::assignable, "" ); +static_assert(Kokkos::Impl::MemorySpaceAccess::assignable, + ""); -template< typename S > +template struct HostMirror { -private: + private: // If input execution space can access HostSpace then keep it. // Example: Kokkos::OpenMP can access, Kokkos::Cuda cannot - enum { keep_exe = Kokkos::Impl::MemorySpaceAccess - < typename S::execution_space::memory_space, Kokkos::HostSpace >::accessible }; + enum { + keep_exe = Kokkos::Impl::MemorySpaceAccess< + typename S::execution_space::memory_space, + Kokkos::HostSpace>::accessible + }; // If HostSpace can access memory space then keep it. // Example: Cannot access Kokkos::CudaSpace, can access Kokkos::CudaUVMSpace - enum { keep_mem = Kokkos::Impl::MemorySpaceAccess - < Kokkos::HostSpace, typename S::memory_space >::accessible }; - -public: - - typedef typename std::conditional - < keep_exe && keep_mem /* Can keep whole space */ - , S - , typename std::conditional - < keep_mem /* Can keep memory space, use default Host execution space */ - , Kokkos::Device< Kokkos::HostSpace::execution_space - , typename S::memory_space > - , Kokkos::HostSpace - >::type - >::type Space; + enum { + keep_mem = + Kokkos::Impl::MemorySpaceAccess::accessible + }; + + public: + typedef typename std::conditional< + keep_exe && keep_mem /* Can keep whole space */ + , + S, + typename std::conditional< + keep_mem /* Can keep memory space, use default Host execution space */ + , + Kokkos::Device, + Kokkos::HostSpace>::type>::type Space; }; -} // namespace Impl +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- @@ -214,19 +227,18 @@ namespace Kokkos { namespace Impl { -template<> -class SharedAllocationRecord< Kokkos::HostSpace, void > - : public SharedAllocationRecord< void, void > -{ -private: +template <> +class SharedAllocationRecord + : public SharedAllocationRecord { + private: friend Kokkos::HostSpace; - typedef SharedAllocationRecord< void, void > RecordBase; + typedef SharedAllocationRecord RecordBase; - SharedAllocationRecord( const SharedAllocationRecord & ) = delete; - SharedAllocationRecord & operator = ( const SharedAllocationRecord & ) = delete; + SharedAllocationRecord(const SharedAllocationRecord&) = delete; + SharedAllocationRecord& operator=(const SharedAllocationRecord&) = delete; - static void deallocate( RecordBase * ); + static void deallocate(RecordBase*); #ifdef KOKKOS_DEBUG /**\brief Root record for tracked allocations from this HostSpace instance */ @@ -235,61 +247,51 @@ private: const Kokkos::HostSpace m_space; -protected: + protected: ~SharedAllocationRecord(); SharedAllocationRecord() = default; - SharedAllocationRecord( const Kokkos::HostSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - , const RecordBase::function_type arg_dealloc = & deallocate - ); + SharedAllocationRecord( + const Kokkos::HostSpace& arg_space, const std::string& arg_label, + const size_t arg_alloc_size, + const RecordBase::function_type arg_dealloc = &deallocate); -public: - - inline - std::string get_label() const - { - return std::string( RecordBase::head()->m_label ); + public: + inline std::string get_label() const { + return std::string(RecordBase::head()->m_label); } - KOKKOS_INLINE_FUNCTION static - SharedAllocationRecord * allocate( const Kokkos::HostSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - ) - { -#if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) - return new SharedAllocationRecord( arg_space, arg_label, arg_alloc_size ); + KOKKOS_INLINE_FUNCTION static SharedAllocationRecord* allocate( + const Kokkos::HostSpace& arg_space, const std::string& arg_label, + const size_t arg_alloc_size) { +#if defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST) + return new SharedAllocationRecord(arg_space, arg_label, arg_alloc_size); #else - return (SharedAllocationRecord *) 0; + return (SharedAllocationRecord*)0; #endif } - /**\brief Allocate tracked memory in the space */ - static - void * allocate_tracked( const Kokkos::HostSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size ); + static void* allocate_tracked(const Kokkos::HostSpace& arg_space, + const std::string& arg_label, + const size_t arg_alloc_size); /**\brief Reallocate tracked memory in the space */ - static - void * reallocate_tracked( void * const arg_alloc_ptr - , const size_t arg_alloc_size ); + static void* reallocate_tracked(void* const arg_alloc_ptr, + const size_t arg_alloc_size); /**\brief Deallocate tracked memory in the space */ - static - void deallocate_tracked( void * const arg_alloc_ptr ); + static void deallocate_tracked(void* const arg_alloc_ptr); - static SharedAllocationRecord * get_record( void * arg_alloc_ptr ); + static SharedAllocationRecord* get_record(void* arg_alloc_ptr); - static void print_records( std::ostream &, const Kokkos::HostSpace &, bool detail = false ); + static void print_records(std::ostream&, const Kokkos::HostSpace&, + bool detail = false); }; -} // namespace Impl +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- @@ -297,24 +299,21 @@ namespace Kokkos { namespace Impl { -#define PAR_DEEP_COPY_USE_MEMCPY - -template< class ExecutionSpace > -struct DeepCopy< HostSpace, HostSpace, ExecutionSpace > { - DeepCopy( void * dst, const void * src, size_t n ) { - hostspace_parallel_deepcopy(dst,src,n); +template +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t n) { + hostspace_parallel_deepcopy(dst, src, n); } - DeepCopy( const ExecutionSpace& exec, void * dst, const void * src, size_t n ) { + DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, size_t n) { exec.fence(); - hostspace_parallel_deepcopy(dst,src,n); + hostspace_parallel_deepcopy(dst, src, n); exec.fence(); } }; -} // namespace Impl - -} // namespace Kokkos +} // namespace Impl -#endif // #define KOKKOS_HOSTSPACE_HPP +} // namespace Kokkos +#endif // #define KOKKOS_HOSTSPACE_HPP diff --git a/lib/kokkos/core/src/Kokkos_Layout.hpp b/lib/kokkos/core/src/Kokkos_Layout.hpp index 6f423d545f..d34bdb9150 100644 --- a/lib/kokkos/core/src/Kokkos_Layout.hpp +++ b/lib/kokkos/core/src/Kokkos_Layout.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -72,22 +73,22 @@ enum { ARRAY_LAYOUT_MAX_RANK = 8 }; /// major." struct LayoutLeft { //! Tag this class as a kokkos array layout - typedef LayoutLeft array_layout ; + typedef LayoutLeft array_layout; - size_t dimension[ ARRAY_LAYOUT_MAX_RANK ]; + size_t dimension[ARRAY_LAYOUT_MAX_RANK]; enum { is_extent_constructible = true }; - LayoutLeft( LayoutLeft const & ) = default ; - LayoutLeft( LayoutLeft && ) = default ; - LayoutLeft & operator = ( LayoutLeft const & ) = default ; - LayoutLeft & operator = ( LayoutLeft && ) = default ; + LayoutLeft(LayoutLeft const&) = default; + LayoutLeft(LayoutLeft&&) = default; + LayoutLeft& operator=(LayoutLeft const&) = default; + LayoutLeft& operator=(LayoutLeft&&) = default; KOKKOS_INLINE_FUNCTION - explicit constexpr - LayoutLeft( size_t N0 = 0 , size_t N1 = 0 , size_t N2 = 0 , size_t N3 = 0 - , size_t N4 = 0 , size_t N5 = 0 , size_t N6 = 0 , size_t N7 = 0 ) - : dimension { N0 , N1 , N2 , N3 , N4 , N5 , N6 , N7 } {} + explicit constexpr LayoutLeft(size_t N0 = 0, size_t N1 = 0, size_t N2 = 0, + size_t N3 = 0, size_t N4 = 0, size_t N5 = 0, + size_t N6 = 0, size_t N7 = 0) + : dimension{N0, N1, N2, N3, N4, N5, N6, N7} {} }; //---------------------------------------------------------------------------- @@ -106,22 +107,22 @@ struct LayoutLeft { /// two-dimensional array, "layout right" is also called "row major." struct LayoutRight { //! Tag this class as a kokkos array layout - typedef LayoutRight array_layout ; + typedef LayoutRight array_layout; - size_t dimension[ ARRAY_LAYOUT_MAX_RANK ]; + size_t dimension[ARRAY_LAYOUT_MAX_RANK]; enum { is_extent_constructible = true }; - LayoutRight( LayoutRight const & ) = default ; - LayoutRight( LayoutRight && ) = default ; - LayoutRight & operator = ( LayoutRight const & ) = default ; - LayoutRight & operator = ( LayoutRight && ) = default ; + LayoutRight(LayoutRight const&) = default; + LayoutRight(LayoutRight&&) = default; + LayoutRight& operator=(LayoutRight const&) = default; + LayoutRight& operator=(LayoutRight&&) = default; KOKKOS_INLINE_FUNCTION - explicit constexpr - LayoutRight( size_t N0 = 0 , size_t N1 = 0 , size_t N2 = 0 , size_t N3 = 0 - , size_t N4 = 0 , size_t N5 = 0 , size_t N6 = 0 , size_t N7 = 0 ) - : dimension { N0 , N1 , N2 , N3 , N4 , N5 , N6 , N7 } {} + explicit constexpr LayoutRight(size_t N0 = 0, size_t N1 = 0, size_t N2 = 0, + size_t N3 = 0, size_t N4 = 0, size_t N5 = 0, + size_t N6 = 0, size_t N7 = 0) + : dimension{N0, N1, N2, N3, N4, N5, N6, N7} {} }; //---------------------------------------------------------------------------- @@ -129,19 +130,18 @@ struct LayoutRight { /// \brief Memory layout tag indicated arbitrarily strided /// multi-index mapping into contiguous memory. struct LayoutStride { - //! Tag this class as a kokkos array layout - typedef LayoutStride array_layout ; + typedef LayoutStride array_layout; - size_t dimension[ ARRAY_LAYOUT_MAX_RANK ] ; - size_t stride[ ARRAY_LAYOUT_MAX_RANK ] ; + size_t dimension[ARRAY_LAYOUT_MAX_RANK]; + size_t stride[ARRAY_LAYOUT_MAX_RANK]; enum { is_extent_constructible = false }; - LayoutStride( LayoutStride const & ) = default ; - LayoutStride( LayoutStride && ) = default ; - LayoutStride & operator = ( LayoutStride const & ) = default ; - LayoutStride & operator = ( LayoutStride && ) = default ; + LayoutStride(LayoutStride const&) = default; + LayoutStride(LayoutStride&&) = default; + LayoutStride& operator=(LayoutStride const&) = default; + LayoutStride& operator=(LayoutStride&&) = default; /** \brief Compute strides from ordered dimensions. * @@ -150,47 +150,40 @@ struct LayoutStride { * Order = {0,1,2,...} is LayoutLeft * Order = {...,2,1,0} is LayoutRight */ - template< typename iTypeOrder , typename iTypeDimen > - KOKKOS_INLINE_FUNCTION static - LayoutStride order_dimensions( int const rank - , iTypeOrder const * const order - , iTypeDimen const * const dimen ) - { - LayoutStride tmp ; - // Verify valid rank order: - int check_input = ARRAY_LAYOUT_MAX_RANK < rank ? 0 : int( 1 << rank ) - 1 ; - for ( int r = 0 ; r < ARRAY_LAYOUT_MAX_RANK ; ++r ) { - tmp.dimension[r] = 0 ; - tmp.stride[r] = 0 ; - } - for ( int r = 0 ; r < rank ; ++r ) { - check_input &= ~int( 1 << order[r] ); - } - if ( 0 == check_input ) { - size_t n = 1 ; - for ( int r = 0 ; r < rank ; ++r ) { - tmp.stride[ order[r] ] = n ; - n *= ( dimen[order[r]] ); - tmp.dimension[r] = dimen[r]; - } + template + KOKKOS_INLINE_FUNCTION static LayoutStride order_dimensions( + int const rank, iTypeOrder const* const order, + iTypeDimen const* const dimen) { + LayoutStride tmp; + // Verify valid rank order: + int check_input = ARRAY_LAYOUT_MAX_RANK < rank ? 0 : int(1 << rank) - 1; + for (int r = 0; r < ARRAY_LAYOUT_MAX_RANK; ++r) { + tmp.dimension[r] = 0; + tmp.stride[r] = 0; + } + for (int r = 0; r < rank; ++r) { + check_input &= ~int(1 << order[r]); + } + if (0 == check_input) { + size_t n = 1; + for (int r = 0; r < rank; ++r) { + tmp.stride[order[r]] = n; + n *= (dimen[order[r]]); + tmp.dimension[r] = dimen[r]; } - return tmp ; } + return tmp; + } KOKKOS_INLINE_FUNCTION - explicit constexpr - LayoutStride( size_t N0 = 0 , size_t S0 = 0 - , size_t N1 = 0 , size_t S1 = 0 - , size_t N2 = 0 , size_t S2 = 0 - , size_t N3 = 0 , size_t S3 = 0 - , size_t N4 = 0 , size_t S4 = 0 - , size_t N5 = 0 , size_t S5 = 0 - , size_t N6 = 0 , size_t S6 = 0 - , size_t N7 = 0 , size_t S7 = 0 - ) - : dimension { N0 , N1 , N2 , N3 , N4 , N5 , N6 , N7 } - , stride { S0 , S1 , S2 , S3 , S4 , S5 , S6 , S7 } - {} + explicit constexpr LayoutStride(size_t N0 = 0, size_t S0 = 0, size_t N1 = 0, + size_t S1 = 0, size_t N2 = 0, size_t S2 = 0, + size_t N3 = 0, size_t S3 = 0, size_t N4 = 0, + size_t S4 = 0, size_t N5 = 0, size_t S5 = 0, + size_t N6 = 0, size_t S6 = 0, size_t N7 = 0, + size_t S7 = 0) + : dimension{N0, N1, N2, N3, N4, N5, N6, N7}, stride{S0, S1, S2, S3, + S4, S5, S6, S7} {} }; // ========================================================================== @@ -213,81 +206,81 @@ struct LayoutStride { /// compile-time constants. This speeds up index calculations. If /// both tile dimensions are powers of two, Kokkos can optimize /// further. -template < unsigned ArgN0 , unsigned ArgN1 , - bool IsPowerOfTwo = ( Impl::is_integral_power_of_two(ArgN0) && - Impl::is_integral_power_of_two(ArgN1) ) - > +template struct LayoutTileLeft { - - static_assert( Impl::is_integral_power_of_two(ArgN0) && - Impl::is_integral_power_of_two(ArgN1) - , "LayoutTileLeft must be given power-of-two tile dimensions" ); + static_assert(Impl::is_integral_power_of_two(ArgN0) && + Impl::is_integral_power_of_two(ArgN1), + "LayoutTileLeft must be given power-of-two tile dimensions"); //! Tag this class as a kokkos array layout - typedef LayoutTileLeft array_layout ; + typedef LayoutTileLeft array_layout; enum { N0 = ArgN0 }; enum { N1 = ArgN1 }; - size_t dimension[ ARRAY_LAYOUT_MAX_RANK ] ; + size_t dimension[ARRAY_LAYOUT_MAX_RANK]; enum { is_extent_constructible = true }; - LayoutTileLeft( LayoutTileLeft const & ) = default ; - LayoutTileLeft( LayoutTileLeft && ) = default ; - LayoutTileLeft & operator = ( LayoutTileLeft const & ) = default ; - LayoutTileLeft & operator = ( LayoutTileLeft && ) = default ; + LayoutTileLeft(LayoutTileLeft const&) = default; + LayoutTileLeft(LayoutTileLeft&&) = default; + LayoutTileLeft& operator=(LayoutTileLeft const&) = default; + LayoutTileLeft& operator=(LayoutTileLeft&&) = default; KOKKOS_INLINE_FUNCTION - explicit constexpr - LayoutTileLeft( size_t argN0 = 0 , size_t argN1 = 0 , size_t argN2 = 0 , size_t argN3 = 0 - , size_t argN4 = 0 , size_t argN5 = 0 , size_t argN6 = 0 , size_t argN7 = 0 - ) - : dimension { argN0 , argN1 , argN2 , argN3 , argN4 , argN5 , argN6 , argN7 } {} + explicit constexpr LayoutTileLeft(size_t argN0 = 0, size_t argN1 = 0, + size_t argN2 = 0, size_t argN3 = 0, + size_t argN4 = 0, size_t argN5 = 0, + size_t argN6 = 0, size_t argN7 = 0) + : dimension{argN0, argN1, argN2, argN3, argN4, argN5, argN6, argN7} {} }; -#endif // KOKKOS_ENABLE_DEPRECATED_CODE +#endif // KOKKOS_ENABLE_DEPRECATED_CODE // =================================================================================== ////////////////////////////////////////////////////////////////////////////////////// -enum class Iterate -{ +enum class Iterate { Default, - Left, // Left indices stride fastest - Right // Right indices stride fastest + Left, // Left indices stride fastest + Right // Right indices stride fastest }; // To check for LayoutTiled -// This is to hide extra compile-time 'identifier' info within the LayoutTiled class by not relying on template specialization to include the ArgN*'s -template < typename LayoutTiledCheck, class Enable = void > +// This is to hide extra compile-time 'identifier' info within the LayoutTiled +// class by not relying on template specialization to include the ArgN*'s +template struct is_layouttiled : std::false_type {}; #ifndef KOKKOS_ENABLE_DEPRECATED_CODE -template < typename LayoutTiledCheck > -struct is_layouttiled< LayoutTiledCheck, typename std::enable_if::type > : std::true_type {}; +template +struct is_layouttiled< + LayoutTiledCheck, + typename std::enable_if::type> + : std::true_type {}; namespace Experimental { /// LayoutTiled // Must have Rank >= 2 -template < Kokkos::Iterate OuterP, Kokkos::Iterate InnerP, - unsigned ArgN0 , unsigned ArgN1 , unsigned ArgN2 = 0, unsigned ArgN3 = 0, unsigned ArgN4 = 0, unsigned ArgN5 = 0, unsigned ArgN6 = 0, unsigned ArgN7 = 0, - bool IsPowerOfTwo = - ( Kokkos::Impl::is_integral_power_of_two(ArgN0) && - Kokkos::Impl::is_integral_power_of_two(ArgN1) && - (Kokkos::Impl::is_integral_power_of_two(ArgN2) || (ArgN2 == 0) ) && - (Kokkos::Impl::is_integral_power_of_two(ArgN3) || (ArgN3 == 0) ) && - (Kokkos::Impl::is_integral_power_of_two(ArgN4) || (ArgN4 == 0) ) && - (Kokkos::Impl::is_integral_power_of_two(ArgN5) || (ArgN5 == 0) ) && - (Kokkos::Impl::is_integral_power_of_two(ArgN6) || (ArgN6 == 0) ) && - (Kokkos::Impl::is_integral_power_of_two(ArgN7) || (ArgN7 == 0) ) - ) - > +template < + Kokkos::Iterate OuterP, Kokkos::Iterate InnerP, unsigned ArgN0, + unsigned ArgN1, unsigned ArgN2 = 0, unsigned ArgN3 = 0, unsigned ArgN4 = 0, + unsigned ArgN5 = 0, unsigned ArgN6 = 0, unsigned ArgN7 = 0, + bool IsPowerOfTwo = + (Kokkos::Impl::is_integral_power_of_two(ArgN0) && + Kokkos::Impl::is_integral_power_of_two(ArgN1) && + (Kokkos::Impl::is_integral_power_of_two(ArgN2) || (ArgN2 == 0)) && + (Kokkos::Impl::is_integral_power_of_two(ArgN3) || (ArgN3 == 0)) && + (Kokkos::Impl::is_integral_power_of_two(ArgN4) || (ArgN4 == 0)) && + (Kokkos::Impl::is_integral_power_of_two(ArgN5) || (ArgN5 == 0)) && + (Kokkos::Impl::is_integral_power_of_two(ArgN6) || (ArgN6 == 0)) && + (Kokkos::Impl::is_integral_power_of_two(ArgN7) || (ArgN7 == 0)))> struct LayoutTiled { - - static_assert( IsPowerOfTwo - , "LayoutTiled must be given power-of-two tile dimensions" ); + static_assert(IsPowerOfTwo, + "LayoutTiled must be given power-of-two tile dimensions"); #if 0 static_assert( (Impl::is_integral_power_of_two(ArgN0) ) && @@ -301,7 +294,9 @@ struct LayoutTiled { , "LayoutTiled must be given power-of-two tile dimensions" ); #endif - typedef LayoutTiled array_layout ; + typedef LayoutTiled + array_layout; static constexpr Iterate outer_pattern = OuterP; static constexpr Iterate inner_pattern = InnerP; @@ -314,79 +309,93 @@ struct LayoutTiled { enum { N6 = ArgN6 }; enum { N7 = ArgN7 }; - size_t dimension[ ARRAY_LAYOUT_MAX_RANK ] ; + size_t dimension[ARRAY_LAYOUT_MAX_RANK]; enum { is_extent_constructible = true }; - LayoutTiled( LayoutTiled const & ) = default ; - LayoutTiled( LayoutTiled && ) = default ; - LayoutTiled & operator = ( LayoutTiled const & ) = default ; - LayoutTiled & operator = ( LayoutTiled && ) = default ; + LayoutTiled(LayoutTiled const&) = default; + LayoutTiled(LayoutTiled&&) = default; + LayoutTiled& operator=(LayoutTiled const&) = default; + LayoutTiled& operator=(LayoutTiled&&) = default; KOKKOS_INLINE_FUNCTION - explicit constexpr - LayoutTiled( size_t argN0 = 0 , size_t argN1 = 0 , size_t argN2 = 0 , size_t argN3 = 0 - , size_t argN4 = 0 , size_t argN5 = 0 , size_t argN6 = 0 , size_t argN7 = 0 - ) - : dimension { argN0 , argN1 , argN2 , argN3 , argN4 , argN5 , argN6 , argN7 } {} + explicit constexpr LayoutTiled(size_t argN0 = 0, size_t argN1 = 0, + size_t argN2 = 0, size_t argN3 = 0, + size_t argN4 = 0, size_t argN5 = 0, + size_t argN6 = 0, size_t argN7 = 0) + : dimension{argN0, argN1, argN2, argN3, argN4, argN5, argN6, argN7} {} }; -} // namespace Experimental +} // namespace Experimental #endif - // For use with view_copy -template < typename ... Layout > +template struct layout_iterate_type_selector { - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Default ; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Default ; + static const Kokkos::Iterate outer_iteration_pattern = + Kokkos::Iterate::Default; + static const Kokkos::Iterate inner_iteration_pattern = + Kokkos::Iterate::Default; }; template <> -struct layout_iterate_type_selector< Kokkos::LayoutRight > { - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Right ; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Right ; +struct layout_iterate_type_selector { + static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Right; + static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Right; }; template <> -struct layout_iterate_type_selector< Kokkos::LayoutLeft > { - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Left ; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Left ; +struct layout_iterate_type_selector { + static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Left; + static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Left; }; template <> -struct layout_iterate_type_selector< Kokkos::LayoutStride > { - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Default ; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Default ; +struct layout_iterate_type_selector { + static const Kokkos::Iterate outer_iteration_pattern = + Kokkos::Iterate::Default; + static const Kokkos::Iterate inner_iteration_pattern = + Kokkos::Iterate::Default; }; #ifndef KOKKOS_ENABLE_DEPRECATED_CODE -template < unsigned ArgN0 , unsigned ArgN1 , unsigned ArgN2 , unsigned ArgN3 , unsigned ArgN4 , unsigned ArgN5 , unsigned ArgN6 , unsigned ArgN7 > -struct layout_iterate_type_selector< Kokkos::Experimental::LayoutTiled > { - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Left ; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Left ; +template +struct layout_iterate_type_selector > { + static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Left; + static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Left; }; -template < unsigned ArgN0 , unsigned ArgN1 , unsigned ArgN2 , unsigned ArgN3 , unsigned ArgN4 , unsigned ArgN5 , unsigned ArgN6 , unsigned ArgN7 > -struct layout_iterate_type_selector< Kokkos::Experimental::LayoutTiled > { - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Right ; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Left ; +template +struct layout_iterate_type_selector > { + static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Right; + static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Left; }; -template < unsigned ArgN0 , unsigned ArgN1 , unsigned ArgN2 , unsigned ArgN3 , unsigned ArgN4 , unsigned ArgN5 , unsigned ArgN6 , unsigned ArgN7 > -struct layout_iterate_type_selector< Kokkos::Experimental::LayoutTiled > { - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Left ; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Right ; +template +struct layout_iterate_type_selector > { + static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Left; + static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Right; }; -template < unsigned ArgN0 , unsigned ArgN1 , unsigned ArgN2 , unsigned ArgN3 , unsigned ArgN4 , unsigned ArgN5 , unsigned ArgN6 , unsigned ArgN7 > -struct layout_iterate_type_selector< Kokkos::Experimental::LayoutTiled > { - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Right ; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Right ; +template +struct layout_iterate_type_selector > { + static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Right; + static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Right; }; #endif -} // namespace Kokkos - -#endif // #ifndef KOKKOS_LAYOUT_HPP +} // namespace Kokkos +#endif // #ifndef KOKKOS_LAYOUT_HPP diff --git a/lib/kokkos/core/src/Kokkos_Macros.hpp b/lib/kokkos/core/src/Kokkos_Macros.hpp index 6b8ae02f82..5649d12e97 100644 --- a/lib/kokkos/core/src/Kokkos_Macros.hpp +++ b/lib/kokkos/core/src/Kokkos_Macros.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -52,15 +53,16 @@ * KOKKOS_ENABLE_QTHREADS Kokkos::Qthreads execution space * KOKKOS_ENABLE_HPX Kokkos::Experimental::HPX execution space * KOKKOS_ENABLE_OPENMP Kokkos::OpenMP execution space - * KOKKOS_ENABLE_OPENMPTARGET Kokkos::Experimental::OpenMPTarget execution space - * KOKKOS_ENABLE_HWLOC HWLOC library is available. + * KOKKOS_ENABLE_OPENMPTARGET Kokkos::Experimental::OpenMPTarget + * execution space KOKKOS_ENABLE_HWLOC HWLOC library is available. * KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK Insert array bounds checks, is expensive! - * KOKKOS_ENABLE_MPI Negotiate MPI/execution space interactions. - * KOKKOS_ENABLE_CUDA_UVM Use CUDA UVM for Cuda memory space. + * KOKKOS_ENABLE_MPI Negotiate MPI/execution space + * interactions. KOKKOS_ENABLE_CUDA_UVM Use CUDA UVM for Cuda memory + * space. */ #ifndef KOKKOS_DONT_INCLUDE_CORE_CONFIG_H - #include +#include #endif #include @@ -97,449 +99,461 @@ //---------------------------------------------------------------------------- -#if defined(KOKKOS_ENABLE_SERIAL) || defined(KOKKOS_ENABLE_THREADS) || \ +#if defined(KOKKOS_ENABLE_SERIAL) || defined(KOKKOS_ENABLE_THREADS) || \ defined(KOKKOS_ENABLE_OPENMP) || defined(KOKKOS_ENABLE_QTHREADS) || \ - defined(KOKKOS_ENABLE_HPX) || \ - defined(KOKKOS_ENABLE_ROCM) || defined(KOKKOS_ENABLE_OPENMPTARGET) - #define KOKKOS_INTERNAL_ENABLE_NON_CUDA_BACKEND + defined(KOKKOS_ENABLE_HPX) || defined(KOKKOS_ENABLE_ROCM) || \ + defined(KOKKOS_ENABLE_OPENMPTARGET) +#define KOKKOS_INTERNAL_ENABLE_NON_CUDA_BACKEND #endif -#if !defined(KOKKOS_ENABLE_THREADS) && !defined(KOKKOS_ENABLE_CUDA) && \ +#if !defined(KOKKOS_ENABLE_THREADS) && !defined(KOKKOS_ENABLE_CUDA) && \ !defined(KOKKOS_ENABLE_OPENMP) && !defined(KOKKOS_ENABLE_QTHREADS) && \ - !defined(KOKKOS_ENABLE_HPX) && \ - !defined(KOKKOS_ENABLE_ROCM) && !defined(KOKKOS_ENABLE_OPENMPTARGET) - #define KOKKOS_INTERNAL_NOT_PARALLEL + !defined(KOKKOS_ENABLE_HPX) && !defined(KOKKOS_ENABLE_ROCM) && \ + !defined(KOKKOS_ENABLE_OPENMPTARGET) +#define KOKKOS_INTERNAL_NOT_PARALLEL #endif #define KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA -#if defined( KOKKOS_ENABLE_CUDA ) && defined( __CUDACC__ ) - // Compiling with a CUDA compiler. - // - // Include to pick up the CUDA_VERSION macro defined as: - // CUDA_VERSION = ( MAJOR_VERSION * 1000 ) + ( MINOR_VERSION * 10 ) - // - // When generating device code the __CUDA_ARCH__ macro is defined as: - // __CUDA_ARCH__ = ( MAJOR_CAPABILITY * 100 ) + ( MINOR_CAPABILITY * 10 ) - - #include - #include - - #if !defined( CUDA_VERSION ) - #error "#include did not define CUDA_VERSION." - #endif - - #if ( CUDA_VERSION < 7000 ) - // CUDA supports C++11 in device code starting with version 7.0. - // This includes auto type and device code internal lambdas. - #error "Cuda version 7.0 or greater required." - #endif - - #if defined( __CUDA_ARCH__ ) && ( __CUDA_ARCH__ < 300 ) - // Compiling with CUDA compiler for device code. - #error "Cuda device capability >= 3.0 is required." - #endif - - #ifdef KOKKOS_ENABLE_CUDA_LAMBDA - #if ( CUDA_VERSION < 7050 ) - // CUDA supports C++11 lambdas generated in host code to be given - // to the device starting with version 7.5. But the release candidate (7.5.6) - // still identifies as 7.0. - #error "Cuda version 7.5 or greater required for host-to-device Lambda support." - #endif - - #if ( CUDA_VERSION < 8000 ) && defined( __NVCC__ ) - #define KOKKOS_LAMBDA [=]__device__ - #if defined( KOKKOS_INTERNAL_ENABLE_NON_CUDA_BACKEND ) - #undef KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA - #endif - #else - #define KOKKOS_LAMBDA [=]__host__ __device__ - - #if defined( KOKKOS_ENABLE_CXX17 ) || defined( KOKKOS_ENABLE_CXX20 ) - #define KOKKOS_CLASS_LAMBDA [=,*this] __host__ __device__ - #endif - #endif - - #if defined( __NVCC__ ) - #define KOKKOS_IMPL_NEED_FUNCTOR_WRAPPER - #endif - #else // !defined(KOKKOS_ENABLE_CUDA_LAMBDA) - #undef KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA - #endif // !defined(KOKKOS_ENABLE_CUDA_LAMBDA) - - #if ( 9000 <= CUDA_VERSION ) && ( CUDA_VERSION < 10000 ) - // CUDA 9 introduced an incorrect warning, - // see https://github.com/kokkos/kokkos/issues/1470 - #define KOKKOS_CUDA_9_DEFAULTED_BUG_WORKAROUND - #endif - - #if ( 10000 > CUDA_VERSION ) - #define KOKKOS_ENABLE_PRE_CUDA_10_DEPRECATION_API - #endif - - #if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 700) - // PTX atomics with memory order semantics are only available on volta and later - #if !defined(KOKKOS_DISABLE_CUDA_ASM) - #if !defined(KOKKOS_ENABLE_CUDA_ASM) - #define KOKKOS_ENABLE_CUDA_ASM - #if !defined(KOKKOS_DISABLE_CUDA_ASM_ATOMICS) - #define KOKKOS_ENABLE_CUDA_ASM_ATOMICS - #endif - #endif - #endif - #endif - - -#endif // #if defined( KOKKOS_ENABLE_CUDA ) && defined( __CUDACC__ ) +#if defined(KOKKOS_ENABLE_CUDA) && defined(__CUDACC__) +// Compiling with a CUDA compiler. +// +// Include to pick up the CUDA_VERSION macro defined as: +// CUDA_VERSION = ( MAJOR_VERSION * 1000 ) + ( MINOR_VERSION * 10 ) +// +// When generating device code the __CUDA_ARCH__ macro is defined as: +// __CUDA_ARCH__ = ( MAJOR_CAPABILITY * 100 ) + ( MINOR_CAPABILITY * 10 ) + +#include +#include + +#if !defined(CUDA_VERSION) +#error "#include did not define CUDA_VERSION." +#endif + +#if (CUDA_VERSION < 7000) +// CUDA supports C++11 in device code starting with version 7.0. +// This includes auto type and device code internal lambdas. +#error "Cuda version 7.0 or greater required." +#endif + +#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ < 300) +// Compiling with CUDA compiler for device code. +#error "Cuda device capability >= 3.0 is required." +#endif + +#ifdef KOKKOS_ENABLE_CUDA_LAMBDA +#if (CUDA_VERSION < 7050) +// CUDA supports C++11 lambdas generated in host code to be given +// to the device starting with version 7.5. But the release candidate (7.5.6) +// still identifies as 7.0. +#error "Cuda version 7.5 or greater required for host-to-device Lambda support." +#endif + +#if (CUDA_VERSION < 8000) && defined(__NVCC__) +#define KOKKOS_LAMBDA [=] __device__ +#if defined(KOKKOS_INTERNAL_ENABLE_NON_CUDA_BACKEND) +#undef KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA +#endif +#else +#define KOKKOS_LAMBDA [=] __host__ __device__ + +#if defined(KOKKOS_ENABLE_CXX17) || defined(KOKKOS_ENABLE_CXX20) +#define KOKKOS_CLASS_LAMBDA [ =, *this ] __host__ __device__ +#endif +#endif + +#if defined(__NVCC__) +#define KOKKOS_IMPL_NEED_FUNCTOR_WRAPPER +#endif +#else // !defined(KOKKOS_ENABLE_CUDA_LAMBDA) +#undef KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA +#endif // !defined(KOKKOS_ENABLE_CUDA_LAMBDA) +#if (9000 <= CUDA_VERSION) && (CUDA_VERSION < 10000) +// CUDA 9 introduced an incorrect warning, +// see https://github.com/kokkos/kokkos/issues/1470 +#define KOKKOS_CUDA_9_DEFAULTED_BUG_WORKAROUND +#endif + +#if (10000 > CUDA_VERSION) +#define KOKKOS_ENABLE_PRE_CUDA_10_DEPRECATION_API +#endif + +#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 700) +// PTX atomics with memory order semantics are only available on volta and later +#if !defined(KOKKOS_DISABLE_CUDA_ASM) +#if !defined(KOKKOS_ENABLE_CUDA_ASM) +#define KOKKOS_ENABLE_CUDA_ASM +#if !defined(KOKKOS_DISABLE_CUDA_ASM_ATOMICS) +#define KOKKOS_ENABLE_CUDA_ASM_ATOMICS +#endif +#endif +#endif +#endif + +#endif // #if defined( KOKKOS_ENABLE_CUDA ) && defined( __CUDACC__ ) //---------------------------------------------------------------------------- // Mapping compiler built-ins to KOKKOS_COMPILER_*** macros -#if defined( __NVCC__ ) - // NVIDIA compiler is being used. - // Code is parsed and separated into host and device code. - // Host code is compiled again with another compiler. - // Device code is compile to 'ptx'. - #define KOKKOS_COMPILER_NVCC __NVCC__ -#endif // #if defined( __NVCC__ ) +#if defined(__NVCC__) +// NVIDIA compiler is being used. +// Code is parsed and separated into host and device code. +// Host code is compiled again with another compiler. +// Device code is compile to 'ptx'. +#define KOKKOS_COMPILER_NVCC __NVCC__ +#endif // #if defined( __NVCC__ ) -#if !defined( KOKKOS_LAMBDA ) - #define KOKKOS_LAMBDA [=] +#if !defined(KOKKOS_LAMBDA) +#define KOKKOS_LAMBDA [=] #endif -#if (defined( KOKKOS_ENABLE_CXX17 ) || defined( KOKKOS_ENABLE_CXX20) )&& !defined( KOKKOS_CLASS_LAMBDA ) - #define KOKKOS_CLASS_LAMBDA [=,*this] +#if (defined(KOKKOS_ENABLE_CXX17) || defined(KOKKOS_ENABLE_CXX20)) && \ + !defined(KOKKOS_CLASS_LAMBDA) +#define KOKKOS_CLASS_LAMBDA [ =, *this ] #endif //#if !defined( __CUDA_ARCH__ ) // Not compiling Cuda code to 'ptx'. // Intel compiler for host code. -#if defined( __INTEL_COMPILER ) - #define KOKKOS_COMPILER_INTEL __INTEL_COMPILER -#elif defined( __ICC ) - // Old define - #define KOKKOS_COMPILER_INTEL __ICC -#elif defined( __ECC ) - // Very old define - #define KOKKOS_COMPILER_INTEL __ECC +#if defined(__INTEL_COMPILER) +#define KOKKOS_COMPILER_INTEL __INTEL_COMPILER +#elif defined(__ICC) +// Old define +#define KOKKOS_COMPILER_INTEL __ICC +#elif defined(__ECC) +// Very old define +#define KOKKOS_COMPILER_INTEL __ECC #endif // CRAY compiler for host code -#if defined( _CRAYC ) - #define KOKKOS_COMPILER_CRAYC _CRAYC +#if defined(_CRAYC) +#define KOKKOS_COMPILER_CRAYC _CRAYC #endif -#if defined( __IBMCPP__ ) - // IBM C++ - #define KOKKOS_COMPILER_IBM __IBMCPP__ -#elif defined( __IBMC__ ) - #define KOKKOS_COMPILER_IBM __IBMC__ +#if defined(__IBMCPP__) +// IBM C++ +#define KOKKOS_COMPILER_IBM __IBMCPP__ +#elif defined(__IBMC__) +#define KOKKOS_COMPILER_IBM __IBMC__ #endif -#if defined( __APPLE_CC__ ) - #define KOKKOS_COMPILER_APPLECC __APPLE_CC__ +#if defined(__APPLE_CC__) +#define KOKKOS_COMPILER_APPLECC __APPLE_CC__ #endif -#if defined( __clang__ ) && !defined( KOKKOS_COMPILER_INTEL ) - #define KOKKOS_COMPILER_CLANG __clang_major__*100+__clang_minor__*10+__clang_patchlevel__ +#if defined(__clang__) && !defined(KOKKOS_COMPILER_INTEL) +#define KOKKOS_COMPILER_CLANG \ + __clang_major__ * 100 + __clang_minor__ * 10 + __clang_patchlevel__ #endif -#if !defined( __clang__ ) && !defined( KOKKOS_COMPILER_INTEL ) &&defined( __GNUC__ ) - #define KOKKOS_COMPILER_GNU __GNUC__*100+__GNUC_MINOR__*10+__GNUC_PATCHLEVEL__ +#if !defined(__clang__) && !defined(KOKKOS_COMPILER_INTEL) && defined(__GNUC__) +#define KOKKOS_COMPILER_GNU \ + __GNUC__ * 100 + __GNUC_MINOR__ * 10 + __GNUC_PATCHLEVEL__ - #if ( 472 > KOKKOS_COMPILER_GNU ) - #error "Compiling with GCC version earlier than 4.7.2 is not supported." - #endif +#if (472 > KOKKOS_COMPILER_GNU) +#error "Compiling with GCC version earlier than 4.7.2 is not supported." +#endif #endif -#if defined( __PGIC__ ) - #define KOKKOS_COMPILER_PGI __PGIC__*100+__PGIC_MINOR__*10+__PGIC_PATCHLEVEL__ +#if defined(__PGIC__) +#define KOKKOS_COMPILER_PGI \ + __PGIC__ * 100 + __PGIC_MINOR__ * 10 + __PGIC_PATCHLEVEL__ - #if ( 1540 > KOKKOS_COMPILER_PGI ) - #error "Compiling with PGI version earlier than 15.4 is not supported." - #endif +#if (1540 > KOKKOS_COMPILER_PGI) +#error "Compiling with PGI version earlier than 15.4 is not supported." +#endif #endif //#endif // #if !defined( __CUDA_ARCH__ ) //---------------------------------------------------------------------------- // Language info: C++, CUDA, OPENMP -#if defined( KOKKOS_ENABLE_CUDA ) - // Compiling Cuda code to 'ptx' +#if defined(KOKKOS_ENABLE_CUDA) +// Compiling Cuda code to 'ptx' - #define KOKKOS_FORCEINLINE_FUNCTION __device__ __host__ __forceinline__ - #define KOKKOS_INLINE_FUNCTION __device__ __host__ inline - #define KOKKOS_FUNCTION __device__ __host__ - #if defined( KOKKOS_COMPILER_NVCC ) - #define KOKKOS_INLINE_FUNCTION_DELETED inline - #else - #define KOKKOS_INLINE_FUNCTION_DELETED __device__ __host__ inline - #endif -#endif // #if defined( __CUDA_ARCH__ ) +#define KOKKOS_FORCEINLINE_FUNCTION __device__ __host__ __forceinline__ +#define KOKKOS_IMPL_FORCEINLINE __forceinline__ +#define KOKKOS_INLINE_FUNCTION __device__ __host__ inline +#define KOKKOS_FUNCTION __device__ __host__ +#if defined(KOKKOS_COMPILER_NVCC) +#define KOKKOS_INLINE_FUNCTION_DELETED inline +#else +#define KOKKOS_INLINE_FUNCTION_DELETED __device__ __host__ inline +#endif +#endif // #if defined( __CUDA_ARCH__ ) -#if defined( KOKKOS_ENABLE_ROCM ) && defined( __HCC__ ) +#if defined(KOKKOS_ENABLE_ROCM) && defined(__HCC__) - #define KOKKOS_FORCEINLINE_FUNCTION __attribute__((amp,cpu)) inline - #define KOKKOS_INLINE_FUNCTION __attribute__((amp,cpu)) inline - #define KOKKOS_FUNCTION __attribute__((amp,cpu)) - #define KOKKOS_LAMBDA [=] __attribute__((amp,cpu)) +#define KOKKOS_FORCEINLINE_FUNCTION __attribute__((amp, cpu)) inline +#define KOKKOS_INLINE_FUNCTION __attribute__((amp, cpu)) inline +#define KOKKOS_FUNCTION __attribute__((amp, cpu)) +#define KOKKOS_LAMBDA [=] __attribute__((amp, cpu)) #endif -#if defined( _OPENMP ) - // Compiling with OpenMP. - // The value of _OPENMP is an integer value YYYYMM - // where YYYY and MM are the year and month designation - // of the supported OpenMP API version. -#endif // #if defined( _OPENMP ) +#if defined(_OPENMP) +// Compiling with OpenMP. +// The value of _OPENMP is an integer value YYYYMM +// where YYYY and MM are the year and month designation +// of the supported OpenMP API version. +#endif // #if defined( _OPENMP ) //---------------------------------------------------------------------------- // Intel compiler macros -#if defined( KOKKOS_COMPILER_INTEL ) - #define KOKKOS_ENABLE_PRAGMA_UNROLL 1 - #define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1 - #define KOKKOS_ENABLE_PRAGMA_VECTOR 1 - #if ( 1800 > KOKKOS_COMPILER_INTEL ) - #define KOKKOS_ENABLE_PRAGMA_SIMD 1 - #endif - - #if ( __INTEL_COMPILER > 1400 ) - #define KOKKOS_ENABLE_PRAGMA_IVDEP 1 - #endif - - #if ! defined( KOKKOS_MEMORY_ALIGNMENT ) - #define KOKKOS_MEMORY_ALIGNMENT 64 - #endif - - #define KOKKOS_RESTRICT __restrict__ - - #ifndef KOKKOS_IMPL_ALIGN_PTR - #define KOKKOS_IMPL_ALIGN_PTR(size) __attribute__((align_value(size))) - #endif - - #if ( 1400 > KOKKOS_COMPILER_INTEL ) - #if ( 1300 > KOKKOS_COMPILER_INTEL ) - #error "Compiling with Intel version earlier than 13.0 is not supported. Official minimal version is 14.0." - #else - #warning "Compiling with Intel version 13.x probably works but is not officially supported. Official minimal version is 14.0." - #endif - #endif - - #if !defined( KOKKOS_ENABLE_ASM ) && !defined( _WIN32 ) - #define KOKKOS_ENABLE_ASM 1 - #endif - - #if !defined( KOKKOS_FORCEINLINE_FUNCTION ) - #if !defined( _WIN32 ) - #define KOKKOS_FORCEINLINE_FUNCTION inline __attribute__((always_inline)) - #else - #define KOKKOS_FORCEINLINE_FUNCTION inline - #endif - #endif - - #if defined( KOKKOS_ARCH_AVX512MIC ) - #define KOKKOS_ENABLE_RFO_PREFETCH 1 - #if (KOKKOS_COMPILER_INTEL < 1800) && !defined(KOKKOS_KNL_USE_ASM_WORKAROUND) - #define KOKKOS_KNL_USE_ASM_WORKAROUND 1 - #endif - #endif - - #if defined( __MIC__ ) - // Compiling for Xeon Phi - #endif +#if defined(KOKKOS_COMPILER_INTEL) +#define KOKKOS_ENABLE_PRAGMA_UNROLL 1 +#define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1 +#define KOKKOS_ENABLE_PRAGMA_VECTOR 1 +#if (1800 > KOKKOS_COMPILER_INTEL) +#define KOKKOS_ENABLE_PRAGMA_SIMD 1 +#endif + +#if (__INTEL_COMPILER > 1400) +#define KOKKOS_ENABLE_PRAGMA_IVDEP 1 +#endif + +#if !defined(KOKKOS_MEMORY_ALIGNMENT) +#define KOKKOS_MEMORY_ALIGNMENT 64 +#endif + +#define KOKKOS_RESTRICT __restrict__ + +#ifndef KOKKOS_IMPL_ALIGN_PTR +#define KOKKOS_IMPL_ALIGN_PTR(size) __attribute__((align_value(size))) +#endif + +#if (1400 > KOKKOS_COMPILER_INTEL) +#if (1300 > KOKKOS_COMPILER_INTEL) +#error \ + "Compiling with Intel version earlier than 13.0 is not supported. Official minimal version is 14.0." +#else +#warning \ + "Compiling with Intel version 13.x probably works but is not officially supported. Official minimal version is 14.0." +#endif +#endif + +#if !defined(KOKKOS_ENABLE_ASM) && !defined(_WIN32) +#define KOKKOS_ENABLE_ASM 1 +#endif + +#if !defined(KOKKOS_FORCEINLINE_FUNCTION) +#if !defined(_WIN32) +#define KOKKOS_FORCEINLINE_FUNCTION inline __attribute__((always_inline)) +#define KOKKOS_IMPL_FORCEINLINE __attribute__((always_inline)) +#else +#define KOKKOS_FORCEINLINE_FUNCTION inline +#endif +#endif + +#if defined(KOKKOS_ARCH_AVX512MIC) +#define KOKKOS_ENABLE_RFO_PREFETCH 1 +#if (KOKKOS_COMPILER_INTEL < 1800) && !defined(KOKKOS_KNL_USE_ASM_WORKAROUND) +#define KOKKOS_KNL_USE_ASM_WORKAROUND 1 +#endif +#endif + +#if defined(__MIC__) +// Compiling for Xeon Phi +#endif #endif //---------------------------------------------------------------------------- // Cray compiler macros -#if defined( KOKKOS_COMPILER_CRAYC ) +#if defined(KOKKOS_COMPILER_CRAYC) #endif //---------------------------------------------------------------------------- // IBM Compiler macros -#if defined( KOKKOS_COMPILER_IBM ) - #define KOKKOS_ENABLE_PRAGMA_UNROLL 1 - //#define KOKKOS_ENABLE_PRAGMA_IVDEP 1 - //#define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1 - //#define KOKKOS_ENABLE_PRAGMA_VECTOR 1 - //#define KOKKOS_ENABLE_PRAGMA_SIMD 1 +#if defined(KOKKOS_COMPILER_IBM) +#define KOKKOS_ENABLE_PRAGMA_UNROLL 1 +//#define KOKKOS_ENABLE_PRAGMA_IVDEP 1 +//#define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1 +//#define KOKKOS_ENABLE_PRAGMA_VECTOR 1 +//#define KOKKOS_ENABLE_PRAGMA_SIMD 1 - #if ! defined( KOKKOS_ENABLE_ASM ) - #define KOKKOS_ENABLE_ASM 1 - #endif +#if !defined(KOKKOS_ENABLE_ASM) +#define KOKKOS_ENABLE_ASM 1 +#endif #endif //---------------------------------------------------------------------------- // CLANG compiler macros -#if defined( KOKKOS_COMPILER_CLANG ) - //#define KOKKOS_ENABLE_PRAGMA_UNROLL 1 - //#define KOKKOS_ENABLE_PRAGMA_IVDEP 1 - //#define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1 - //#define KOKKOS_ENABLE_PRAGMA_VECTOR 1 - //#define KOKKOS_ENABLE_PRAGMA_SIMD 1 +#if defined(KOKKOS_COMPILER_CLANG) +//#define KOKKOS_ENABLE_PRAGMA_UNROLL 1 +//#define KOKKOS_ENABLE_PRAGMA_IVDEP 1 +//#define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1 +//#define KOKKOS_ENABLE_PRAGMA_VECTOR 1 +//#define KOKKOS_ENABLE_PRAGMA_SIMD 1 - #if !defined( KOKKOS_FORCEINLINE_FUNCTION ) - #define KOKKOS_FORCEINLINE_FUNCTION inline __attribute__((always_inline)) - #endif +#if !defined(KOKKOS_FORCEINLINE_FUNCTION) +#define KOKKOS_FORCEINLINE_FUNCTION inline __attribute__((always_inline)) +#define KOKKOS_IMPL_FORCEINLINE __attribute__((always_inline)) +#endif - #if !defined( KOKKOS_IMPL_ALIGN_PTR ) - #define KOKKOS_IMPL_ALIGN_PTR(size) __attribute__((aligned(size))) - #endif +#if !defined(KOKKOS_IMPL_ALIGN_PTR) +#define KOKKOS_IMPL_ALIGN_PTR(size) __attribute__((aligned(size))) +#endif #endif //---------------------------------------------------------------------------- // GNU Compiler macros -#if defined( KOKKOS_COMPILER_GNU ) - //#define KOKKOS_ENABLE_PRAGMA_UNROLL 1 - //#define KOKKOS_ENABLE_PRAGMA_IVDEP 1 - //#define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1 - //#define KOKKOS_ENABLE_PRAGMA_VECTOR 1 - //#define KOKKOS_ENABLE_PRAGMA_SIMD 1 +#if defined(KOKKOS_COMPILER_GNU) +//#define KOKKOS_ENABLE_PRAGMA_UNROLL 1 +//#define KOKKOS_ENABLE_PRAGMA_IVDEP 1 +//#define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1 +//#define KOKKOS_ENABLE_PRAGMA_VECTOR 1 +//#define KOKKOS_ENABLE_PRAGMA_SIMD 1 - #if defined( KOKKOS_ARCH_AVX512MIC ) - #define KOKKOS_ENABLE_RFO_PREFETCH 1 - #endif +#if defined(KOKKOS_ARCH_AVX512MIC) +#define KOKKOS_ENABLE_RFO_PREFETCH 1 +#endif - #if !defined( KOKKOS_FORCEINLINE_FUNCTION ) - #define KOKKOS_FORCEINLINE_FUNCTION inline __attribute__((always_inline)) - #endif +#if !defined(KOKKOS_FORCEINLINE_FUNCTION) +#define KOKKOS_FORCEINLINE_FUNCTION inline __attribute__((always_inline)) +#define KOKKOS_IMPL_FORCEINLINE __attribute__((always_inline)) +#endif - #define KOKKOS_RESTRICT __restrict__ +#define KOKKOS_RESTRICT __restrict__ - #if !defined( KOKKOS_ENABLE_ASM ) && !defined( __PGIC__ ) && \ - ( defined( __amd64 ) || defined( __amd64__ ) || \ - defined( __x86_64 ) || defined( __x86_64__ ) || \ - defined(__PPC64__) ) - #define KOKKOS_ENABLE_ASM 1 - #endif +#if !defined(KOKKOS_ENABLE_ASM) && !defined(__PGIC__) && \ + (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || \ + defined(__x86_64__) || defined(__PPC64__)) +#define KOKKOS_ENABLE_ASM 1 +#endif #endif //---------------------------------------------------------------------------- -#if defined( KOKKOS_COMPILER_PGI ) - #define KOKKOS_ENABLE_PRAGMA_UNROLL 1 - #define KOKKOS_ENABLE_PRAGMA_IVDEP 1 - //#define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1 - #define KOKKOS_ENABLE_PRAGMA_VECTOR 1 - //#define KOKKOS_ENABLE_PRAGMA_SIMD 1 +#if defined(KOKKOS_COMPILER_PGI) +#define KOKKOS_ENABLE_PRAGMA_UNROLL 1 +#define KOKKOS_ENABLE_PRAGMA_IVDEP 1 +//#define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1 +#define KOKKOS_ENABLE_PRAGMA_VECTOR 1 +//#define KOKKOS_ENABLE_PRAGMA_SIMD 1 #endif //---------------------------------------------------------------------------- -#if defined( KOKKOS_COMPILER_NVCC ) - #if defined( __CUDA_ARCH__ ) - #define KOKKOS_ENABLE_PRAGMA_UNROLL 1 - #endif +#if defined(KOKKOS_COMPILER_NVCC) +#if defined(__CUDA_ARCH__) +#define KOKKOS_ENABLE_PRAGMA_UNROLL 1 +#endif #endif //---------------------------------------------------------------------------- // Define function marking macros if compiler specific macros are undefined: -#if !defined( KOKKOS_FORCEINLINE_FUNCTION ) - define KOKKOS_FORCEINLINE_FUNCTION inline +#if !defined(KOKKOS_FORCEINLINE_FUNCTION) +#define KOKKOS_FORCEINLINE_FUNCTION inline #endif -#if !defined( KOKKOS_INLINE_FUNCTION ) - #define KOKKOS_INLINE_FUNCTION inline +#if !defined(KOKKOS_IMPL_FORCEINLINE) +#define KOKKOS_IMPL_FORCEINLINE inline #endif -#if !defined( KOKKOS_FUNCTION ) - #define KOKKOS_FUNCTION /**/ +#if !defined(KOKKOS_INLINE_FUNCTION) +#define KOKKOS_INLINE_FUNCTION inline #endif -#if !defined( KOKKOS_INLINE_FUNCTION_DELETED ) - #define KOKKOS_INLINE_FUNCTION_DELETED inline +#if !defined(KOKKOS_FUNCTION) +#define KOKKOS_FUNCTION /**/ +#endif + +#if !defined(KOKKOS_INLINE_FUNCTION_DELETED) +#define KOKKOS_INLINE_FUNCTION_DELETED inline #endif //---------------------------------------------------------------------------- // Define empty macro for restrict if necessary: -#if !defined( KOKKOS_RESTRICT ) - #define KOKKOS_RESTRICT +#if !defined(KOKKOS_RESTRICT) +#define KOKKOS_RESTRICT #endif //---------------------------------------------------------------------------- // Define Macro for alignment: -#if ! defined( KOKKOS_MEMORY_ALIGNMENT ) - #define KOKKOS_MEMORY_ALIGNMENT 64 +#if !defined(KOKKOS_MEMORY_ALIGNMENT) +#define KOKKOS_MEMORY_ALIGNMENT 64 #endif -#if ! defined( KOKKOS_MEMORY_ALIGNMENT_THRESHOLD ) - #define KOKKOS_MEMORY_ALIGNMENT_THRESHOLD 1 +#if !defined(KOKKOS_MEMORY_ALIGNMENT_THRESHOLD) +#define KOKKOS_MEMORY_ALIGNMENT_THRESHOLD 1 #endif -#if !defined( KOKKOS_IMPL_ALIGN_PTR ) - #define KOKKOS_IMPL_ALIGN_PTR(size) /* */ +#if !defined(KOKKOS_IMPL_ALIGN_PTR) +#define KOKKOS_IMPL_ALIGN_PTR(size) /* */ #endif //---------------------------------------------------------------------------- // Determine the default execution space for parallel dispatch. // There is zero or one default execution space specified. -#if 1 < ( ( defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_CUDA ) ? 1 : 0 ) + \ - ( defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_ROCM ) ? 1 : 0 ) + \ - ( defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMPTARGET ) ? 1 : 0 ) + \ - ( defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP ) ? 1 : 0 ) + \ - ( defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS ) ? 1 : 0 ) + \ - ( defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_QTHREADS ) ? 1 : 0 ) + \ - ( defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX ) ? 1 : 0 ) + \ - ( defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL ) ? 1 : 0 ) ) - #error "More than one KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_* specified." +#if 1 < ((defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_CUDA) ? 1 : 0) + \ + (defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_ROCM) ? 1 : 0) + \ + (defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMPTARGET) ? 1 : 0) + \ + (defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP) ? 1 : 0) + \ + (defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS) ? 1 : 0) + \ + (defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_QTHREADS) ? 1 : 0) + \ + (defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX) ? 1 : 0) + \ + (defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL) ? 1 : 0)) +#error "More than one KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_* specified." #endif // If default is not specified then chose from enabled execution spaces. // Priority: CUDA, OPENMP, THREADS, QTHREADS, HPX, SERIAL -#if defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_CUDA ) -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_ROCM ) -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMPTARGET ) -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP ) -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS ) +#if defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_CUDA) +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_ROCM) +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMPTARGET) +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP) +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS) //#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_QTHREADS ) -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX ) -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL ) -#elif defined( KOKKOS_ENABLE_CUDA ) - #define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_CUDA -#elif defined( KOKKOS_ENABLE_ROCM ) - #define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_ROCM -#elif defined( KOKKOS_ENABLE_OPENMPTARGET ) - #define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMPTARGET -#elif defined( KOKKOS_ENABLE_OPENMP ) - #define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP -#elif defined( KOKKOS_ENABLE_THREADS ) - #define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX) +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL) +#elif defined(KOKKOS_ENABLE_CUDA) +#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_CUDA +#elif defined(KOKKOS_ENABLE_ROCM) +#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_ROCM +#elif defined(KOKKOS_ENABLE_OPENMPTARGET) +#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMPTARGET +#elif defined(KOKKOS_ENABLE_OPENMP) +#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP +#elif defined(KOKKOS_ENABLE_THREADS) +#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS //#elif defined( KOKKOS_ENABLE_QTHREADS ) // #define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_QTHREADS -#elif defined( KOKKOS_ENABLE_HPX ) - #define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX +#elif defined(KOKKOS_ENABLE_HPX) +#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX #else - #define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL +#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL #endif //---------------------------------------------------------------------------- // Determine for what space the code is being compiled: -#if defined( __CUDACC__ ) && defined( __CUDA_ARCH__ ) && defined( KOKKOS_ENABLE_CUDA ) - #define KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_CUDA -#elif defined( __HCC__ ) && defined( __HCC_ACCELERATOR__ ) && defined( KOKKOS_ENABLE_ROCM ) - #define KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_ROCM_GPU +#if defined(__CUDACC__) && defined(__CUDA_ARCH__) && defined(KOKKOS_ENABLE_CUDA) +#define KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_CUDA +#elif defined(__HCC__) && defined(__HCC_ACCELERATOR__) && \ + defined(KOKKOS_ENABLE_ROCM) +#define KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_ROCM_GPU #else - #define KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST +#define KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST #endif //---------------------------------------------------------------------------- -#if ( defined( _POSIX_C_SOURCE ) && _POSIX_C_SOURCE >= 200112L ) || \ - ( defined( _XOPEN_SOURCE ) && _XOPEN_SOURCE >= 600 ) - #if defined( KOKKOS_ENABLE_PERFORMANCE_POSIX_MEMALIGN ) - #define KOKKOS_ENABLE_POSIX_MEMALIGN 1 - #endif +#if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || \ + (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600) +#if defined(KOKKOS_ENABLE_PERFORMANCE_POSIX_MEMALIGN) +#define KOKKOS_ENABLE_POSIX_MEMALIGN 1 +#endif #endif //---------------------------------------------------------------------------- @@ -547,53 +561,65 @@ // and use relocateable device code to enable the task policy. // nvcc relocatable device code option: --relocatable-device-code=true -#if ( defined( KOKKOS_ENABLE_CUDA ) ) - #if ( 8000 <= CUDA_VERSION ) && defined( KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE ) - #define KOKKOS_ENABLE_TASKDAG - #endif +#if (defined(KOKKOS_ENABLE_CUDA)) +#if (8000 <= CUDA_VERSION) && \ + defined(KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE) +#define KOKKOS_ENABLE_TASKDAG +#endif #else - #define KOKKOS_ENABLE_TASKDAG +#define KOKKOS_ENABLE_TASKDAG #endif - -#if defined ( KOKKOS_ENABLE_CUDA ) - #if ( 9000 <= CUDA_VERSION ) - #define KOKKOS_IMPL_CUDA_VERSION_9_WORKAROUND - #if ( __CUDA_ARCH__ ) - #define KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - #endif - #endif +#if defined(KOKKOS_ENABLE_CUDA) +#if (9000 <= CUDA_VERSION) +#define KOKKOS_IMPL_CUDA_VERSION_9_WORKAROUND +#if (__CUDA_ARCH__) +#define KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK +#endif +#endif #endif #define KOKKOS_INVALID_INDEX (~std::size_t(0)) #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - #define KOKKOS_IMPL_CTOR_DEFAULT_ARG 0 +#define KOKKOS_IMPL_CTOR_DEFAULT_ARG 0 #else - #define KOKKOS_IMPL_CTOR_DEFAULT_ARG KOKKOS_INVALID_INDEX +#define KOKKOS_IMPL_CTOR_DEFAULT_ARG KOKKOS_INVALID_INDEX #endif -#if (defined(KOKKOS_ENABLE_CXX14) || defined(KOKKOS_ENABLE_CXX17) || defined(KOKKOS_ENABLE_CXX20)) - #define KOKKOS_CONSTEXPR_14 constexpr - #define KOKKOS_DEPRECATED [[deprecated]] - #define KOKKOS_DEPRECATED_TRAILING_ATTRIBUTE +#if (defined(KOKKOS_ENABLE_CXX14) || defined(KOKKOS_ENABLE_CXX17) || \ + defined(KOKKOS_ENABLE_CXX20)) +#define KOKKOS_CONSTEXPR_14 constexpr +#define KOKKOS_DEPRECATED [[deprecated]] +#define KOKKOS_DEPRECATED_TRAILING_ATTRIBUTE +#else +#define KOKKOS_CONSTEXPR_14 +#if defined(KOKKOS_COMPILER_GNU) || defined(KOKKOS_COMPILER_CLANG) +#define KOKKOS_DEPRECATED +#define KOKKOS_DEPRECATED_TRAILING_ATTRIBUTE __attribute__((deprecated)) #else - #define KOKKOS_CONSTEXPR_14 - #if defined(KOKKOS_COMPILER_GNU) || defined(KOKKOS_COMPILER_CLANG) - #define KOKKOS_DEPRECATED - #define KOKKOS_DEPRECATED_TRAILING_ATTRIBUTE __attribute__ ((deprecated)) - #else - #define KOKKOS_DEPRECATED - #define KOKKOS_DEPRECATED_TRAILING_ATTRIBUTE - #endif +#define KOKKOS_DEPRECATED +#define KOKKOS_DEPRECATED_TRAILING_ATTRIBUTE +#endif #endif - // DJS 05/28/2019: Bugfix: Issue 2155 -// Use KOKKOS_ENABLE_CUDA_LDG_INTRINSIC to avoid memory leak in RandomAccess View +// Use KOKKOS_ENABLE_CUDA_LDG_INTRINSIC to avoid memory leak in RandomAccess +// View #if defined(KOKKOS_ENABLE_CUDA) && !defined(KOKKOS_ENABLE_CUDA_LDG_INTRINSIC) - #define KOKKOS_ENABLE_CUDA_LDG_INTRINSIC +#define KOKKOS_ENABLE_CUDA_LDG_INTRINSIC #endif -#endif // #ifndef KOKKOS_MACROS_HPP +#if defined(KOKKOS_ENABLE_CXX17) || defined(KOKKOS_ENABLE_CXX20) +#define KOKKOS_ATTRIBUTE_NODISCARD [[nodiscard]] +#else +#define KOKKOS_ATTRIBUTE_NODISCARD +#endif + +#if defined(KOKKOS_COMPILER_GNU) || defined(KOKKOS_COMPILER_CLANG) || \ + defined(KOKKOS_COMPILER_INTEL) || defined(KOKKOS_COMPILER_PGI) +#define KOKKOS_IMPL_ENABLE_STACKTRACE +#define KOKKOS_IMPL_ENABLE_CXXABI +#endif +#endif // #ifndef KOKKOS_MACROS_HPP diff --git a/lib/kokkos/core/src/Kokkos_MasterLock.hpp b/lib/kokkos/core/src/Kokkos_MasterLock.hpp index 2db22d2fdd..3c45e131a0 100644 --- a/lib/kokkos/core/src/Kokkos_MasterLock.hpp +++ b/lib/kokkos/core/src/Kokkos_MasterLock.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -46,7 +47,8 @@ #include -namespace Kokkos { namespace Experimental { +namespace Kokkos { +namespace Experimental { // my be used to coordinate work between master instances // SHOULD NOT be used within a parallel algorithm @@ -67,7 +69,7 @@ namespace Kokkos { namespace Experimental { template class MasterLock; -}} // namespace Kokkos::Experimental - -#endif //KOKKOS_MASTER_LOCK_HPP +} // namespace Experimental +} // namespace Kokkos +#endif // KOKKOS_MASTER_LOCK_HPP diff --git a/lib/kokkos/core/src/Kokkos_MemoryPool.hpp b/lib/kokkos/core/src/Kokkos_MemoryPool.hpp index 365db2baec..5228f36612 100644 --- a/lib/kokkos/core/src/Kokkos_MemoryPool.hpp +++ b/lib/kokkos/core/src/Kokkos_MemoryPool.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -55,37 +56,34 @@ namespace Kokkos { namespace Impl { /* Report violation of size constraints: * min_block_alloc_size <= max_block_alloc_size - * max_block_alloc_size <= min_superblock_size + * max_block_alloc_size <= min_superblock_size * min_superblock_size <= max_superblock_size * min_superblock_size <= min_total_alloc_size - * min_superblock_size <= min_block_alloc_size * + * min_superblock_size <= min_block_alloc_size * * max_block_per_superblock */ -void memory_pool_bounds_verification - ( size_t min_block_alloc_size - , size_t max_block_alloc_size - , size_t min_superblock_size - , size_t max_superblock_size - , size_t max_block_per_superblock - , size_t min_total_alloc_size - ); -} -} +void memory_pool_bounds_verification(size_t min_block_alloc_size, + size_t max_block_alloc_size, + size_t min_superblock_size, + size_t max_superblock_size, + size_t max_block_per_superblock, + size_t min_total_alloc_size); +} // namespace Impl +} // namespace Kokkos namespace Kokkos { -template< typename DeviceType > +template class MemoryPool { -private: + private: + typedef typename Kokkos::Impl::concurrent_bitset CB; - typedef typename Kokkos::Impl::concurrent_bitset CB ; - - enum : uint32_t { bits_per_int_lg2 = CB::bits_per_int_lg2 }; - enum : uint32_t { state_shift = CB::state_shift }; - enum : uint32_t { state_used_mask = CB::state_used_mask }; + enum : uint32_t { bits_per_int_lg2 = CB::bits_per_int_lg2 }; + enum : uint32_t { state_shift = CB::state_shift }; + enum : uint32_t { state_used_mask = CB::state_used_mask }; enum : uint32_t { state_header_mask = CB::state_header_mask }; enum : uint32_t { max_bit_count_lg2 = CB::max_bit_count_lg2 }; - enum : uint32_t { max_bit_count = CB::max_bit_count }; + enum : uint32_t { max_bit_count = CB::max_bit_count }; enum : uint32_t { HINT_PER_BLOCK_SIZE = 2 }; @@ -109,231 +107,219 @@ private: * Thus A_block_size < B_block_size <=> A_block_state > B_block_state */ - typedef typename DeviceType::memory_space base_memory_space ; - - enum { accessible = - Kokkos::Impl::MemorySpaceAccess< Kokkos::HostSpace - , base_memory_space >::accessible }; - - typedef Kokkos::Impl::SharedAllocationTracker Tracker ; - typedef Kokkos::Impl::SharedAllocationRecord - < base_memory_space > Record ; + typedef typename DeviceType::memory_space base_memory_space; - Tracker m_tracker ; - uint32_t * m_sb_state_array ; - uint32_t m_sb_state_size ; - uint32_t m_sb_size_lg2 ; - uint32_t m_max_block_size_lg2 ; - uint32_t m_min_block_size_lg2 ; - int32_t m_sb_count ; - int32_t m_hint_offset ; // Offset to K * #block_size array of hints - int32_t m_data_offset ; // Offset to 0th superblock data - int32_t m_unused_padding ; - -public: + enum { + accessible = Kokkos::Impl::MemorySpaceAccess::accessible + }; + typedef Kokkos::Impl::SharedAllocationTracker Tracker; + typedef Kokkos::Impl::SharedAllocationRecord Record; + + Tracker m_tracker; + uint32_t *m_sb_state_array; + uint32_t m_sb_state_size; + uint32_t m_sb_size_lg2; + uint32_t m_max_block_size_lg2; + uint32_t m_min_block_size_lg2; + int32_t m_sb_count; + int32_t m_hint_offset; // Offset to K * #block_size array of hints + int32_t m_data_offset; // Offset to 0th superblock data + int32_t m_unused_padding; + + public: using memory_space = typename DeviceType::memory_space; /**\brief The maximum size of a superblock and block */ - enum : uint32_t { max_superblock_size = 1LU << 31 /* 2 gigabytes */ }; + enum : uint32_t { max_superblock_size = 1LU << 31 /* 2 gigabytes */ }; enum : uint32_t { max_block_per_superblock = max_bit_count }; //-------------------------------------------------------------------------- KOKKOS_INLINE_FUNCTION - bool operator==(MemoryPool const& other) const - { return m_sb_state_array == other.m_sb_state_array; } + bool operator==(MemoryPool const &other) const { + return m_sb_state_array == other.m_sb_state_array; + } KOKKOS_INLINE_FUNCTION - size_t capacity() const noexcept - { return size_t(m_sb_count) << m_sb_size_lg2 ; } + size_t capacity() const noexcept { + return size_t(m_sb_count) << m_sb_size_lg2; + } KOKKOS_INLINE_FUNCTION - size_t min_block_size() const noexcept - { return ( 1LU << m_min_block_size_lg2 ); } + size_t min_block_size() const noexcept { + return (1LU << m_min_block_size_lg2); + } KOKKOS_INLINE_FUNCTION - size_t max_block_size() const noexcept - { return ( 1LU << m_max_block_size_lg2 ); } + size_t max_block_size() const noexcept { + return (1LU << m_max_block_size_lg2); + } struct usage_statistics { - size_t capacity_bytes ; ///< Capacity in bytes - size_t superblock_bytes ; ///< Superblock size in bytes - size_t max_block_bytes ; ///< Maximum block size in bytes - size_t min_block_bytes ; ///< Minimum block size in bytes - size_t capacity_superblocks ; ///< Number of superblocks - size_t consumed_superblocks ; ///< Superblocks assigned to allocations - size_t consumed_blocks ; ///< Number of allocations - size_t consumed_bytes ; ///< Bytes allocated - size_t reserved_blocks ; ///< Unallocated blocks in assigned superblocks - size_t reserved_bytes ; ///< Unallocated bytes in assigned superblocks + size_t capacity_bytes; ///< Capacity in bytes + size_t superblock_bytes; ///< Superblock size in bytes + size_t max_block_bytes; ///< Maximum block size in bytes + size_t min_block_bytes; ///< Minimum block size in bytes + size_t capacity_superblocks; ///< Number of superblocks + size_t consumed_superblocks; ///< Superblocks assigned to allocations + size_t consumed_blocks; ///< Number of allocations + size_t consumed_bytes; ///< Bytes allocated + size_t reserved_blocks; ///< Unallocated blocks in assigned superblocks + size_t reserved_bytes; ///< Unallocated bytes in assigned superblocks }; - void get_usage_statistics( usage_statistics & stats ) const - { - Kokkos::HostSpace host ; + void get_usage_statistics(usage_statistics &stats) const { + Kokkos::HostSpace host; - const size_t alloc_size = m_hint_offset * sizeof(uint32_t); + const size_t alloc_size = m_hint_offset * sizeof(uint32_t); - uint32_t * const sb_state_array = - accessible ? m_sb_state_array : (uint32_t *) host.allocate(alloc_size); + uint32_t *const sb_state_array = + accessible ? m_sb_state_array : (uint32_t *)host.allocate(alloc_size); - if ( ! accessible ) { - Kokkos::Impl::DeepCopy< Kokkos::HostSpace , base_memory_space > - ( sb_state_array , m_sb_state_array , alloc_size ); - } - - stats.superblock_bytes = ( 1LU << m_sb_size_lg2 ); - stats.max_block_bytes = ( 1LU << m_max_block_size_lg2 ); - stats.min_block_bytes = ( 1LU << m_min_block_size_lg2 ); - stats.capacity_bytes = stats.superblock_bytes * m_sb_count ; - stats.capacity_superblocks = m_sb_count ; - stats.consumed_superblocks = 0 ; - stats.consumed_blocks = 0 ; - stats.consumed_bytes = 0 ; - stats.reserved_blocks = 0 ; - stats.reserved_bytes = 0 ; - - const uint32_t * sb_state_ptr = sb_state_array ; - - for ( int32_t i = 0 ; i < m_sb_count - ; ++i , sb_state_ptr += m_sb_state_size ) { - - const uint32_t block_count_lg2 = (*sb_state_ptr) >> state_shift ; - - if ( block_count_lg2 ) { - const uint32_t block_count = 1u << block_count_lg2 ; - const uint32_t block_size_lg2 = m_sb_size_lg2 - block_count_lg2 ; - const uint32_t block_size = 1u << block_size_lg2 ; - const uint32_t block_used = (*sb_state_ptr) & state_used_mask ; - - stats.consumed_superblocks++ ; - stats.consumed_blocks += block_used ; - stats.consumed_bytes += block_used * block_size ; - stats.reserved_blocks += block_count - block_used ; - stats.reserved_bytes += (block_count - block_used ) * block_size ; - } - } + if (!accessible) { + Kokkos::Impl::DeepCopy( + sb_state_array, m_sb_state_array, alloc_size); + } - if ( ! accessible ) { - host.deallocate( sb_state_array, alloc_size ); + stats.superblock_bytes = (1LU << m_sb_size_lg2); + stats.max_block_bytes = (1LU << m_max_block_size_lg2); + stats.min_block_bytes = (1LU << m_min_block_size_lg2); + stats.capacity_bytes = stats.superblock_bytes * m_sb_count; + stats.capacity_superblocks = m_sb_count; + stats.consumed_superblocks = 0; + stats.consumed_blocks = 0; + stats.consumed_bytes = 0; + stats.reserved_blocks = 0; + stats.reserved_bytes = 0; + + const uint32_t *sb_state_ptr = sb_state_array; + + for (int32_t i = 0; i < m_sb_count; ++i, sb_state_ptr += m_sb_state_size) { + const uint32_t block_count_lg2 = (*sb_state_ptr) >> state_shift; + + if (block_count_lg2) { + const uint32_t block_count = 1u << block_count_lg2; + const uint32_t block_size_lg2 = m_sb_size_lg2 - block_count_lg2; + const uint32_t block_size = 1u << block_size_lg2; + const uint32_t block_used = (*sb_state_ptr) & state_used_mask; + + stats.consumed_superblocks++; + stats.consumed_blocks += block_used; + stats.consumed_bytes += block_used * block_size; + stats.reserved_blocks += block_count - block_used; + stats.reserved_bytes += (block_count - block_used) * block_size; } } - void print_state( std::ostream & s ) const - { - Kokkos::HostSpace host ; - - const size_t alloc_size = m_hint_offset * sizeof(uint32_t); + if (!accessible) { + host.deallocate(sb_state_array, alloc_size); + } + } - uint32_t * const sb_state_array = - accessible ? m_sb_state_array : (uint32_t *) host.allocate(alloc_size); + void print_state(std::ostream &s) const { + Kokkos::HostSpace host; - if ( ! accessible ) { - Kokkos::Impl::DeepCopy< Kokkos::HostSpace , base_memory_space > - ( sb_state_array , m_sb_state_array , alloc_size ); - } + const size_t alloc_size = m_hint_offset * sizeof(uint32_t); - const uint32_t * sb_state_ptr = sb_state_array ; + uint32_t *const sb_state_array = + accessible ? m_sb_state_array : (uint32_t *)host.allocate(alloc_size); - s << "pool_size(" << ( size_t(m_sb_count) << m_sb_size_lg2 ) << ")" - << " superblock_size(" << ( 1LU << m_sb_size_lg2 ) << ")" << std::endl ; + if (!accessible) { + Kokkos::Impl::DeepCopy( + sb_state_array, m_sb_state_array, alloc_size); + } - for ( int32_t i = 0 ; i < m_sb_count - ; ++i , sb_state_ptr += m_sb_state_size ) { + const uint32_t *sb_state_ptr = sb_state_array; - if ( *sb_state_ptr ) { + s << "pool_size(" << (size_t(m_sb_count) << m_sb_size_lg2) << ")" + << " superblock_size(" << (1LU << m_sb_size_lg2) << ")" << std::endl; - const uint32_t block_count_lg2 = (*sb_state_ptr) >> state_shift ; - const uint32_t block_size_lg2 = m_sb_size_lg2 - block_count_lg2 ; - const uint32_t block_count = 1u << block_count_lg2 ; - const uint32_t block_used = (*sb_state_ptr) & state_used_mask ; + for (int32_t i = 0; i < m_sb_count; ++i, sb_state_ptr += m_sb_state_size) { + if (*sb_state_ptr) { + const uint32_t block_count_lg2 = (*sb_state_ptr) >> state_shift; + const uint32_t block_size_lg2 = m_sb_size_lg2 - block_count_lg2; + const uint32_t block_count = 1u << block_count_lg2; + const uint32_t block_used = (*sb_state_ptr) & state_used_mask; - s << "Superblock[ " << i << " / " << m_sb_count << " ] {" - << " block_size(" << ( 1 << block_size_lg2 ) << ")" - << " block_count( " << block_used - << " / " << block_count << " )" - << std::endl ; - } + s << "Superblock[ " << i << " / " << m_sb_count << " ] {" + << " block_size(" << (1 << block_size_lg2) << ")" + << " block_count( " << block_used << " / " << block_count << " )" + << std::endl; } + } - if ( ! accessible ) { - host.deallocate( sb_state_array, alloc_size ); - } + if (!accessible) { + host.deallocate(sb_state_array, alloc_size); } + } //-------------------------------------------------------------------------- #ifdef KOKKOS_CUDA_9_DEFAULTED_BUG_WORKAROUND - KOKKOS_INLINE_FUNCTION MemoryPool( MemoryPool && rhs ) - : m_tracker(std::move(rhs.m_tracker)) - , m_sb_state_array(std::move(rhs.m_sb_state_array)) - , m_sb_state_size(std::move(rhs.m_sb_state_size)) - , m_sb_size_lg2(std::move(rhs.m_sb_size_lg2)) - , m_max_block_size_lg2(std::move(rhs.m_max_block_size_lg2)) - , m_min_block_size_lg2(std::move(rhs.m_min_block_size_lg2)) - , m_sb_count(std::move(rhs.m_sb_count)) - , m_hint_offset(std::move(rhs.m_hint_offset)) - , m_data_offset(std::move(rhs.m_data_offset)) - { - } - KOKKOS_INLINE_FUNCTION MemoryPool( const MemoryPool & rhs ) - : m_tracker(rhs.m_tracker) - , m_sb_state_array(rhs.m_sb_state_array) - , m_sb_state_size(rhs.m_sb_state_size) - , m_sb_size_lg2(rhs.m_sb_size_lg2) - , m_max_block_size_lg2(rhs.m_max_block_size_lg2) - , m_min_block_size_lg2(rhs.m_min_block_size_lg2) - , m_sb_count(rhs.m_sb_count) - , m_hint_offset(rhs.m_hint_offset) - , m_data_offset(rhs.m_data_offset) - { - } - KOKKOS_INLINE_FUNCTION MemoryPool & operator = ( MemoryPool && rhs ) - { - m_tracker = std::move(rhs.m_tracker); - m_sb_state_array = std::move(rhs.m_sb_state_array); - m_sb_state_size = std::move(rhs.m_sb_state_size); - m_sb_size_lg2 = std::move(rhs.m_sb_size_lg2); + KOKKOS_INLINE_FUNCTION MemoryPool(MemoryPool &&rhs) + : m_tracker(std::move(rhs.m_tracker)), + m_sb_state_array(std::move(rhs.m_sb_state_array)), + m_sb_state_size(std::move(rhs.m_sb_state_size)), + m_sb_size_lg2(std::move(rhs.m_sb_size_lg2)), + m_max_block_size_lg2(std::move(rhs.m_max_block_size_lg2)), + m_min_block_size_lg2(std::move(rhs.m_min_block_size_lg2)), + m_sb_count(std::move(rhs.m_sb_count)), + m_hint_offset(std::move(rhs.m_hint_offset)), + m_data_offset(std::move(rhs.m_data_offset)) {} + KOKKOS_INLINE_FUNCTION MemoryPool(const MemoryPool &rhs) + : m_tracker(rhs.m_tracker), + m_sb_state_array(rhs.m_sb_state_array), + m_sb_state_size(rhs.m_sb_state_size), + m_sb_size_lg2(rhs.m_sb_size_lg2), + m_max_block_size_lg2(rhs.m_max_block_size_lg2), + m_min_block_size_lg2(rhs.m_min_block_size_lg2), + m_sb_count(rhs.m_sb_count), + m_hint_offset(rhs.m_hint_offset), + m_data_offset(rhs.m_data_offset) {} + KOKKOS_INLINE_FUNCTION MemoryPool &operator=(MemoryPool &&rhs) { + m_tracker = std::move(rhs.m_tracker); + m_sb_state_array = std::move(rhs.m_sb_state_array); + m_sb_state_size = std::move(rhs.m_sb_state_size); + m_sb_size_lg2 = std::move(rhs.m_sb_size_lg2); m_max_block_size_lg2 = std::move(rhs.m_max_block_size_lg2); m_min_block_size_lg2 = std::move(rhs.m_min_block_size_lg2); - m_sb_count = std::move(rhs.m_sb_count); - m_hint_offset = std::move(rhs.m_hint_offset); - m_data_offset = std::move(rhs.m_data_offset); + m_sb_count = std::move(rhs.m_sb_count); + m_hint_offset = std::move(rhs.m_hint_offset); + m_data_offset = std::move(rhs.m_data_offset); return *this; } - KOKKOS_INLINE_FUNCTION MemoryPool & operator = ( const MemoryPool & rhs ) - { - m_tracker = rhs.m_tracker; - m_sb_state_array = rhs.m_sb_state_array; - m_sb_state_size = rhs.m_sb_state_size; - m_sb_size_lg2 = rhs.m_sb_size_lg2; + KOKKOS_INLINE_FUNCTION MemoryPool &operator=(const MemoryPool &rhs) { + m_tracker = rhs.m_tracker; + m_sb_state_array = rhs.m_sb_state_array; + m_sb_state_size = rhs.m_sb_state_size; + m_sb_size_lg2 = rhs.m_sb_size_lg2; m_max_block_size_lg2 = rhs.m_max_block_size_lg2; m_min_block_size_lg2 = rhs.m_min_block_size_lg2; - m_sb_count = rhs.m_sb_count; - m_hint_offset = rhs.m_hint_offset; - m_data_offset = rhs.m_data_offset; + m_sb_count = rhs.m_sb_count; + m_hint_offset = rhs.m_hint_offset; + m_data_offset = rhs.m_data_offset; return *this; } #else - KOKKOS_INLINE_FUNCTION MemoryPool( MemoryPool && ) = default ; - KOKKOS_INLINE_FUNCTION MemoryPool( const MemoryPool & ) = default ; - KOKKOS_INLINE_FUNCTION MemoryPool & operator = ( MemoryPool && ) = default ; - KOKKOS_INLINE_FUNCTION MemoryPool & operator = ( const MemoryPool & ) = default ; + KOKKOS_INLINE_FUNCTION MemoryPool(MemoryPool &&) = default; + KOKKOS_INLINE_FUNCTION MemoryPool(const MemoryPool &) = default; + KOKKOS_INLINE_FUNCTION MemoryPool &operator=(MemoryPool &&) = default; + KOKKOS_INLINE_FUNCTION MemoryPool &operator=(const MemoryPool &) = default; #endif KOKKOS_INLINE_FUNCTION MemoryPool() - : m_tracker() - , m_sb_state_array(0) - , m_sb_state_size(0) - , m_sb_size_lg2(0) - , m_max_block_size_lg2(0) - , m_min_block_size_lg2(0) - , m_sb_count(0) - , m_hint_offset(0) - , m_data_offset(0) - , m_unused_padding(0) - {} + : m_tracker(), + m_sb_state_array(0), + m_sb_state_size(0), + m_sb_size_lg2(0), + m_max_block_size_lg2(0), + m_min_block_size_lg2(0), + m_sb_count(0), + m_hint_offset(0), + m_data_offset(0), + m_unused_padding(0) {} /**\brief Allocate a memory pool from 'memspace'. * @@ -349,221 +335,199 @@ public: * is also a power-of-two. These roundings are made to enable * significant runtime performance improvements. */ - MemoryPool( const base_memory_space & memspace - , const size_t min_total_alloc_size - , size_t min_block_alloc_size = 0 - , size_t max_block_alloc_size = 0 - , size_t min_superblock_size = 0 - ) - : m_tracker() - , m_sb_state_array(0) - , m_sb_state_size(0) - , m_sb_size_lg2(0) - , m_max_block_size_lg2(0) - , m_min_block_size_lg2(0) - , m_sb_count(0) - , m_hint_offset(0) - , m_data_offset(0) - , m_unused_padding(0) - { - const uint32_t int_align_lg2 = 3 ; /* align as int[8] */ - const uint32_t int_align_mask = ( 1u << int_align_lg2 ) - 1 ; - const uint32_t default_min_block_size = 1u << 6 ; /* 64 bytes */ - const uint32_t default_max_block_size = 1u << 12 ;/* 4k bytes */ - const uint32_t default_min_superblock_size = 1u << 20 ;/* 1M bytes */ - - //-------------------------------------------------- - // Default block and superblock sizes: - - if ( 0 == min_block_alloc_size ) { - // Default all sizes: - - min_superblock_size = - std::min( size_t(default_min_superblock_size) - , min_total_alloc_size ); - - min_block_alloc_size = - std::min( size_t(default_min_block_size) - , min_superblock_size ); - - max_block_alloc_size = - std::min( size_t(default_max_block_size) - , min_superblock_size ); - } - else if ( 0 == min_superblock_size ) { - - // Choose superblock size as minimum of: - // max_block_per_superblock * min_block_size - // max_superblock_size - // min_total_alloc_size + MemoryPool(const base_memory_space &memspace, + const size_t min_total_alloc_size, size_t min_block_alloc_size = 0, + size_t max_block_alloc_size = 0, size_t min_superblock_size = 0) + : m_tracker(), + m_sb_state_array(0), + m_sb_state_size(0), + m_sb_size_lg2(0), + m_max_block_size_lg2(0), + m_min_block_size_lg2(0), + m_sb_count(0), + m_hint_offset(0), + m_data_offset(0), + m_unused_padding(0) { + const uint32_t int_align_lg2 = 3; /* align as int[8] */ + const uint32_t int_align_mask = (1u << int_align_lg2) - 1; + const uint32_t default_min_block_size = 1u << 6; /* 64 bytes */ + const uint32_t default_max_block_size = 1u << 12; /* 4k bytes */ + const uint32_t default_min_superblock_size = 1u << 20; /* 1M bytes */ + + //-------------------------------------------------- + // Default block and superblock sizes: + + if (0 == min_block_alloc_size) { + // Default all sizes: + + min_superblock_size = + std::min(size_t(default_min_superblock_size), min_total_alloc_size); + + min_block_alloc_size = + std::min(size_t(default_min_block_size), min_superblock_size); + + max_block_alloc_size = + std::min(size_t(default_max_block_size), min_superblock_size); + } else if (0 == min_superblock_size) { + // Choose superblock size as minimum of: + // max_block_per_superblock * min_block_size + // max_superblock_size + // min_total_alloc_size + + const size_t max_superblock = + min_block_alloc_size * max_block_per_superblock; + + min_superblock_size = + std::min(max_superblock, + std::min(size_t(max_superblock_size), min_total_alloc_size)); + } - const size_t max_superblock = - min_block_alloc_size * max_block_per_superblock ; + if (0 == max_block_alloc_size) { + max_block_alloc_size = min_superblock_size; + } - min_superblock_size = - std::min( max_superblock , - std::min( size_t(max_superblock_size) - , min_total_alloc_size ) ); - } + //-------------------------------------------------- - if ( 0 == max_block_alloc_size ) { - max_block_alloc_size = min_superblock_size ; - } + /* Enforce size constraints: + * min_block_alloc_size <= max_block_alloc_size + * max_block_alloc_size <= min_superblock_size + * min_superblock_size <= max_superblock_size + * min_superblock_size <= min_total_alloc_size + * min_superblock_size <= min_block_alloc_size * + * max_block_per_superblock + */ - //-------------------------------------------------- - - /* Enforce size constraints: - * min_block_alloc_size <= max_block_alloc_size - * max_block_alloc_size <= min_superblock_size - * min_superblock_size <= max_superblock_size - * min_superblock_size <= min_total_alloc_size - * min_superblock_size <= min_block_alloc_size * - * max_block_per_superblock - */ - - Kokkos::Impl::memory_pool_bounds_verification - ( min_block_alloc_size - , max_block_alloc_size - , min_superblock_size - , max_superblock_size - , max_block_per_superblock - , min_total_alloc_size - ); + Kokkos::Impl::memory_pool_bounds_verification( + min_block_alloc_size, max_block_alloc_size, min_superblock_size, + max_superblock_size, max_block_per_superblock, min_total_alloc_size); - //-------------------------------------------------- - // Block and superblock size is power of two: - // Maximum value is 'max_superblock_size' + //-------------------------------------------------- + // Block and superblock size is power of two: + // Maximum value is 'max_superblock_size' - m_min_block_size_lg2 = + m_min_block_size_lg2 = Kokkos::Impl::integral_power_of_two_that_contains(min_block_alloc_size); - m_max_block_size_lg2 = + m_max_block_size_lg2 = Kokkos::Impl::integral_power_of_two_that_contains(max_block_alloc_size); - - m_sb_size_lg2 = + + m_sb_size_lg2 = Kokkos::Impl::integral_power_of_two_that_contains(min_superblock_size); - { - // number of superblocks is multiple of superblock size that - // can hold min_total_alloc_size. + { + // number of superblocks is multiple of superblock size that + // can hold min_total_alloc_size. - const uint64_t sb_size_mask = ( 1LU << m_sb_size_lg2 ) - 1 ; + const uint64_t sb_size_mask = (1LU << m_sb_size_lg2) - 1; - m_sb_count = ( min_total_alloc_size + sb_size_mask ) >> m_sb_size_lg2 ; - } + m_sb_count = (min_total_alloc_size + sb_size_mask) >> m_sb_size_lg2; + } - { - // Any superblock can be assigned to the smallest size block - // Size the block bitset to maximum number of blocks + { + // Any superblock can be assigned to the smallest size block + // Size the block bitset to maximum number of blocks - const uint32_t max_block_count_lg2 = - m_sb_size_lg2 - m_min_block_size_lg2 ; + const uint32_t max_block_count_lg2 = m_sb_size_lg2 - m_min_block_size_lg2; - m_sb_state_size = - ( CB::buffer_bound_lg2( max_block_count_lg2 ) + int_align_mask ) & ~int_align_mask ; - } + m_sb_state_size = + (CB::buffer_bound_lg2(max_block_count_lg2) + int_align_mask) & + ~int_align_mask; + } - // Array of all superblock states + // Array of all superblock states - const size_t all_sb_state_size = - ( m_sb_count * m_sb_state_size + int_align_mask ) & ~int_align_mask ; + const size_t all_sb_state_size = + (m_sb_count * m_sb_state_size + int_align_mask) & ~int_align_mask; - // Number of block sizes + // Number of block sizes - const int32_t number_block_sizes = - 1 + m_max_block_size_lg2 - m_min_block_size_lg2 ; + const int32_t number_block_sizes = + 1 + m_max_block_size_lg2 - m_min_block_size_lg2; - // Array length for possible block sizes - // Hint array is one uint32_t per block size + // Array length for possible block sizes + // Hint array is one uint32_t per block size - const int32_t block_size_array_size = - ( number_block_sizes + int_align_mask ) & ~int_align_mask ; + const int32_t block_size_array_size = + (number_block_sizes + int_align_mask) & ~int_align_mask; - m_hint_offset = all_sb_state_size ; - m_data_offset = m_hint_offset + - block_size_array_size * HINT_PER_BLOCK_SIZE ; + m_hint_offset = all_sb_state_size; + m_data_offset = m_hint_offset + block_size_array_size * HINT_PER_BLOCK_SIZE; - // Allocation: + // Allocation: - const size_t header_size = m_data_offset * sizeof(uint32_t); - const size_t alloc_size = header_size + - ( size_t(m_sb_count) << m_sb_size_lg2 ); + const size_t header_size = m_data_offset * sizeof(uint32_t); + const size_t alloc_size = + header_size + (size_t(m_sb_count) << m_sb_size_lg2); - Record * rec = Record::allocate( memspace , "MemoryPool" , alloc_size ); + Record *rec = Record::allocate(memspace, "MemoryPool", alloc_size); - m_tracker.assign_allocated_record_to_uninitialized( rec ); + m_tracker.assign_allocated_record_to_uninitialized(rec); - m_sb_state_array = (uint32_t *) rec->data(); + m_sb_state_array = (uint32_t *)rec->data(); - Kokkos::HostSpace host ; + Kokkos::HostSpace host; - uint32_t * const sb_state_array = - accessible ? m_sb_state_array - : (uint32_t *) host.allocate(header_size); + uint32_t *const sb_state_array = + accessible ? m_sb_state_array : (uint32_t *)host.allocate(header_size); - for ( int32_t i = 0 ; i < m_data_offset ; ++i ) sb_state_array[i] = 0 ; + for (int32_t i = 0; i < m_data_offset; ++i) sb_state_array[i] = 0; - // Initial assignment of empty superblocks to block sizes: + // Initial assignment of empty superblocks to block sizes: - for ( int32_t i = 0 ; i < number_block_sizes ; ++i ) { - const uint32_t block_size_lg2 = i + m_min_block_size_lg2 ; - const uint32_t block_count_lg2 = m_sb_size_lg2 - block_size_lg2 ; - const uint32_t block_state = block_count_lg2 << state_shift ; - const uint32_t hint_begin = m_hint_offset + i * HINT_PER_BLOCK_SIZE ; + for (int32_t i = 0; i < number_block_sizes; ++i) { + const uint32_t block_size_lg2 = i + m_min_block_size_lg2; + const uint32_t block_count_lg2 = m_sb_size_lg2 - block_size_lg2; + const uint32_t block_state = block_count_lg2 << state_shift; + const uint32_t hint_begin = m_hint_offset + i * HINT_PER_BLOCK_SIZE; - // for block size index 'i': - // sb_id_hint = sb_state_array[ hint_begin ]; - // sb_id_begin = sb_state_array[ hint_begin + 1 ]; + // for block size index 'i': + // sb_id_hint = sb_state_array[ hint_begin ]; + // sb_id_begin = sb_state_array[ hint_begin + 1 ]; - const int32_t jbeg = ( i * m_sb_count ) / number_block_sizes ; - const int32_t jend = ( ( i + 1 ) * m_sb_count ) / number_block_sizes ; + const int32_t jbeg = (i * m_sb_count) / number_block_sizes; + const int32_t jend = ((i + 1) * m_sb_count) / number_block_sizes; - sb_state_array[ hint_begin ] = uint32_t(jbeg); - sb_state_array[ hint_begin + 1 ] = uint32_t(jbeg); + sb_state_array[hint_begin] = uint32_t(jbeg); + sb_state_array[hint_begin + 1] = uint32_t(jbeg); - for ( int32_t j = jbeg ; j < jend ; ++j ) { - sb_state_array[ j * m_sb_state_size ] = block_state ; - } + for (int32_t j = jbeg; j < jend; ++j) { + sb_state_array[j * m_sb_state_size] = block_state; } + } - // Write out initialized state: + // Write out initialized state: - if ( ! accessible ) { - Kokkos::Impl::DeepCopy< base_memory_space , Kokkos::HostSpace > - ( m_sb_state_array , sb_state_array , header_size ); + if (!accessible) { + Kokkos::Impl::DeepCopy( + m_sb_state_array, sb_state_array, header_size); - host.deallocate( sb_state_array, header_size ); - } - else { - Kokkos::memory_fence(); - } + host.deallocate(sb_state_array, header_size); + } else { + Kokkos::memory_fence(); } + } //-------------------------------------------------------------------------- -private: - + private: /* Given a size 'n' get the block size in which it can be allocated. * Restrict lower bound to minimum block size. */ KOKKOS_FORCEINLINE_FUNCTION - uint32_t get_block_size_lg2( uint32_t n ) const noexcept - { - const unsigned i = Kokkos::Impl::integral_power_of_two_that_contains( n ); - - return i < m_min_block_size_lg2 ? m_min_block_size_lg2 : i ; - } + uint32_t get_block_size_lg2(uint32_t n) const noexcept { + const unsigned i = Kokkos::Impl::integral_power_of_two_that_contains(n); -public: + return i < m_min_block_size_lg2 ? m_min_block_size_lg2 : i; + } + public: /* Return 0 for invalid block size */ KOKKOS_INLINE_FUNCTION - uint32_t allocate_block_size( uint64_t alloc_size ) const noexcept - { - return alloc_size <= (1UL << m_max_block_size_lg2) - ? ( 1UL << get_block_size_lg2( uint32_t(alloc_size) ) ) - : 0 ; - } + uint32_t allocate_block_size(uint64_t alloc_size) const noexcept { + return alloc_size <= (1UL << m_max_block_size_lg2) + ? (1UL << get_block_size_lg2(uint32_t(alloc_size))) + : 0; + } //-------------------------------------------------------------------------- /**\brief Allocate a block of memory that is at least 'alloc_size' @@ -576,105 +540,98 @@ public: * The allocation attempt will try up to 'attempt_limit' times. */ KOKKOS_FUNCTION - void * allocate( size_t alloc_size - , int32_t attempt_limit = 1 ) const noexcept - { - if ( size_t(1LU << m_max_block_size_lg2) < alloc_size ) { - Kokkos::abort("Kokkos MemoryPool allocation request exceeded specified maximum allocation size"); - } + void *allocate(size_t alloc_size, int32_t attempt_limit = 1) const noexcept { + if (size_t(1LU << m_max_block_size_lg2) < alloc_size) { + Kokkos::abort( + "Kokkos MemoryPool allocation request exceeded specified maximum " + "allocation size"); + } - if ( 0 == alloc_size ) return (void*) 0 ; + if (0 == alloc_size) return (void *)0; - void * p = 0 ; + void *p = 0; - const uint32_t block_size_lg2 = get_block_size_lg2( alloc_size ); + const uint32_t block_size_lg2 = get_block_size_lg2(alloc_size); - // Allocation will fit within a superblock - // that has block sizes ( 1 << block_size_lg2 ) + // Allocation will fit within a superblock + // that has block sizes ( 1 << block_size_lg2 ) - const uint32_t block_count_lg2 = m_sb_size_lg2 - block_size_lg2 ; - const uint32_t block_state = block_count_lg2 << state_shift ; - const uint32_t block_count = 1u << block_count_lg2 ; + const uint32_t block_count_lg2 = m_sb_size_lg2 - block_size_lg2; + const uint32_t block_state = block_count_lg2 << state_shift; + const uint32_t block_count = 1u << block_count_lg2; - // Superblock hints for this block size: - // hint_sb_id_ptr[0] is the dynamically changing hint - // hint_sb_id_ptr[1] is the static start point + // Superblock hints for this block size: + // hint_sb_id_ptr[0] is the dynamically changing hint + // hint_sb_id_ptr[1] is the static start point - volatile uint32_t * const hint_sb_id_ptr - = m_sb_state_array /* memory pool state array */ - + m_hint_offset /* offset to hint portion of array */ - + HINT_PER_BLOCK_SIZE /* number of hints per block size */ - * ( block_size_lg2 - m_min_block_size_lg2 ); /* block size id */ + volatile uint32_t *const hint_sb_id_ptr = + m_sb_state_array /* memory pool state array */ + + m_hint_offset /* offset to hint portion of array */ + + HINT_PER_BLOCK_SIZE /* number of hints per block size */ + * (block_size_lg2 - m_min_block_size_lg2); /* block size id */ - const int32_t sb_id_begin = int32_t( hint_sb_id_ptr[1] ); + const int32_t sb_id_begin = int32_t(hint_sb_id_ptr[1]); - // Fast query clock register 'tic' to pseudo-randomize - // the guess for which block within a superblock should - // be claimed. If not available then a search occurs. + // Fast query clock register 'tic' to pseudo-randomize + // the guess for which block within a superblock should + // be claimed. If not available then a search occurs. - const uint32_t block_id_hint = - (uint32_t)( Kokkos::Impl::clock_tic() -#if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_CUDA ) - // Spread out potentially concurrent access - // by threads within a warp or thread block. - + ( threadIdx.x + blockDim.x * threadIdx.y ) + const uint32_t block_id_hint = + (uint32_t)(Kokkos::Impl::clock_tic() +#if defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_CUDA) + // Spread out potentially concurrent access + // by threads within a warp or thread block. + + (threadIdx.x + blockDim.x * threadIdx.y) #endif ); - // expected state of superblock for allocation - uint32_t sb_state = block_state ; - - int32_t sb_id = -1 ; + // expected state of superblock for allocation + uint32_t sb_state = block_state; - volatile uint32_t * sb_state_array = 0 ; + int32_t sb_id = -1; - while ( attempt_limit ) { + volatile uint32_t *sb_state_array = 0; - int32_t hint_sb_id = -1 ; + while (attempt_limit) { + int32_t hint_sb_id = -1; - if ( sb_id < 0 ) { + if (sb_id < 0) { + // No superblock specified, try the hint for this block size - // No superblock specified, try the hint for this block size + sb_id = hint_sb_id = int32_t(*hint_sb_id_ptr); - sb_id = hint_sb_id = int32_t( *hint_sb_id_ptr ); - - sb_state_array = m_sb_state_array + ( sb_id * m_sb_state_size ); - } - - // Require: - // 0 <= sb_id - // sb_state_array == m_sb_state_array + m_sb_state_size * sb_id + sb_state_array = m_sb_state_array + (sb_id * m_sb_state_size); + } - if ( sb_state == ( state_header_mask & *sb_state_array ) ) { + // Require: + // 0 <= sb_id + // sb_state_array == m_sb_state_array + m_sb_state_size * sb_id - // This superblock state is as expected, for the moment. - // Attempt to claim a bit. The attempt updates the state - // so have already made sure the state header is as expected. + if (sb_state == (state_header_mask & *sb_state_array)) { + // This superblock state is as expected, for the moment. + // Attempt to claim a bit. The attempt updates the state + // so have already made sure the state header is as expected. - const uint32_t count_lg2 = sb_state >> state_shift ; - const uint32_t mask = ( 1u << count_lg2 ) - 1 ; + const uint32_t count_lg2 = sb_state >> state_shift; + const uint32_t mask = (1u << count_lg2) - 1; - const Kokkos::pair result = - CB::acquire_bounded_lg2( sb_state_array - , count_lg2 - , block_id_hint & mask - , sb_state - ); + const Kokkos::pair result = CB::acquire_bounded_lg2( + sb_state_array, count_lg2, block_id_hint & mask, sb_state); - // If result.first < 0 then failed to acquire - // due to either full or buffer was wrong state. - // Could be wrong state if a deallocation raced the - // superblock to empty before the acquire could succeed. + // If result.first < 0 then failed to acquire + // due to either full or buffer was wrong state. + // Could be wrong state if a deallocation raced the + // superblock to empty before the acquire could succeed. - if ( 0 <= result.first ) { // acquired a bit + if (0 <= result.first) { // acquired a bit - const uint32_t size_lg2 = m_sb_size_lg2 - count_lg2 ; + const uint32_t size_lg2 = m_sb_size_lg2 - count_lg2; - // Set the allocated block pointer + // Set the allocated block pointer - p = ((char*)( m_sb_state_array + m_data_offset )) - + ( uint64_t(sb_id) << m_sb_size_lg2 ) // superblock memory - + ( uint64_t(result.first) << size_lg2 ); // block memory + p = ((char *)(m_sb_state_array + m_data_offset)) + + (uint64_t(sb_id) << m_sb_size_lg2) // superblock memory + + (uint64_t(result.first) << size_lg2); // block memory #if 0 printf( " MemoryPool(0x%lx) pointer(0x%lx) allocate(%lu) sb_id(%d) sb_state(0x%x) block_size(%d) block_capacity(%d) block_id(%d) block_claimed(%d)\n" @@ -689,146 +646,133 @@ public: , result.second ); #endif - break ; // Success - } + break; // Success } - //------------------------------------------------------------------ - // Arrive here if failed to acquire a block. - // Must find a new superblock. - - // Start searching at designated index for this block size. - // Look for superblock that, in preferential order, - // 1) part-full superblock of this block size - // 2) empty superblock to claim for this block size - // 3) part-full superblock of the next larger block size - - sb_state = block_state ; // Expect to find the desired state - sb_id = -1 ; - - bool update_hint = false ; - int32_t sb_id_empty = -1 ; - int32_t sb_id_large = -1 ; - uint32_t sb_state_large = 0 ; - - sb_state_array = m_sb_state_array + sb_id_begin * m_sb_state_size ; - - for ( int32_t i = 0 , id = sb_id_begin ; i < m_sb_count ; ++i ) { - - // Query state of the candidate superblock. - // Note that the state may change at any moment - // as concurrent allocations and deallocations occur. - - const uint32_t full_state = *sb_state_array ; - const uint32_t used = full_state & state_used_mask ; - const uint32_t state = full_state & state_header_mask ; + } + //------------------------------------------------------------------ + // Arrive here if failed to acquire a block. + // Must find a new superblock. - if ( state == block_state ) { + // Start searching at designated index for this block size. + // Look for superblock that, in preferential order, + // 1) part-full superblock of this block size + // 2) empty superblock to claim for this block size + // 3) part-full superblock of the next larger block size - // Superblock is assigned to this block size + sb_state = block_state; // Expect to find the desired state + sb_id = -1; - if ( used < block_count ) { + bool update_hint = false; + int32_t sb_id_empty = -1; + int32_t sb_id_large = -1; + uint32_t sb_state_large = 0; - // There is room to allocate one block + sb_state_array = m_sb_state_array + sb_id_begin * m_sb_state_size; - sb_id = id ; + for (int32_t i = 0, id = sb_id_begin; i < m_sb_count; ++i) { + // Query state of the candidate superblock. + // Note that the state may change at any moment + // as concurrent allocations and deallocations occur. - // Is there room to allocate more than one block? + const uint32_t full_state = *sb_state_array; + const uint32_t used = full_state & state_used_mask; + const uint32_t state = full_state & state_header_mask; - update_hint = used + 1 < block_count ; + if (state == block_state) { + // Superblock is assigned to this block size - break ; - } - } - else if ( 0 == used ) { + if (used < block_count) { + // There is room to allocate one block - // Superblock is empty + sb_id = id; - if ( -1 == sb_id_empty ) { + // Is there room to allocate more than one block? - // Superblock is not assigned to this block size - // and is the first empty superblock encountered. - // Save this id to use if a partfull superblock is not found. + update_hint = used + 1 < block_count; - sb_id_empty = id ; - } - } - else if ( ( -1 == sb_id_empty /* have not found an empty */ ) && - ( -1 == sb_id_large /* have not found a larger */ ) && - ( state < block_state /* a larger block */ ) && - // is not full: - ( used < ( 1u << ( state >> state_shift ) ) ) ) { - // First superblock encountered that is - // larger than this block size and - // has room for an allocation. - // Save this id to use of partfull or empty superblock not found - sb_id_large = id ; - sb_state_large = state ; + break; } + } else if (0 == used) { + // Superblock is empty - // Iterate around the superblock array: + if (-1 == sb_id_empty) { + // Superblock is not assigned to this block size + // and is the first empty superblock encountered. + // Save this id to use if a partfull superblock is not found. - if ( ++id < m_sb_count ) { - sb_state_array += m_sb_state_size ; - } - else { - id = 0 ; - sb_state_array = m_sb_state_array ; + sb_id_empty = id; } + } else if ((-1 == sb_id_empty /* have not found an empty */) && + (-1 == sb_id_large /* have not found a larger */) && + (state < block_state /* a larger block */) && + // is not full: + (used < (1u << (state >> state_shift)))) { + // First superblock encountered that is + // larger than this block size and + // has room for an allocation. + // Save this id to use of partfull or empty superblock not found + sb_id_large = id; + sb_state_large = state; } - // printf(" search m_sb_count(%d) sb_id(%d) sb_id_empty(%d) sb_id_large(%d)\n" , m_sb_count , sb_id , sb_id_empty , sb_id_large); + // Iterate around the superblock array: - if ( sb_id < 0 ) { + if (++id < m_sb_count) { + sb_state_array += m_sb_state_size; + } else { + id = 0; + sb_state_array = m_sb_state_array; + } + } - // Did not find a partfull superblock for this block size. + // printf(" search m_sb_count(%d) sb_id(%d) sb_id_empty(%d) + // sb_id_large(%d)\n" , m_sb_count , sb_id , sb_id_empty , sb_id_large); - if ( 0 <= sb_id_empty ) { + if (sb_id < 0) { + // Did not find a partfull superblock for this block size. - // Found first empty superblock following designated superblock - // Attempt to claim it for this block size. - // If the claim fails assume that another thread claimed it - // for this block size and try to use it anyway, - // but do not update hint. + if (0 <= sb_id_empty) { + // Found first empty superblock following designated superblock + // Attempt to claim it for this block size. + // If the claim fails assume that another thread claimed it + // for this block size and try to use it anyway, + // but do not update hint. - sb_id = sb_id_empty ; + sb_id = sb_id_empty; - sb_state_array = m_sb_state_array + ( sb_id * m_sb_state_size ); + sb_state_array = m_sb_state_array + (sb_id * m_sb_state_size); - // If successfully changed assignment of empty superblock 'sb_id' - // to this block_size then update the hint. + // If successfully changed assignment of empty superblock 'sb_id' + // to this block_size then update the hint. - const uint32_t state_empty = state_header_mask & *sb_state_array ; + const uint32_t state_empty = state_header_mask & *sb_state_array; - // If this thread claims the empty block then update the hint - update_hint = - state_empty == - Kokkos::atomic_compare_exchange - (sb_state_array,state_empty,block_state); - } - else if ( 0 <= sb_id_large ) { + // If this thread claims the empty block then update the hint + update_hint = + state_empty == Kokkos::atomic_compare_exchange( + sb_state_array, state_empty, block_state); + } else if (0 <= sb_id_large) { + // Found a larger superblock with space available - // Found a larger superblock with space available + sb_id = sb_id_large; + sb_state = sb_state_large; - sb_id = sb_id_large ; - sb_state = sb_state_large ; - - sb_state_array = m_sb_state_array + ( sb_id * m_sb_state_size ); - } - else { - // Did not find a potentially usable superblock - --attempt_limit ; - } + sb_state_array = m_sb_state_array + (sb_id * m_sb_state_size); + } else { + // Did not find a potentially usable superblock + --attempt_limit; } + } - if ( update_hint ) { - Kokkos::atomic_compare_exchange - ( hint_sb_id_ptr , uint32_t(hint_sb_id) , uint32_t(sb_id) ); - } - } // end allocation attempt loop - //-------------------------------------------------------------------- + if (update_hint) { + Kokkos::atomic_compare_exchange(hint_sb_id_ptr, uint32_t(hint_sb_id), + uint32_t(sb_id)); + } + } // end allocation attempt loop + //-------------------------------------------------------------------- - return p ; - } + return p; + } // end allocate //-------------------------------------------------------------------------- @@ -839,47 +783,43 @@ public: * For now the alloc_size is ignored. */ KOKKOS_INLINE_FUNCTION - void deallocate( void * p , size_t /* alloc_size */ ) const noexcept - { - if ( 0 == p ) return ; - - // Determine which superblock and block - const ptrdiff_t d = - ((char*)p) - ((char*)( m_sb_state_array + m_data_offset )); + void deallocate(void *p, size_t /* alloc_size */) const noexcept { + if (0 == p) return; - // Verify contained within the memory pool's superblocks: - const int ok_contains = - ( 0 <= d ) && ( size_t(d) < ( size_t(m_sb_count) << m_sb_size_lg2 ) ); + // Determine which superblock and block + const ptrdiff_t d = + ((char *)p) - ((char *)(m_sb_state_array + m_data_offset)); - int ok_block_aligned = 0 ; - int ok_dealloc_once = 0 ; + // Verify contained within the memory pool's superblocks: + const int ok_contains = + (0 <= d) && (size_t(d) < (size_t(m_sb_count) << m_sb_size_lg2)); - if ( ok_contains ) { + int ok_block_aligned = 0; + int ok_dealloc_once = 0; - const int sb_id = d >> m_sb_size_lg2 ; + if (ok_contains) { + const int sb_id = d >> m_sb_size_lg2; - // State array for the superblock. - volatile uint32_t * const sb_state_array = - m_sb_state_array + ( sb_id * m_sb_state_size ); + // State array for the superblock. + volatile uint32_t *const sb_state_array = + m_sb_state_array + (sb_id * m_sb_state_size); - const uint32_t block_state = (*sb_state_array) & state_header_mask ; - const uint32_t block_size_lg2 = - m_sb_size_lg2 - ( block_state >> state_shift ); + const uint32_t block_state = (*sb_state_array) & state_header_mask; + const uint32_t block_size_lg2 = + m_sb_size_lg2 - (block_state >> state_shift); - ok_block_aligned = 0 == ( d & ( ( 1UL << block_size_lg2 ) - 1 ) ); + ok_block_aligned = 0 == (d & ((1UL << block_size_lg2) - 1)); - if ( ok_block_aligned ) { + if (ok_block_aligned) { + // Map address to block's bit + // mask into superblock and then shift down for block index - // Map address to block's bit - // mask into superblock and then shift down for block index + const uint32_t bit = + (d & (ptrdiff_t(1LU << m_sb_size_lg2) - 1)) >> block_size_lg2; - const uint32_t bit = - ( d & ( ptrdiff_t( 1LU << m_sb_size_lg2 ) - 1 ) ) >> block_size_lg2 ; + const int result = CB::release(sb_state_array, bit, block_state); - const int result = - CB::release( sb_state_array , bit , block_state ); - - ok_dealloc_once = 0 <= result ; + ok_dealloc_once = 0 <= result; #if 0 printf( " MemoryPool(0x%lx) pointer(0x%lx) deallocate sb_id(%d) block_size(%d) block_capacity(%d) block_id(%d) block_claimed(%d)\n" @@ -891,10 +831,10 @@ public: , bit , result ); #endif - } } + } - if ( ! ok_contains || ! ok_block_aligned || ! ok_dealloc_once ) { + if (!ok_contains || !ok_block_aligned || !ok_dealloc_once) { #if 0 printf( " MemoryPool(0x%lx) pointer(0x%lx) deallocate ok_contains(%d) ok_block_aligned(%d) ok_dealloc_once(%d)\n" , (uintptr_t)m_sb_state_array @@ -903,44 +843,40 @@ public: , int(ok_block_aligned) , int(ok_dealloc_once) ); #endif - Kokkos::abort("Kokkos MemoryPool::deallocate given erroneous pointer"); - } + Kokkos::abort("Kokkos MemoryPool::deallocate given erroneous pointer"); } + } // end deallocate //-------------------------------------------------------------------------- KOKKOS_INLINE_FUNCTION - int number_of_superblocks() const noexcept { return m_sb_count ; } + int number_of_superblocks() const noexcept { return m_sb_count; } KOKKOS_INLINE_FUNCTION - void superblock_state( int sb_id - , int & block_size - , int & block_count_capacity - , int & block_count_used ) const noexcept - { - block_size = 0 ; - block_count_capacity = 0 ; - block_count_used = 0 ; - - if ( Kokkos::Impl::MemorySpaceAccess - < Kokkos::Impl::ActiveExecutionMemorySpace - , base_memory_space >::accessible ) { - // Can access the state array - - const uint32_t state = - ((uint32_t volatile *)m_sb_state_array)[sb_id*m_sb_state_size]; - - const uint32_t block_count_lg2 = state >> state_shift ; - const uint32_t block_used = state & state_used_mask ; - - block_size = 1LU << ( m_sb_size_lg2 - block_count_lg2 ); - block_count_capacity = 1LU << block_count_lg2 ; - block_count_used = block_used ; - } + void superblock_state(int sb_id, int &block_size, int &block_count_capacity, + int &block_count_used) const noexcept { + block_size = 0; + block_count_capacity = 0; + block_count_used = 0; + + if (Kokkos::Impl::MemorySpaceAccess< + Kokkos::Impl::ActiveExecutionMemorySpace, + base_memory_space>::accessible) { + // Can access the state array + + const uint32_t state = + ((uint32_t volatile *)m_sb_state_array)[sb_id * m_sb_state_size]; + + const uint32_t block_count_lg2 = state >> state_shift; + const uint32_t block_used = state & state_used_mask; + + block_size = 1LU << (m_sb_size_lg2 - block_count_lg2); + block_count_capacity = 1LU << block_count_lg2; + block_count_used = block_used; } + } }; -} // namespace Kokkos +} // namespace Kokkos #endif /* #ifndef KOKKOS_MEMORYPOOL_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_MemoryTraits.hpp b/lib/kokkos/core/src/Kokkos_MemoryTraits.hpp index 509ac6499e..75d3d40144 100644 --- a/lib/kokkos/core/src/Kokkos_MemoryTraits.hpp +++ b/lib/kokkos/core/src/Kokkos_MemoryTraits.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -59,53 +60,64 @@ namespace Kokkos { * A zero value is the default for a View, indicating that none of * these traits are present. */ -enum MemoryTraitsFlags - { Unmanaged = 0x01 - , RandomAccess = 0x02 - , Atomic = 0x04 - , Restrict = 0x08 - , Aligned = 0x10 - }; +enum MemoryTraitsFlags { + Unmanaged = 0x01, + RandomAccess = 0x02, + Atomic = 0x04, + Restrict = 0x08, + Aligned = 0x10 +}; -template < unsigned T > +template struct MemoryTraits { //! Tag this class as a kokkos memory traits: - typedef MemoryTraits memory_traits ; + typedef MemoryTraits memory_traits; #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - enum : bool { Unmanaged = (unsigned(0) != (T & unsigned(Kokkos::Unmanaged))) }; - enum : bool { RandomAccess = (unsigned(0) != (T & unsigned(Kokkos::RandomAccess))) }; - enum : bool { Atomic = (unsigned(0) != (T & unsigned(Kokkos::Atomic))) }; - enum : bool { Restrict = (unsigned(0) != (T & unsigned(Kokkos::Restrict))) }; - enum : bool { Aligned = (unsigned(0) != (T & unsigned(Kokkos::Aligned))) }; + enum : bool { + Unmanaged = (unsigned(0) != (T & unsigned(Kokkos::Unmanaged))) + }; + enum : bool { + RandomAccess = (unsigned(0) != (T & unsigned(Kokkos::RandomAccess))) + }; + enum : bool { Atomic = (unsigned(0) != (T & unsigned(Kokkos::Atomic))) }; + enum : bool { Restrict = (unsigned(0) != (T & unsigned(Kokkos::Restrict))) }; + enum : bool { Aligned = (unsigned(0) != (T & unsigned(Kokkos::Aligned))) }; #endif - enum : bool { is_unmanaged = (unsigned(0) != (T & unsigned(Kokkos::Unmanaged))) }; - enum : bool { is_random_access = (unsigned(0) != (T & unsigned(Kokkos::RandomAccess))) }; - enum : bool { is_atomic = (unsigned(0) != (T & unsigned(Kokkos::Atomic))) }; - enum : bool { is_restrict = (unsigned(0) != (T & unsigned(Kokkos::Restrict))) }; - enum : bool { is_aligned = (unsigned(0) != (T & unsigned(Kokkos::Aligned))) }; + enum : bool { + is_unmanaged = (unsigned(0) != (T & unsigned(Kokkos::Unmanaged))) + }; + enum : bool { + is_random_access = (unsigned(0) != (T & unsigned(Kokkos::RandomAccess))) + }; + enum : bool { is_atomic = (unsigned(0) != (T & unsigned(Kokkos::Atomic))) }; + enum : bool { + is_restrict = (unsigned(0) != (T & unsigned(Kokkos::Restrict))) + }; + enum : bool { is_aligned = (unsigned(0) != (T & unsigned(Kokkos::Aligned))) }; }; -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- namespace Kokkos { -typedef Kokkos::MemoryTraits<0> MemoryManaged ; -typedef Kokkos::MemoryTraits< Kokkos::Unmanaged > MemoryUnmanaged ; -typedef Kokkos::MemoryTraits< Kokkos::Unmanaged | Kokkos::RandomAccess > MemoryRandomAccess ; +typedef Kokkos::MemoryTraits<0> MemoryManaged; +typedef Kokkos::MemoryTraits MemoryUnmanaged; +typedef Kokkos::MemoryTraits + MemoryRandomAccess; -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- namespace Kokkos { namespace Impl { -static_assert( - ( 0 < int(KOKKOS_MEMORY_ALIGNMENT) ) && - ( 0 == ( int(KOKKOS_MEMORY_ALIGNMENT) & (int(KOKKOS_MEMORY_ALIGNMENT)-1))) , - "KOKKOS_MEMORY_ALIGNMENT must be a power of two" ); +static_assert((0 < int(KOKKOS_MEMORY_ALIGNMENT)) && + (0 == (int(KOKKOS_MEMORY_ALIGNMENT) & + (int(KOKKOS_MEMORY_ALIGNMENT) - 1))), + "KOKKOS_MEMORY_ALIGNMENT must be a power of two"); /** \brief Memory alignment settings * @@ -113,13 +125,12 @@ static_assert( * Enable compatibility of views from different devices with static stride. * Use compiler flag to enable overwrites. */ -enum : unsigned - { MEMORY_ALIGNMENT = KOKKOS_MEMORY_ALIGNMENT - , MEMORY_ALIGNMENT_THRESHOLD = KOKKOS_MEMORY_ALIGNMENT_THRESHOLD - }; +enum : unsigned { + MEMORY_ALIGNMENT = KOKKOS_MEMORY_ALIGNMENT, + MEMORY_ALIGNMENT_THRESHOLD = KOKKOS_MEMORY_ALIGNMENT_THRESHOLD +}; -} //namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos #endif /* #ifndef KOKKOS_MEMORYTRAITS_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_NumericTraits.hpp b/lib/kokkos/core/src/Kokkos_NumericTraits.hpp index baac782545..666bb33266 100644 --- a/lib/kokkos/core/src/Kokkos_NumericTraits.hpp +++ b/lib/kokkos/core/src/Kokkos_NumericTraits.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,176 +45,347 @@ #ifndef KOKKOS_NUMERICTRAITS_HPP #define KOKKOS_NUMERICTRAITS_HPP -#include -#include +#include +#include namespace Kokkos { -template +template struct reduction_identity; /*{ KOKKOS_FORCEINLINE_FUNCTION constexpr static T sum() { return T(); } // 0 KOKKOS_FORCEINLINE_FUNCTION constexpr static T prod() // 1 - { static_assert( false, "Missing specialization of Kokkos::reduction_identity for custom prod reduction type"); return T(); } + { static_assert( false, "Missing specialization of +Kokkos::reduction_identity for custom prod reduction type"); return T(); } KOKKOS_FORCEINLINE_FUNCTION constexpr static T max() // minimum value - { static_assert( false, "Missing specialization of Kokkos::reduction_identity for custom max reduction type"); return T(); } + { static_assert( false, "Missing specialization of +Kokkos::reduction_identity for custom max reduction type"); return T(); } KOKKOS_FORCEINLINE_FUNCTION constexpr static T min() // maximum value - { static_assert( false, "Missing specialization of Kokkos::reduction_identity for custom min reduction type"); return T(); } - KOKKOS_FORCEINLINE_FUNCTION constexpr static T bor() // 0, only for integer type - { static_assert( false, "Missing specialization of Kokkos::reduction_identity for custom bor reduction type"); return T(); } - KOKKOS_FORCEINLINE_FUNCTION constexpr static T band() // !0, only for integer type - { static_assert( false, "Missing specialization of Kokkos::reduction_identity for custom band reduction type"); return T(); } - KOKKOS_FORCEINLINE_FUNCTION constexpr static T lor() // 0, only for integer type - { static_assert( false, "Missing specialization of Kokkos::reduction_identity for custom lor reduction type"); return T(); } - KOKKOS_FORCEINLINE_FUNCTION constexpr static T land() // !0, only for integer type - { static_assert( false, "Missing specialization of Kokkos::reduction_identity for custom land reduction type"); return T(); } + { static_assert( false, "Missing specialization of +Kokkos::reduction_identity for custom min reduction type"); return T(); } + KOKKOS_FORCEINLINE_FUNCTION constexpr static T bor() // 0, only for integer +type { static_assert( false, "Missing specialization of +Kokkos::reduction_identity for custom bor reduction type"); return T(); } + KOKKOS_FORCEINLINE_FUNCTION constexpr static T band() // !0, only for integer +type { static_assert( false, "Missing specialization of +Kokkos::reduction_identity for custom band reduction type"); return T(); } + KOKKOS_FORCEINLINE_FUNCTION constexpr static T lor() // 0, only for integer +type { static_assert( false, "Missing specialization of +Kokkos::reduction_identity for custom lor reduction type"); return T(); } + KOKKOS_FORCEINLINE_FUNCTION constexpr static T land() // !0, only for integer +type { static_assert( false, "Missing specialization of +Kokkos::reduction_identity for custom land reduction type"); return T(); } };*/ -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char sum() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char prod() {return static_cast(1);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char max() {return SCHAR_MIN;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char min() {return SCHAR_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char bor() {return static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char band() {return ~static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char lor() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char land() {return static_cast(1);} + KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char sum() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char prod() { + return static_cast(1); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char max() { + return SCHAR_MIN; + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char min() { + return SCHAR_MAX; + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char bor() { + return static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char band() { + return ~static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char lor() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char land() { + return static_cast(1); + } }; -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static short sum() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static short prod() {return static_cast(1);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static short max() {return SHRT_MIN;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static short min() {return SHRT_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static short bor() {return static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static short band() {return ~static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static short lor() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static short land() {return static_cast(1);} + KOKKOS_FORCEINLINE_FUNCTION constexpr static short sum() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static short prod() { + return static_cast(1); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static short max() { return SHRT_MIN; } + KOKKOS_FORCEINLINE_FUNCTION constexpr static short min() { return SHRT_MAX; } + KOKKOS_FORCEINLINE_FUNCTION constexpr static short bor() { + return static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static short band() { + return ~static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static short lor() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static short land() { + return static_cast(1); + } }; -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static int sum() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static int prod() {return static_cast(1);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static int max() {return INT_MIN;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static int min() {return INT_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static int bor() {return static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static int band() {return ~static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static int lor() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static int land() {return static_cast(1);} + KOKKOS_FORCEINLINE_FUNCTION constexpr static int sum() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static int prod() { + return static_cast(1); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static int max() { return INT_MIN; } + KOKKOS_FORCEINLINE_FUNCTION constexpr static int min() { return INT_MAX; } + KOKKOS_FORCEINLINE_FUNCTION constexpr static int bor() { + return static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static int band() { + return ~static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static int lor() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static int land() { + return static_cast(1); + } }; -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static long sum() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long prod() {return static_cast(1);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long max() {return LLONG_MIN;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long min() {return LLONG_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long bor() {return static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long band() {return ~static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long lor() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long land() {return static_cast(1);} + KOKKOS_FORCEINLINE_FUNCTION constexpr static long sum() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long prod() { + return static_cast(1); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long max() { return LLONG_MIN; } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long min() { return LLONG_MAX; } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long bor() { + return static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long band() { + return ~static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long lor() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long land() { + return static_cast(1); + } }; -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static long long sum() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long long prod() {return static_cast(1);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long long max() {return LLONG_MIN;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long long min() {return LLONG_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long long bor() {return static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long long band() {return ~static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long long lor() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long long land() {return static_cast(1);} + KOKKOS_FORCEINLINE_FUNCTION constexpr static long long sum() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long long prod() { + return static_cast(1); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long long max() { + return LLONG_MIN; + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long long min() { + return LLONG_MAX; + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long long bor() { + return static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long long band() { + return ~static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long long lor() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long long land() { + return static_cast(1); + } }; -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char sum() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char prod() {return static_cast(1);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char max() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char min() {return UCHAR_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char bor() {return static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char band() {return ~static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char lor() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char land() {return static_cast(1);} + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char sum() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char prod() { + return static_cast(1); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char max() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char min() { + return UCHAR_MAX; + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char bor() { + return static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char band() { + return ~static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char lor() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char land() { + return static_cast(1); + } }; -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short sum() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short prod() {return static_cast(1);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short max() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short min() {return USHRT_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short bor() {return static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short band() {return ~static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short lor() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short land() {return static_cast(1);} + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short sum() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short prod() { + return static_cast(1); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short max() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short min() { + return USHRT_MAX; + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short bor() { + return static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short band() { + return ~static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short lor() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short land() { + return static_cast(1); + } }; -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int sum() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int prod() {return static_cast(1);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int max() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int min() {return UINT_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int bor() {return static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int band() {return ~static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int lor() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int land() {return static_cast(1);} + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int sum() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int prod() { + return static_cast(1); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int max() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int min() { + return UINT_MAX; + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int bor() { + return static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int band() { + return ~static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int lor() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int land() { + return static_cast(1); + } }; -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long sum() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long prod() {return static_cast(1);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long max() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long min() {return ULONG_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long bor() {return static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long band() {return ~static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long lor() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long land() {return static_cast(1);} + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long sum() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long prod() { + return static_cast(1); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long max() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long min() { + return ULONG_MAX; + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long bor() { + return static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long band() { + return ~static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long lor() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long land() { + return static_cast(1); + } }; -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long sum() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long prod() {return static_cast(1);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long max() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long min() {return ULLONG_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long bor() {return static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long band() {return ~static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long lor() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long land() {return static_cast(1);} + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long sum() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long prod() { + return static_cast(1); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long max() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long min() { + return ULLONG_MAX; + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long bor() { + return static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long band() { + return ~static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long lor() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long land() { + return static_cast(1); + } }; -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static float sum() {return static_cast(0.0f);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static float prod() {return static_cast(1.0f);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static float max() {return -FLT_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static float min() {return FLT_MAX;} + KOKKOS_FORCEINLINE_FUNCTION constexpr static float sum() { + return static_cast(0.0f); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static float prod() { + return static_cast(1.0f); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static float max() { return -FLT_MAX; } + KOKKOS_FORCEINLINE_FUNCTION constexpr static float min() { return FLT_MAX; } }; -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static double sum() {return static_cast(0.0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static double prod() {return static_cast(1.0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static double max() {return -DBL_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static double min() {return DBL_MAX;} + KOKKOS_FORCEINLINE_FUNCTION constexpr static double sum() { + return static_cast(0.0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static double prod() { + return static_cast(1.0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static double max() { return -DBL_MAX; } + KOKKOS_FORCEINLINE_FUNCTION constexpr static double min() { return DBL_MAX; } }; -#if !defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_CUDA ) -template<> +#if !defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_CUDA) +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static long double sum() {return static_cast(0.0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long double prod() {return static_cast(1.0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long double max() {return -LDBL_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long double min() {return LDBL_MAX;} + KOKKOS_FORCEINLINE_FUNCTION constexpr static long double sum() { + return static_cast(0.0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long double prod() { + return static_cast(1.0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long double max() { + return -LDBL_MAX; + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long double min() { + return LDBL_MAX; + } }; #endif -} +} // namespace Kokkos #endif diff --git a/lib/kokkos/core/src/Kokkos_OpenMP.hpp b/lib/kokkos/core/src/Kokkos_OpenMP.hpp index 6ee8f08dc8..3955c06156 100644 --- a/lib/kokkos/core/src/Kokkos_OpenMP.hpp +++ b/lib/kokkos/core/src/Kokkos_OpenMP.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,7 +46,7 @@ #define KOKKOS_OPENMP_HPP #include -#if defined( KOKKOS_ENABLE_OPENMP) +#if defined(KOKKOS_ENABLE_OPENMP) #include @@ -76,53 +77,48 @@ class OpenMPExec; /// \class OpenMP /// \brief Kokkos device for multicore processors in the host memory space. class OpenMP { -public: + public: //! Tag this class as a kokkos execution space using execution_space = OpenMP; using memory_space = - #ifdef KOKKOS_ENABLE_HBWSPACE - Experimental::HBWSpace; - #else - HostSpace; - #endif +#ifdef KOKKOS_ENABLE_HBWSPACE + Experimental::HBWSpace; +#else + HostSpace; +#endif //! This execution space preferred device_type - using device_type = Kokkos::Device< execution_space, memory_space >; + using device_type = Kokkos::Device; using array_layout = LayoutRight; using size_type = memory_space::size_type; - using scratch_memory_space = ScratchMemorySpace< OpenMP >; + using scratch_memory_space = ScratchMemorySpace; /// \brief Get a handle to the default execution space instance - inline - OpenMP() noexcept; + inline OpenMP() noexcept; /// \brief Print configuration information to the given output stream. - static void print_configuration( std::ostream & , const bool verbose = false ); + static void print_configuration(std::ostream&, const bool verbose = false); /// \brief is the instance running a parallel algorithm - inline - static bool in_parallel( OpenMP const& = OpenMP() ) noexcept; + inline static bool in_parallel(OpenMP const& = OpenMP()) noexcept; /// \brief Wait until all dispatched functors complete on the given instance /// /// This is a no-op on OpenMP - static void impl_static_fence( OpenMP const& = OpenMP() ) noexcept; + static void impl_static_fence(OpenMP const& = OpenMP()) noexcept; - #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - static void fence( OpenMP const& = OpenMP() ) noexcept; - #else +#ifdef KOKKOS_ENABLE_DEPRECATED_CODE + static void fence(OpenMP const& = OpenMP()) noexcept; +#else void fence() const; - #endif - +#endif /// \brief Does the given instance return immediately after launching /// a parallel algorithm /// /// This always returns false on OpenMP - inline - static bool is_asynchronous( OpenMP const& = OpenMP() ) noexcept; - + inline static bool is_asynchronous(OpenMP const& = OpenMP()) noexcept; /// \brief Partition the default instance into new instances without creating /// new masters @@ -137,24 +133,22 @@ public: /// This is a no-op on OpenMP since a non default instance cannot be created static OpenMP create_instance(...); - /// \brief Partition the default instance and call 'f' on each new 'master' thread + /// \brief Partition the default instance and call 'f' on each new 'master' + /// thread /// /// Func is a functor with the following signiture /// void( int partition_id, int num_partitions ) template - static void partition_master( F const& f - , int requested_num_partitions = 0 - , int requested_partition_size = 0 - ); + static void partition_master(F const& f, int requested_num_partitions = 0, + int requested_partition_size = 0); // use UniqueToken static int concurrency(); #ifdef KOKKOS_ENABLE_DEPRECATED_CODE /// \brief Initialize the default execution space - static void initialize( int thread_count, - int use_numa_count, - int use_cores_per_numa = 0); + static void initialize(int thread_count, int use_numa_count, + int use_cores_per_numa = 0); /// \brief Initialize the default execution space /// @@ -166,66 +160,62 @@ public: /// if ( thread_count > 0 ) /// then force openmp to use the given number of threads and change /// the default number of threads - static void initialize( int thread_count = -1 ); + static void initialize(int thread_count = -1); - /// \brief is the default execution space initialized for current 'master' thread + /// \brief is the default execution space initialized for current 'master' + /// thread static bool is_initialized() noexcept; /// \brief Free any resources being consumed by the default execution space static void finalize(); - inline - static int thread_pool_size() noexcept; + inline static int thread_pool_size() noexcept; /** \brief The rank of the executing thread in this thread pool */ KOKKOS_INLINE_FUNCTION static int thread_pool_rank() noexcept; - inline - static int thread_pool_size( int depth ); + inline static int thread_pool_size(int depth); - static void sleep() {}; - static void wake() {}; + static void sleep(){}; + static void wake(){}; // Using omp_get_max_threads(); is problematic // On Intel (essentially an initial call to the OpenMP runtime // without a parallel region before will set a process mask for a single core - // The runtime will than bind threads for a parallel region to other cores on the - // entering the first parallel region and make the process mask the aggregate of - // the thread masks. The intend seems to be to make serial code run fast, if you - // compile with OpenMP enabled but don't actually use parallel regions or so - // static int omp_max_threads = omp_get_max_threads(); + // The runtime will than bind threads for a parallel region to other cores on + // the entering the first parallel region and make the process mask the + // aggregate of the thread masks. The intend seems to be to make serial code + // run fast, if you compile with OpenMP enabled but don't actually use + // parallel regions or so static int omp_max_threads = omp_get_max_threads(); static int get_current_max_threads() noexcept; // use UniqueToken - inline - static int max_hardware_threads() noexcept; + inline static int max_hardware_threads() noexcept; // use UniqueToken KOKKOS_INLINE_FUNCTION static int hardware_thread_id() noexcept; #else - static void impl_initialize( int thread_count = -1 ); + static void impl_initialize(int thread_count = -1); - /// \brief is the default execution space initialized for current 'master' thread + /// \brief is the default execution space initialized for current 'master' + /// thread static bool impl_is_initialized() noexcept; /// \brief Free any resources being consumed by the default execution space static void impl_finalize(); - inline - static int impl_thread_pool_size() noexcept; + inline static int impl_thread_pool_size() noexcept; /** \brief The rank of the executing thread in this thread pool */ KOKKOS_INLINE_FUNCTION static int impl_thread_pool_rank() noexcept; - inline - static int impl_thread_pool_size( int depth ); + inline static int impl_thread_pool_size(int depth); // use UniqueToken - inline - static int impl_max_hardware_threads() noexcept; + inline static int impl_max_hardware_threads() noexcept; // use UniqueToken KOKKOS_INLINE_FUNCTION @@ -237,7 +227,7 @@ public: static constexpr const char* name() noexcept { return "OpenMP"; } }; -} // namespace Kokkos +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -245,30 +235,24 @@ public: namespace Kokkos { namespace Impl { -template<> -struct MemorySpaceAccess - < Kokkos::OpenMP::memory_space - , Kokkos::OpenMP::scratch_memory_space - > -{ +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = true }; - enum { deepcopy = false }; + enum { deepcopy = false }; }; -template<> -struct VerifyExecutionCanAccessMemorySpace - < Kokkos::OpenMP::memory_space - , Kokkos::OpenMP::scratch_memory_space - > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace< + Kokkos::OpenMP::memory_space, Kokkos::OpenMP::scratch_memory_space> { enum { value = true }; - inline static void verify( void ) { } - inline static void verify( const void * ) { } + inline static void verify(void) {} + inline static void verify(const void*) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -283,4 +267,3 @@ struct VerifyExecutionCanAccessMemorySpace #endif /* #if defined( KOKKOS_ENABLE_OPENMP ) && defined( _OPENMP ) */ #endif /* #ifndef KOKKOS_OPENMP_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_OpenMPTarget.hpp b/lib/kokkos/core/src/Kokkos_OpenMPTarget.hpp index e2dd249ff7..9706751f9c 100644 --- a/lib/kokkos/core/src/Kokkos_OpenMPTarget.hpp +++ b/lib/kokkos/core/src/Kokkos_OpenMPTarget.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -46,7 +47,7 @@ #include -#if defined( KOKKOS_ENABLE_OPENMPTARGET ) && defined( _OPENMP ) +#if defined(KOKKOS_ENABLE_OPENMPTARGET) && defined(_OPENMP) #include @@ -67,21 +68,21 @@ namespace Experimental { /// \class OpenMPTarget /// \brief Kokkos device for multicore processors in the host memory space. class OpenMPTarget { -public: + public: //------------------------------------ //! \name Type declarations that all Kokkos devices must provide. //@{ //! Tag this class as a kokkos execution space - typedef OpenMPTarget execution_space ; - typedef OpenMPTargetSpace memory_space ; + typedef OpenMPTarget execution_space; + typedef OpenMPTargetSpace memory_space; //! This execution space preferred device_type - typedef Kokkos::Device device_type; + typedef Kokkos::Device device_type; - typedef LayoutLeft array_layout ; - typedef memory_space::size_type size_type ; + typedef LayoutLeft array_layout; + typedef memory_space::size_type size_type; - typedef ScratchMemorySpace< OpenMPTarget > scratch_memory_space ; + typedef ScratchMemorySpace scratch_memory_space; //@} //------------------------------------ @@ -96,11 +97,12 @@ public: /** \brief Wake the device from the 'sleep' state. A noop for OpenMPTarget. */ static bool wake(); - /** \brief Wait until all dispatched functors complete. A noop for OpenMPTarget. */ + /** \brief Wait until all dispatched functors complete. A noop for + * OpenMPTarget. */ static void fence() {} /// \brief Print configuration information to the given output stream. - static void print_configuration( std::ostream & , const bool detail = false ); + static void print_configuration(std::ostream&, const bool detail = false); /// \brief Free any resources being consumed by the device. static void finalize(); @@ -114,9 +116,8 @@ public: * 2) Allocate a HostThread for each OpenMPTarget thread to hold its * topology and fan in/out data. */ - static void initialize( unsigned thread_count = 0 , - unsigned use_numa_count = 0 , - unsigned use_cores_per_numa = 0 ); + static void initialize(unsigned thread_count = 0, unsigned use_numa_count = 0, + unsigned use_cores_per_numa = 0); static int is_initialized(); @@ -125,14 +126,16 @@ public: //@} //------------------------------------ - /** \brief This execution space has a topological thread pool which can be queried. + /** \brief This execution space has a topological thread pool which can be + * queried. * - * All threads within a pool have a common memory space for which they are cache coherent. - * depth = 0 gives the number of threads in the whole pool. - * depth = 1 gives the number of threads in a NUMA region, typically sharing L3 cache. - * depth = 2 gives the number of threads at the finest granularity, typically sharing L1 cache. + * All threads within a pool have a common memory space for which they are + * cache coherent. depth = 0 gives the number of threads in the whole pool. + * depth = 1 gives the number of threads in a NUMA region, typically + * sharing L3 cache. depth = 2 gives the number of threads at the finest + * granularity, typically sharing L1 cache. */ - inline static int thread_pool_size( int depth = 0 ); + inline static int thread_pool_size(int depth = 0); /** \brief The rank of the executing thread in this thread pool */ KOKKOS_INLINE_FUNCTION static int thread_pool_rank(); @@ -141,15 +144,17 @@ public: inline static unsigned max_hardware_threads() { return thread_pool_size(0); } - KOKKOS_INLINE_FUNCTION static - unsigned hardware_thread_id() { return thread_pool_rank(); } + KOKKOS_INLINE_FUNCTION static unsigned hardware_thread_id() { + return thread_pool_rank(); + } static const char* name(); -private: + + private: static bool m_is_initialized; }; -} // namespace Experimental -} // namespace Kokkos +} // namespace Experimental +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -157,19 +162,17 @@ private: namespace Kokkos { namespace Impl { -template<> -struct VerifyExecutionCanAccessMemorySpace - < Kokkos::Experimental::OpenMPTarget::memory_space - , Kokkos::Experimental::OpenMPTarget::scratch_memory_space - > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace< + Kokkos::Experimental::OpenMPTarget::memory_space, + Kokkos::Experimental::OpenMPTarget::scratch_memory_space> { enum { value = true }; - inline static void verify( void ) { } - inline static void verify( const void * ) { } + inline static void verify(void) {} + inline static void verify(const void*) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -182,5 +185,3 @@ struct VerifyExecutionCanAccessMemorySpace #endif /* #if defined( KOKKOS_ENABLE_OPENMPTARGET ) && defined( _OPENMP ) */ #endif /* #ifndef KOKKOS_OPENMPTARGET_HPP */ - - diff --git a/lib/kokkos/core/src/Kokkos_OpenMPTargetSpace.hpp b/lib/kokkos/core/src/Kokkos_OpenMPTargetSpace.hpp index abb0b8588d..96c46754b4 100644 --- a/lib/kokkos/core/src/Kokkos_OpenMPTargetSpace.hpp +++ b/lib/kokkos/core/src/Kokkos_OpenMPTargetSpace.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -66,25 +67,25 @@ namespace Impl { /// where the hash value is derived from the address of the /// object for which an atomic operation is performed. /// This function initializes the locks to zero (unset). -//void init_lock_array_host_space(); +// void init_lock_array_host_space(); -/// \brief Acquire a lock for the address +/// \brief Aquire a lock for the address /// -/// This function tries to acquire the lock for the hash value derived -/// from the provided ptr. If the lock is successfully acquired the +/// This function tries to aquire the lock for the hash value derived +/// from the provided ptr. If the lock is successfully aquired the /// function returns true. Otherwise it returns false. -//bool lock_address_host_space(void* ptr); +// bool lock_address_host_space(void* ptr); /// \brief Release lock for the address /// /// This function releases the lock for the hash value derived /// from the provided ptr. This function should only be called -/// after previously successfully acquiring a lock with +/// after previously successfully aquiring a lock with /// lock_address. -//void unlock_address_host_space(void* ptr); +// void unlock_address_host_space(void* ptr); -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos namespace Kokkos { namespace Experimental { @@ -95,11 +96,10 @@ namespace Experimental { /// OpenMPTargetSpace is a memory space that governs host memory. "Host" /// memory means the usual CPU-accessible memory. class OpenMPTargetSpace { -public: - + public: //! Tag this class as a kokkos memory space - typedef OpenMPTargetSpace memory_space ; - typedef size_t size_type ; + typedef OpenMPTargetSpace memory_space; + typedef size_t size_type; /// \typedef execution_space /// \brief Default execution space for this memory space. @@ -107,34 +107,33 @@ public: /// Every memory space has a default execution space. This is /// useful for things like initializing a View (which happens in /// parallel using the View's default execution space). - typedef Kokkos::Experimental::OpenMPTarget execution_space ; + typedef Kokkos::Experimental::OpenMPTarget execution_space; //! This memory space preferred device_type - typedef Kokkos::Device device_type; + typedef Kokkos::Device device_type; /*--------------------------------*/ /**\brief Default memory space instance */ OpenMPTargetSpace(); - OpenMPTargetSpace( OpenMPTargetSpace && rhs ) = default ; - OpenMPTargetSpace( const OpenMPTargetSpace & rhs ) = default ; - OpenMPTargetSpace & operator = ( OpenMPTargetSpace && ) = default ; - OpenMPTargetSpace & operator = ( const OpenMPTargetSpace & ) = default ; - ~OpenMPTargetSpace() = default ; + OpenMPTargetSpace(OpenMPTargetSpace&& rhs) = default; + OpenMPTargetSpace(const OpenMPTargetSpace& rhs) = default; + OpenMPTargetSpace& operator=(OpenMPTargetSpace&&) = default; + OpenMPTargetSpace& operator=(const OpenMPTargetSpace&) = default; + ~OpenMPTargetSpace() = default; /**\brief Allocate untracked memory in the space */ - void * allocate( const size_t arg_alloc_size ) const ; + void* allocate(const size_t arg_alloc_size) const; /**\brief Deallocate untracked memory in the space */ - void deallocate( void * const arg_alloc_ptr - , const size_t arg_alloc_size ) const ; - -private: + void deallocate(void* const arg_alloc_ptr, const size_t arg_alloc_size) const; - friend class Kokkos::Impl::SharedAllocationRecord< Kokkos::Experimental::OpenMPTargetSpace , void > ; + private: + friend class Kokkos::Impl::SharedAllocationRecord< + Kokkos::Experimental::OpenMPTargetSpace, void>; }; -} // namespace Experimental -} // namespace Kokkos +} // namespace Experimental +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -142,70 +141,62 @@ private: namespace Kokkos { namespace Impl { -template<> -class SharedAllocationRecord< Kokkos::Experimental::OpenMPTargetSpace , void > - : public SharedAllocationRecord< void , void > -{ -private: - - friend Kokkos::Experimental::OpenMPTargetSpace ; +template <> +class SharedAllocationRecord + : public SharedAllocationRecord { + private: + friend Kokkos::Experimental::OpenMPTargetSpace; - typedef SharedAllocationRecord< void , void > RecordBase ; + typedef SharedAllocationRecord RecordBase; - SharedAllocationRecord( const SharedAllocationRecord & ) = delete ; - SharedAllocationRecord & operator = ( const SharedAllocationRecord & ) = delete ; + SharedAllocationRecord(const SharedAllocationRecord&) = delete; + SharedAllocationRecord& operator=(const SharedAllocationRecord&) = delete; - static void deallocate( RecordBase * ); + static void deallocate(RecordBase*); - /**\brief Root record for tracked allocations from this OpenMPTargetSpace instance */ - static RecordBase s_root_record ; + /**\brief Root record for tracked allocations from this OpenMPTargetSpace + * instance */ + static RecordBase s_root_record; - const Kokkos::Experimental::OpenMPTargetSpace m_space ; - -protected: + const Kokkos::Experimental::OpenMPTargetSpace m_space; + protected: ~SharedAllocationRecord(); - SharedAllocationRecord() = default ; - - SharedAllocationRecord( const Kokkos::Experimental::OpenMPTargetSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - , const RecordBase::function_type arg_dealloc = & deallocate - ); + SharedAllocationRecord() = default; -public: + SharedAllocationRecord( + const Kokkos::Experimental::OpenMPTargetSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size, + const RecordBase::function_type arg_dealloc = &deallocate); + public: std::string get_label() const; - KOKKOS_INLINE_FUNCTION static - SharedAllocationRecord * allocate( const Kokkos::Experimental::OpenMPTargetSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - ); + KOKKOS_INLINE_FUNCTION static SharedAllocationRecord* allocate( + const Kokkos::Experimental::OpenMPTargetSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size); /**\brief Allocate tracked memory in the space */ - static - void * allocate_tracked( const Kokkos::Experimental::OpenMPTargetSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size ); + static void* allocate_tracked( + const Kokkos::Experimental::OpenMPTargetSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size); /**\brief Reallocate tracked memory in the space */ - static - void * reallocate_tracked( void * const arg_alloc_ptr - , const size_t arg_alloc_size ); + static void* reallocate_tracked(void* const arg_alloc_ptr, + const size_t arg_alloc_size); /**\brief Deallocate tracked memory in the space */ - static - void deallocate_tracked( void * const arg_alloc_ptr ); - + static void deallocate_tracked(void* const arg_alloc_ptr); - static SharedAllocationRecord * get_record( void * arg_alloc_ptr ); + static SharedAllocationRecord* get_record(void* arg_alloc_ptr); - static void print_records( std::ostream & , const Kokkos::Experimental::OpenMPTargetSpace & , bool detail = false ); + static void print_records(std::ostream&, + const Kokkos::Experimental::OpenMPTargetSpace&, + bool detail = false); }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -213,53 +204,59 @@ public: namespace Kokkos { namespace Impl { -//TODO: implement all possible deep_copies -template -struct DeepCopy { - DeepCopy( void * dst , const void * src , size_t n ) { - omp_target_memcpy( dst , const_cast (src) , n, 0, 0, omp_get_default_device(), omp_get_default_device()); +// TODO: implement all possible deep_copies +template +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t n) { + omp_target_memcpy(dst, const_cast(src), n, 0, 0, + omp_get_default_device(), omp_get_default_device()); } - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) { + DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, size_t n) { exec.fence(); - omp_target_memcpy( dst , const_cast (src) , n, 0, 0, omp_get_default_device(), omp_get_default_device()); + omp_target_memcpy(dst, const_cast(src), n, 0, 0, + omp_get_default_device(), omp_get_default_device()); } }; - -template -struct DeepCopy { - DeepCopy( void * dst , const void * src , size_t n ) { - omp_target_memcpy( dst , const_cast (src) , n, 0, 0, omp_get_default_device(), omp_get_initial_device()); +template +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t n) { + omp_target_memcpy(dst, const_cast(src), n, 0, 0, + omp_get_default_device(), omp_get_initial_device()); } - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) { + DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, size_t n) { exec.fence(); - omp_target_memcpy( dst , const_cast (src) , n, 0, 0, omp_get_default_device(), omp_get_initial_device()); + omp_target_memcpy(dst, const_cast(src), n, 0, 0, + omp_get_default_device(), omp_get_initial_device()); } }; -template -struct DeepCopy { - DeepCopy( void * dst , const void * src , size_t n ) { - omp_target_memcpy( dst , const_cast (src) , n, 0, 0, omp_get_initial_device(), omp_get_default_device()); +template +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t n) { + omp_target_memcpy(dst, const_cast(src), n, 0, 0, + omp_get_initial_device(), omp_get_default_device()); } - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) { + DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, size_t n) { exec.fence(); - omp_target_memcpy( dst , const_cast (src) , n, 0, 0, omp_get_initial_device(), omp_get_default_device()); + omp_target_memcpy(dst, const_cast(src), n, 0, 0, + omp_get_initial_device(), omp_get_default_device()); } }; - -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::HostSpace , Kokkos::Experimental::OpenMPTargetSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace< + Kokkos::HostSpace, Kokkos::Experimental::OpenMPTargetSpace> { enum { value = false }; - inline static void verify( void ) { } - inline static void verify( const void * ) { } + inline static void verify(void) {} + inline static void verify(const void*) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos #endif #endif /* #define KOKKOS_OPENMPTARGETSPACE_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_Pair.hpp b/lib/kokkos/core/src/Kokkos_Pair.hpp index ab0ab8152a..ee9797b4b3 100644 --- a/lib/kokkos/core/src/Kokkos_Pair.hpp +++ b/lib/kokkos/core/src/Kokkos_Pair.hpp @@ -1,10 +1,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -22,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -61,15 +62,14 @@ namespace Kokkos { /// implements the same interface as std::pair, but can be used on a /// CUDA device as well as on the host. template -struct pair -{ +struct pair { //! The first template parameter of this class. typedef T1 first_type; //! The second template parameter of this class. typedef T2 second_type; //! The first element of the pair. - first_type first; + first_type first; //! The second element of the pair. second_type second; @@ -80,54 +80,48 @@ struct pair /// public. KOKKOS_FORCEINLINE_FUNCTION constexpr #ifdef KOKKOS_CUDA_9_DEFAULTED_BUG_WORKAROUND - pair() : first(), second() {} + pair() + : first(), second() { + } #else - pair() = default; + pair() = default; #endif /// \brief Constructor that takes both elements of the pair. /// /// This calls the copy constructors of T1 and T2. It won't compile /// if those copy constructors are not defined and public. - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair(first_type const& f, second_type const& s) - : first(f), second(s) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(first_type const& f, + second_type const& s) + : first(f), second(s) {} /// \brief Copy constructor. /// /// This calls the copy constructors of T1 and T2. It won't compile /// if those copy constructors are not defined and public. template - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair( const pair &p) - : first(p.first), second(p.second) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(const pair& p) + : first(p.first), second(p.second) {} /// \brief Copy constructor. /// /// This calls the copy constructors of T1 and T2. It won't compile /// if those copy constructors are not defined and public. template - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair( const volatile pair &p) - : first(p.first), second(p.second) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(const volatile pair& p) + : first(p.first), second(p.second) {} /// \brief Assignment operator. /// /// This calls the assignment operators of T1 and T2. It won't /// compile if the assignment operators are not defined and public. template - KOKKOS_FORCEINLINE_FUNCTION - pair & operator=(const pair &p) - { - first = p.first; + KOKKOS_FORCEINLINE_FUNCTION pair& operator=(const pair& p) { + first = p.first; second = p.second; return *this; } - /// \brief Assignment operator, for volatile *this. /// /// \param p [in] Input; right-hand side of the assignment. @@ -140,10 +134,9 @@ struct pair /// practice, this means that you should not chain assignments with /// volatile lvalues. template - KOKKOS_FORCEINLINE_FUNCTION - void operator=(const volatile pair &p) volatile - { - first = p.first; + KOKKOS_FORCEINLINE_FUNCTION void operator=( + const volatile pair& p) volatile { + first = p.first; second = p.second; // We deliberately do not return anything here. See explanation // in public documentation above. @@ -151,9 +144,7 @@ struct pair // from std::pair template - pair( const std::pair &p) - : first(p.first), second(p.second) - {} + pair(const std::pair& p) : first(p.first), second(p.second) {} /// \brief Return the std::pair version of this object. /// @@ -164,20 +155,20 @@ struct pair /// \note This is not a conversion operator, since defining a /// conversion operator made the relational operators have /// ambiguous definitions. - std::pair to_std_pair() const - { return std::make_pair(first,second); } + std::pair to_std_pair() const { + return std::make_pair(first, second); + } }; template -struct pair -{ +struct pair { //! The first template parameter of this class. typedef T1& first_type; //! The second template parameter of this class. typedef T2& second_type; //! The first element of the pair. - first_type first; + first_type first; //! The second element of the pair. second_type second; @@ -185,36 +176,29 @@ struct pair /// /// This calls the copy constructors of T1 and T2. It won't compile /// if those copy constructors are not defined and public. - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair(first_type f, second_type s) - : first(f), second(s) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(first_type f, second_type s) + : first(f), second(s) {} /// \brief Copy constructor. /// /// This calls the copy constructors of T1 and T2. It won't compile /// if those copy constructors are not defined and public. template - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair( const pair &p) - : first(p.first), second(p.second) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(const pair& p) + : first(p.first), second(p.second) {} // from std::pair template - pair( const std::pair &p) - : first(p.first), second(p.second) - {} + pair(const std::pair& p) : first(p.first), second(p.second) {} /// \brief Assignment operator. /// /// This calls the assignment operators of T1 and T2. It won't /// compile if the assignment operators are not defined and public. template - KOKKOS_FORCEINLINE_FUNCTION - pair & operator=(const pair &p) - { - first = p.first; + KOKKOS_FORCEINLINE_FUNCTION pair& operator=( + const pair& p) { + first = p.first; second = p.second; return *this; } @@ -228,20 +212,20 @@ struct pair /// \note This is not a conversion operator, since defining a /// conversion operator made the relational operators have /// ambiguous definitions. - std::pair to_std_pair() const - { return std::make_pair(first,second); } + std::pair to_std_pair() const { + return std::make_pair(first, second); + } }; template -struct pair -{ +struct pair { //! The first template parameter of this class. - typedef T1 first_type; + typedef T1 first_type; //! The second template parameter of this class. typedef T2& second_type; //! The first element of the pair. - first_type first; + first_type first; //! The second element of the pair. second_type second; @@ -249,36 +233,29 @@ struct pair /// /// This calls the copy constructors of T1 and T2. It won't compile /// if those copy constructors are not defined and public. - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair(first_type const& f, second_type s) - : first(f), second(s) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(first_type const& f, second_type s) + : first(f), second(s) {} /// \brief Copy constructor. /// /// This calls the copy constructors of T1 and T2. It won't compile /// if those copy constructors are not defined and public. template - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair( const pair &p) - : first(p.first), second(p.second) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(const pair& p) + : first(p.first), second(p.second) {} // from std::pair template - pair( const std::pair &p) - : first(p.first), second(p.second) - {} + pair(const std::pair& p) : first(p.first), second(p.second) {} /// \brief Assignment operator. /// /// This calls the assignment operators of T1 and T2. It won't /// compile if the assignment operators are not defined and public. template - KOKKOS_FORCEINLINE_FUNCTION - pair & operator=(const pair &p) - { - first = p.first; + KOKKOS_FORCEINLINE_FUNCTION pair& operator=( + const pair& p) { + first = p.first; second = p.second; return *this; } @@ -292,20 +269,20 @@ struct pair /// \note This is not a conversion operator, since defining a /// conversion operator made the relational operators have /// ambiguous definitions. - std::pair to_std_pair() const - { return std::make_pair(first,second); } + std::pair to_std_pair() const { + return std::make_pair(first, second); + } }; template -struct pair -{ +struct pair { //! The first template parameter of this class. - typedef T1& first_type; + typedef T1& first_type; //! The second template parameter of this class. typedef T2 second_type; //! The first element of the pair. - first_type first; + first_type first; //! The second element of the pair. second_type second; @@ -313,36 +290,29 @@ struct pair /// /// This calls the copy constructors of T1 and T2. It won't compile /// if those copy constructors are not defined and public. - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair(first_type f, second_type const& s) - : first(f), second(s) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(first_type f, second_type const& s) + : first(f), second(s) {} /// \brief Copy constructor. /// /// This calls the copy constructors of T1 and T2. It won't compile /// if those copy constructors are not defined and public. template - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair( const pair &p) - : first(p.first), second(p.second) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(const pair& p) + : first(p.first), second(p.second) {} // from std::pair template - pair( const std::pair &p) - : first(p.first), second(p.second) - {} + pair(const std::pair& p) : first(p.first), second(p.second) {} /// \brief Assignment operator. /// /// This calls the assignment operators of T1 and T2. It won't /// compile if the assignment operators are not defined and public. template - KOKKOS_FORCEINLINE_FUNCTION - pair & operator=(const pair &p) - { - first = p.first; + KOKKOS_FORCEINLINE_FUNCTION pair& operator=( + const pair& p) { + first = p.first; second = p.second; return *this; } @@ -356,54 +326,62 @@ struct pair /// \note This is not a conversion operator, since defining a /// conversion operator made the relational operators have /// ambiguous definitions. - std::pair to_std_pair() const - { return std::make_pair(first,second); } + std::pair to_std_pair() const { + return std::make_pair(first, second); + } }; //! Equality operator for Kokkos::pair. template -KOKKOS_FORCEINLINE_FUNCTION -bool operator== (const pair& lhs, const pair& rhs) -{ return lhs.first==rhs.first && lhs.second==rhs.second; } +KOKKOS_FORCEINLINE_FUNCTION bool operator==(const pair& lhs, + const pair& rhs) { + return lhs.first == rhs.first && lhs.second == rhs.second; +} //! Inequality operator for Kokkos::pair. template -KOKKOS_FORCEINLINE_FUNCTION constexpr -bool operator!= (const pair& lhs, const pair& rhs) -{ return !(lhs==rhs); } +KOKKOS_FORCEINLINE_FUNCTION constexpr bool operator!=(const pair& lhs, + const pair& rhs) { + return !(lhs == rhs); +} //! Less-than operator for Kokkos::pair. template -KOKKOS_FORCEINLINE_FUNCTION constexpr -bool operator< (const pair& lhs, const pair& rhs) -{ return lhs.first& lhs, + const pair& rhs) { + return lhs.first < rhs.first || + (!(rhs.first < lhs.first) && lhs.second < rhs.second); +} //! Less-than-or-equal-to operator for Kokkos::pair. template -KOKKOS_FORCEINLINE_FUNCTION constexpr -bool operator<= (const pair& lhs, const pair& rhs) -{ return !(rhs& lhs, + const pair& rhs) { + return !(rhs < lhs); +} //! Greater-than operator for Kokkos::pair. template -KOKKOS_FORCEINLINE_FUNCTION constexpr -bool operator> (const pair& lhs, const pair& rhs) -{ return rhs(const pair& lhs, + const pair& rhs) { + return rhs < lhs; +} //! Greater-than-or-equal-to operator for Kokkos::pair. template -KOKKOS_FORCEINLINE_FUNCTION constexpr -bool operator>= (const pair& lhs, const pair& rhs) -{ return !(lhs=(const pair& lhs, + const pair& rhs) { + return !(lhs < rhs); +} /// \brief Return a new pair. /// /// This is a "nonmember constructor" for Kokkos::pair. It works just /// like std::make_pair. -template -KOKKOS_FORCEINLINE_FUNCTION constexpr -pair make_pair (T1 x, T2 y) -{ return ( pair(x,y) ); } +template +KOKKOS_FORCEINLINE_FUNCTION constexpr pair make_pair(T1 x, T2 y) { + return (pair(x, y)); +} /// \brief Return a pair of references to the input arguments. /// @@ -444,51 +422,44 @@ pair make_pair (T1 x, T2 y) /// element of the pair. The latter could be significant if one or /// both elements of the pair are more substantial objects than \c int /// or \c bool. -template -KOKKOS_FORCEINLINE_FUNCTION -pair tie (T1 & x, T2 & y) -{ return ( pair(x,y) ); } +template +KOKKOS_FORCEINLINE_FUNCTION pair tie(T1& x, T2& y) { + return (pair(x, y)); +} // // Specialization of Kokkos::pair for a \c void second argument. This // is not actually a "pair"; it only contains one element, the first. // template -struct pair -{ +struct pair { typedef T1 first_type; typedef void second_type; - first_type first; + first_type first; enum { second = 0 }; KOKKOS_FORCEINLINE_FUNCTION constexpr #ifdef KOKKOS_CUDA_9_DEFAULTED_BUG_WORKAROUND - pair() : first() {} + pair() + : first() { + } #else - pair() = default; + pair() = default; #endif - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair(const first_type & f) - : first(f) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(const first_type& f) : first(f) {} - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair(const first_type & f, int) - : first(f) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(const first_type& f, int) + : first(f) {} template - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair( const pair &p) - : first(p.first) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(const pair& p) + : first(p.first) {} template - KOKKOS_FORCEINLINE_FUNCTION - pair & operator=(const pair &p) - { + KOKKOS_FORCEINLINE_FUNCTION pair& operator=( + const pair& p) { first = p.first; return *this; } @@ -499,46 +470,52 @@ struct pair // template -KOKKOS_FORCEINLINE_FUNCTION constexpr -bool operator== (const pair& lhs, const pair& rhs) -{ return lhs.first==rhs.first; } +KOKKOS_FORCEINLINE_FUNCTION constexpr bool operator==( + const pair& lhs, const pair& rhs) { + return lhs.first == rhs.first; +} template -KOKKOS_FORCEINLINE_FUNCTION constexpr -bool operator!= (const pair& lhs, const pair& rhs) -{ return !(lhs==rhs); } +KOKKOS_FORCEINLINE_FUNCTION constexpr bool operator!=( + const pair& lhs, const pair& rhs) { + return !(lhs == rhs); +} template -KOKKOS_FORCEINLINE_FUNCTION constexpr -bool operator< (const pair& lhs, const pair& rhs) -{ return lhs.first& lhs, const pair& rhs) { + return lhs.first < rhs.first; +} template -KOKKOS_FORCEINLINE_FUNCTION constexpr -bool operator<= (const pair& lhs, const pair& rhs) -{ return !(rhs& lhs, const pair& rhs) { + return !(rhs < lhs); +} template -KOKKOS_FORCEINLINE_FUNCTION constexpr -bool operator> (const pair& lhs, const pair& rhs) -{ return rhs( + const pair& lhs, const pair& rhs) { + return rhs < lhs; +} template -KOKKOS_FORCEINLINE_FUNCTION constexpr -bool operator>= (const pair& lhs, const pair& rhs) -{ return !(lhs=( + const pair& lhs, const pair& rhs) { + return !(lhs < rhs); +} namespace Impl { -template struct is_pair_like : std::false_type { }; -template struct is_pair_like> : std::true_type { }; -template struct is_pair_like> : std::true_type { }; - -} // end namespace Impl - -} // namespace Kokkos +template +struct is_pair_like : std::false_type {}; +template +struct is_pair_like> : std::true_type {}; +template +struct is_pair_like> : std::true_type {}; +} // end namespace Impl -#endif //KOKKOS_PAIR_HPP +} // namespace Kokkos +#endif // KOKKOS_PAIR_HPP diff --git a/lib/kokkos/core/src/Kokkos_Parallel.hpp b/lib/kokkos/core/src/Kokkos_Parallel.hpp index 09dcf60b11..7277ce287a 100644 --- a/lib/kokkos/core/src/Kokkos_Parallel.hpp +++ b/lib/kokkos/core/src/Kokkos_Parallel.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -63,7 +64,7 @@ #include #ifdef KOKKOS_DEBUG -#include +#include #endif //---------------------------------------------------------------------------- @@ -80,67 +81,52 @@ namespace Impl { * else if the Functor has a device_type use that for backward compatibility * else use the default */ -template< class Functor - , class Policy - , class EnableFunctor - , class EnablePolicy - > +template struct FunctorPolicyExecutionSpace { - typedef Kokkos::DefaultExecutionSpace execution_space ; + typedef Kokkos::DefaultExecutionSpace execution_space; }; -template< class Functor , class Policy > -struct FunctorPolicyExecutionSpace - < Functor , Policy - , typename enable_if_type< typename Functor::device_type >::type - , typename enable_if_type< typename Policy ::execution_space >::type - > -{ - typedef typename Policy ::execution_space execution_space ; +template +struct FunctorPolicyExecutionSpace< + Functor, Policy, + typename enable_if_type::type, + typename enable_if_type::type> { + typedef typename Policy ::execution_space execution_space; }; -template< class Functor , class Policy > -struct FunctorPolicyExecutionSpace - < Functor , Policy - , typename enable_if_type< typename Functor::execution_space >::type - , typename enable_if_type< typename Policy ::execution_space >::type - > -{ - typedef typename Policy ::execution_space execution_space ; +template +struct FunctorPolicyExecutionSpace< + Functor, Policy, + typename enable_if_type::type, + typename enable_if_type::type> { + typedef typename Policy ::execution_space execution_space; }; -template< class Functor , class Policy , class EnableFunctor > -struct FunctorPolicyExecutionSpace - < Functor , Policy - , EnableFunctor - , typename enable_if_type< typename Policy::execution_space >::type - > -{ - typedef typename Policy ::execution_space execution_space ; +template +struct FunctorPolicyExecutionSpace< + Functor, Policy, EnableFunctor, + typename enable_if_type::type> { + typedef typename Policy ::execution_space execution_space; }; -template< class Functor , class Policy , class EnablePolicy > -struct FunctorPolicyExecutionSpace - < Functor , Policy - , typename enable_if_type< typename Functor::device_type >::type - , EnablePolicy - > -{ - typedef typename Functor::device_type execution_space ; +template +struct FunctorPolicyExecutionSpace< + Functor, Policy, + typename enable_if_type::type, + EnablePolicy> { + typedef typename Functor::device_type execution_space; }; -template< class Functor , class Policy , class EnablePolicy > -struct FunctorPolicyExecutionSpace - < Functor , Policy - , typename enable_if_type< typename Functor::execution_space >::type - , EnablePolicy - > -{ - typedef typename Functor::execution_space execution_space ; +template +struct FunctorPolicyExecutionSpace< + Functor, Policy, + typename enable_if_type::type, + EnablePolicy> { + typedef typename Functor::execution_space execution_space; }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -168,89 +154,82 @@ namespace Kokkos { * This compares to a single iteration \c iwork of a \c for loop. * If \c execution_space is not defined DefaultExecutionSpace will be used. */ -template< class ExecPolicy , class FunctorType > -inline -void parallel_for( const ExecPolicy & policy - , const FunctorType & functor - , const std::string& str = "" - , typename Impl::enable_if< Kokkos::Impl::is_execution_policy< ExecPolicy >::value >::type * = 0 - ) -{ +template +inline void parallel_for( + const ExecPolicy& policy, const FunctorType& functor, + const std::string& str = "", + typename Impl::enable_if< + Kokkos::Impl::is_execution_policy::value>::type* = 0) { #if defined(KOKKOS_ENABLE_PROFILING) uint64_t kpID = 0; - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Impl::ParallelConstructName name(str); + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Impl::ParallelConstructName + name(str); Kokkos::Profiling::beginParallelFor(name.get(), 0, &kpID); } #endif - Kokkos::Impl::shared_allocation_tracking_disable(); - Impl::ParallelFor< FunctorType , ExecPolicy > closure( functor , policy ); - Kokkos::Impl::shared_allocation_tracking_enable(); + Kokkos::Impl::shared_allocation_tracking_disable(); + Impl::ParallelFor closure(functor, policy); + Kokkos::Impl::shared_allocation_tracking_enable(); - closure.execute(); + closure.execute(); #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { + if (Kokkos::Profiling::profileLibraryLoaded()) { Kokkos::Profiling::endParallelFor(kpID); } #endif } -template< class FunctorType > -inline -void parallel_for( const size_t work_count - , const FunctorType & functor - , const std::string& str = "" - ) -{ - typedef typename - Impl::FunctorPolicyExecutionSpace< FunctorType , void >::execution_space - execution_space ; - typedef RangePolicy< execution_space > policy ; +template +inline void parallel_for(const size_t work_count, const FunctorType& functor, + const std::string& str = "") { + typedef typename Impl::FunctorPolicyExecutionSpace< + FunctorType, void>::execution_space execution_space; + typedef RangePolicy policy; #if defined(KOKKOS_ENABLE_PROFILING) uint64_t kpID = 0; - if(Kokkos::Profiling::profileLibraryLoaded()) { + if (Kokkos::Profiling::profileLibraryLoaded()) { Kokkos::Impl::ParallelConstructName name(str); Kokkos::Profiling::beginParallelFor(name.get(), 0, &kpID); } #endif Kokkos::Impl::shared_allocation_tracking_disable(); - Impl::ParallelFor< FunctorType , policy > closure( functor , policy(0,work_count) ); + Impl::ParallelFor closure(functor, + policy(0, work_count)); Kokkos::Impl::shared_allocation_tracking_enable(); closure.execute(); #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::endParallelFor(kpID); - } + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endParallelFor(kpID); + } #endif } -template< class ExecPolicy , class FunctorType > -inline -void parallel_for( const std::string & str - , const ExecPolicy & policy - , const FunctorType & functor ) -{ - #if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES +template +inline void parallel_for(const std::string& str, const ExecPolicy& policy, + const FunctorType& functor) { +#if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES Kokkos::fence(); std::cout << "KOKKOS_DEBUG Start parallel_for kernel: " << str << std::endl; - #endif +#endif - ::Kokkos::parallel_for(policy,functor,str); + ::Kokkos::parallel_for(policy, functor, str); - #if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES +#if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES Kokkos::fence(); std::cout << "KOKKOS_DEBUG End parallel_for kernel: " << str << std::endl; - #endif - (void) str; +#endif + (void)str; } -} +} // namespace Kokkos #include //---------------------------------------------------------------------------- @@ -291,9 +270,9 @@ namespace Kokkos { /// // operator() or join(). /// typedef PodType value_type; /// -/// void operator () (const ExecPolicy::member_type & i, value_type& update, const bool final_pass) const; -/// void init (value_type& update) const; -/// void join (volatile value_type& update, volatile const value_type& input) const +/// void operator () (const ExecPolicy::member_type & i, value_type& update, +/// const bool final_pass) const; void init (value_type& update) const; void +/// join (volatile value_type& update, volatile const value_type& input) const /// }; /// \endcode /// @@ -310,9 +289,11 @@ namespace Kokkos { /// typedef typename SpaceType::size_type size_type; /// /// InclScanFunctor( Kokkos::View x -/// , Kokkos::View y ) : m_x(x), m_y(y) {} +/// , Kokkos::View y ) : m_x(x), +/// m_y(y) {} /// -/// void operator () (const size_type i, value_type& update, const bool final_pass) const { +/// void operator () (const size_type i, value_type& update, const bool +/// final_pass) const { /// update += m_x(i); /// if (final_pass) { /// m_y(i) = update; @@ -321,7 +302,8 @@ namespace Kokkos { /// void init (value_type& update) const { /// update = 0; /// } -/// void join (volatile value_type& update, volatile const value_type& input) const { +/// void join (volatile value_type& update, volatile const value_type& input) +/// const { /// update += input; /// } /// @@ -347,7 +329,8 @@ namespace Kokkos { /// /// ExclScanFunctor (Kokkos::View x) : x_ (x) {} /// -/// void operator () (const size_type i, value_type& update, const bool final_pass) const { +/// void operator () (const size_type i, value_type& update, const bool +/// final_pass) const { /// const value_type x_i = x_(i); /// if (final_pass) { /// x_(i) = update; @@ -357,7 +340,8 @@ namespace Kokkos { /// void init (value_type& update) const { /// update = 0; /// } -/// void join (volatile value_type& update, volatile const value_type& input) const { +/// void join (volatile value_type& update, volatile const value_type& input) +/// const { /// update += input; /// } /// @@ -385,10 +369,12 @@ namespace Kokkos { /// // If x has length zero, then lastIndex_ won't be used anyway. /// OffsetScanFunctor( Kokkos::View x /// , Kokkos::View y ) -/// : m_x(x), m_y(y), last_index_ (x.dimension_0 () == 0 ? 0 : x.dimension_0 () - 1) +/// : m_x(x), m_y(y), last_index_ (x.dimension_0 () == 0 ? 0 : +/// x.dimension_0 () - 1) /// {} /// -/// void operator () (const size_type i, int& update, const bool final_pass) const { +/// void operator () (const size_type i, int& update, const bool final_pass) +/// const { /// if (final_pass) { /// m_y(i) = update; /// } @@ -396,12 +382,13 @@ namespace Kokkos { /// // The last entry of m_y gets the final sum. /// if (final_pass && i == last_index_) { /// m_y(i+1) = update; -//i/ } +// i/ } /// } /// void init (value_type& update) const { /// update = 0; /// } -/// void join (volatile value_type& update, volatile const value_type& input) const { +/// void join (volatile value_type& update, volatile const value_type& input) +/// const { /// update += input; /// } /// @@ -412,181 +399,164 @@ namespace Kokkos { /// }; /// \endcode /// -template< class ExecutionPolicy , class FunctorType > -inline -void parallel_scan( const ExecutionPolicy & policy - , const FunctorType & functor - , const std::string& str = "" - , typename Impl::enable_if< Kokkos::Impl::is_execution_policy< ExecutionPolicy >::value >::type * = 0 - ) -{ +template +inline void parallel_scan( + const ExecutionPolicy& policy, const FunctorType& functor, + const std::string& str = "", + typename Impl::enable_if< + Kokkos::Impl::is_execution_policy::value>::type* = 0) { #if defined(KOKKOS_ENABLE_PROFILING) uint64_t kpID = 0; - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Impl::ParallelConstructName name(str); + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Impl::ParallelConstructName + name(str); Kokkos::Profiling::beginParallelScan(name.get(), 0, &kpID); } #endif Kokkos::Impl::shared_allocation_tracking_disable(); - Impl::ParallelScan< FunctorType , ExecutionPolicy > closure( functor , policy ); + Impl::ParallelScan closure(functor, policy); Kokkos::Impl::shared_allocation_tracking_enable(); - + closure.execute(); #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { + if (Kokkos::Profiling::profileLibraryLoaded()) { Kokkos::Profiling::endParallelScan(kpID); } #endif - } -template< class FunctorType > -inline -void parallel_scan( const size_t work_count - , const FunctorType & functor - , const std::string& str = "" ) -{ - typedef typename - Kokkos::Impl::FunctorPolicyExecutionSpace< FunctorType , void >::execution_space - execution_space ; +template +inline void parallel_scan(const size_t work_count, const FunctorType& functor, + const std::string& str = "") { + typedef typename Kokkos::Impl::FunctorPolicyExecutionSpace< + FunctorType, void>::execution_space execution_space; - typedef Kokkos::RangePolicy< execution_space > policy ; + typedef Kokkos::RangePolicy policy; #if defined(KOKKOS_ENABLE_PROFILING) uint64_t kpID = 0; - if(Kokkos::Profiling::profileLibraryLoaded()) { + if (Kokkos::Profiling::profileLibraryLoaded()) { Kokkos::Impl::ParallelConstructName name(str); Kokkos::Profiling::beginParallelScan(name.get(), 0, &kpID); } #endif Kokkos::Impl::shared_allocation_tracking_disable(); - Impl::ParallelScan< FunctorType , policy > closure( functor , policy(0,work_count) ); + Impl::ParallelScan closure(functor, + policy(0, work_count)); Kokkos::Impl::shared_allocation_tracking_enable(); - + closure.execute(); #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { + if (Kokkos::Profiling::profileLibraryLoaded()) { Kokkos::Profiling::endParallelScan(kpID); } #endif - } -template< class ExecutionPolicy , class FunctorType > -inline -void parallel_scan( const std::string& str - , const ExecutionPolicy & policy - , const FunctorType & functor) -{ - #if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES +template +inline void parallel_scan(const std::string& str, const ExecutionPolicy& policy, + const FunctorType& functor) { +#if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES Kokkos::fence(); std::cout << "KOKKOS_DEBUG Start parallel_scan kernel: " << str << std::endl; - #endif - - ::Kokkos::parallel_scan(policy,functor,str); +#endif + + ::Kokkos::parallel_scan(policy, functor, str); - #if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES +#if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES Kokkos::fence(); std::cout << "KOKKOS_DEBUG End parallel_scan kernel: " << str << std::endl; - #endif - (void) str; +#endif + (void)str; } - -template< class ExecutionPolicy , class FunctorType, class ReturnType > -inline -void parallel_scan( const ExecutionPolicy & policy - , const FunctorType & functor - , ReturnType & return_value - , const std::string& str = "" - , typename Impl::enable_if< Kokkos::Impl::is_execution_policy< ExecutionPolicy >::value >::type * = 0 - ) -{ +template +inline void parallel_scan( + const ExecutionPolicy& policy, const FunctorType& functor, + ReturnType& return_value, const std::string& str = "", + typename Impl::enable_if< + Kokkos::Impl::is_execution_policy::value>::type* = 0) { #if defined(KOKKOS_ENABLE_PROFILING) uint64_t kpID = 0; - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Impl::ParallelConstructName name(str); + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Impl::ParallelConstructName + name(str); Kokkos::Profiling::beginParallelScan(name.get(), 0, &kpID); } #endif Kokkos::Impl::shared_allocation_tracking_disable(); - Impl::ParallelScanWithTotal< FunctorType , ExecutionPolicy, ReturnType > closure( functor, policy, return_value ); + Impl::ParallelScanWithTotal closure( + functor, policy, return_value); Kokkos::Impl::shared_allocation_tracking_enable(); - + closure.execute(); #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { + if (Kokkos::Profiling::profileLibraryLoaded()) { Kokkos::Profiling::endParallelScan(kpID); } #endif Kokkos::fence(); } -template< class FunctorType, class ReturnType > -inline -void parallel_scan( const size_t work_count - , const FunctorType & functor - , ReturnType & return_value - , const std::string & str = "" ) -{ - typedef typename - Kokkos::Impl::FunctorPolicyExecutionSpace< FunctorType , void >::execution_space - execution_space ; +template +inline void parallel_scan(const size_t work_count, const FunctorType& functor, + ReturnType& return_value, + const std::string& str = "") { + typedef typename Kokkos::Impl::FunctorPolicyExecutionSpace< + FunctorType, void>::execution_space execution_space; - typedef Kokkos::RangePolicy< execution_space > policy ; + typedef Kokkos::RangePolicy policy; #if defined(KOKKOS_ENABLE_PROFILING) uint64_t kpID = 0; - if(Kokkos::Profiling::profileLibraryLoaded()) { + if (Kokkos::Profiling::profileLibraryLoaded()) { Kokkos::Impl::ParallelConstructName name(str); Kokkos::Profiling::beginParallelScan(name.get(), 0, &kpID); } #endif Kokkos::Impl::shared_allocation_tracking_disable(); - Impl::ParallelScanWithTotal< FunctorType, policy, ReturnType > closure( functor, policy(0,work_count), return_value ); + Impl::ParallelScanWithTotal closure( + functor, policy(0, work_count), return_value); Kokkos::Impl::shared_allocation_tracking_enable(); - + closure.execute(); #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { + if (Kokkos::Profiling::profileLibraryLoaded()) { Kokkos::Profiling::endParallelScan(kpID); } #endif Kokkos::fence(); } -template< class ExecutionPolicy, class FunctorType, class ReturnType > -inline -void parallel_scan( const std::string& str - , const ExecutionPolicy & policy - , const FunctorType & functor - , ReturnType & return_value) -{ - #if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES +template +inline void parallel_scan(const std::string& str, const ExecutionPolicy& policy, + const FunctorType& functor, + ReturnType& return_value) { +#if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES Kokkos::fence(); std::cout << "KOKKOS_DEBUG Start parallel_scan kernel: " << str << std::endl; - #endif - - ::Kokkos::parallel_scan(policy,functor,return_value,str); +#endif + + ::Kokkos::parallel_scan(policy, functor, return_value, str); - #if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES +#if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES Kokkos::fence(); std::cout << "KOKKOS_DEBUG End parallel_scan kernel: " << str << std::endl; - #endif - (void) str; +#endif + (void)str; } - - -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -594,29 +564,35 @@ void parallel_scan( const std::string& str namespace Kokkos { namespace Impl { -template< class FunctorType , class Enable = void > -struct FunctorTeamShmemSize -{ - KOKKOS_INLINE_FUNCTION static size_t value( const FunctorType & , int ) { return 0 ; } +template +struct FunctorTeamShmemSize { + KOKKOS_INLINE_FUNCTION static size_t value(const FunctorType&, int) { + return 0; + } }; -template< class FunctorType > -struct FunctorTeamShmemSize< FunctorType , typename Impl::enable_if< 0 < sizeof( & FunctorType::team_shmem_size ) >::type > -{ - static inline size_t value( const FunctorType & f , int team_size ) { return f.team_shmem_size( team_size ) ; } +template +struct FunctorTeamShmemSize< + FunctorType, + typename Impl::enable_if<0 < sizeof(&FunctorType::team_shmem_size)>::type> { + static inline size_t value(const FunctorType& f, int team_size) { + return f.team_shmem_size(team_size); + } }; -template< class FunctorType > -struct FunctorTeamShmemSize< FunctorType , typename Impl::enable_if< 0 < sizeof( & FunctorType::shmem_size ) >::type > -{ - static inline size_t value( const FunctorType & f , int team_size ) { return f.shmem_size( team_size ) ; } +template +struct FunctorTeamShmemSize< + FunctorType, + typename Impl::enable_if<0 < sizeof(&FunctorType::shmem_size)>::type> { + static inline size_t value(const FunctorType& f, int team_size) { + return f.shmem_size(team_size); + } }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- #endif /* KOKKOS_PARALLEL_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_Parallel_Reduce.hpp b/lib/kokkos/core/src/Kokkos_Parallel_Reduce.hpp index 0e02c468e4..1fa23f714f 100644 --- a/lib/kokkos/core/src/Kokkos_Parallel_Reduce.hpp +++ b/lib/kokkos/core/src/Kokkos_Parallel_Reduce.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,46 +49,43 @@ namespace Kokkos { -template +template struct is_reducer_type { enum { value = 0 }; }; - -template -struct is_reducer_type::type, - typename std::remove_cv::type>::value - >::type> { +template +struct is_reducer_type< + T, typename std::enable_if::type, + typename std::remove_cv::type>::value>::type> { enum { value = 1 }; }; -template +template struct Sum { -public: - //Required + public: + // Required typedef Sum reducer; typedef typename std::remove_cv::type value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - Sum(value_type& value_): value(&value_),references_scalar_v(true) {} + Sum(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - Sum(const result_view_type& value_): value(value_),references_scalar_v(false) {} + Sum(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} - //Required + // Required KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { - dest += src; - } + void join(value_type& dest, const value_type& src) const { dest += src; } KOKKOS_INLINE_FUNCTION void join(volatile value_type& dest, const volatile value_type& src) const { @@ -95,52 +93,44 @@ public: } KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { + void init(value_type& val) const { val = reduction_identity::sum(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -template +template struct Prod { -public: - //Required + public: + // Required typedef Prod reducer; typedef typename std::remove_cv::type value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - Prod(value_type& value_): value(&value_),references_scalar_v(true) {} + Prod(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - Prod(const result_view_type& value_): value(value_),references_scalar_v(false) {} + Prod(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} - //Required + // Required KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { - dest *= src; - } + void join(value_type& dest, const value_type& src) const { dest *= src; } KOKKOS_INLINE_FUNCTION void join(volatile value_type& dest, const volatile value_type& src) const { @@ -148,160 +138,138 @@ public: } KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { + void init(value_type& val) const { val = reduction_identity::prod(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -template +template struct Min { -public: - //Required + public: + // Required typedef Min reducer; typedef typename std::remove_cv::type value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - Min(value_type& value_): value(&value_),references_scalar_v(true) {} + Min(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - Min(const result_view_type& value_): value(value_),references_scalar_v(false) {} + Min(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} - //Required + // Required KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { - if ( src < dest ) - dest = src; + void join(value_type& dest, const value_type& src) const { + if (src < dest) dest = src; } KOKKOS_INLINE_FUNCTION void join(volatile value_type& dest, const volatile value_type& src) const { - if ( src < dest ) - dest = src; + if (src < dest) dest = src; } KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { + void init(value_type& val) const { val = reduction_identity::min(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -template +template struct Max { -public: - //Required + public: + // Required typedef Max reducer; typedef typename std::remove_cv::type value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - Max(value_type& value_): value(&value_),references_scalar_v(true) {} + Max(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - Max(const result_view_type& value_): value(value_),references_scalar_v(false) {} + Max(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} - //Required + // Required KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { - if ( src > dest ) - dest = src; + void join(value_type& dest, const value_type& src) const { + if (src > dest) dest = src; } KOKKOS_INLINE_FUNCTION void join(volatile value_type& dest, const volatile value_type& src) const { - if ( src > dest ) - dest = src; + if (src > dest) dest = src; } - //Required + // Required KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { + void init(value_type& val) const { val = reduction_identity::max(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -template +template struct LAnd { -public: - //Required + public: + // Required typedef LAnd reducer; typedef typename std::remove_cv::type value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - LAnd(value_type& value_): value(&value_),references_scalar_v(true) {} + LAnd(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - LAnd(const result_view_type& value_): value(value_),references_scalar_v(false) {} + LAnd(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { + void join(value_type& dest, const value_type& src) const { dest = dest && src; } @@ -311,50 +279,44 @@ public: } KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { + void init(value_type& val) const { val = reduction_identity::land(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -template +template struct LOr { -public: - //Required + public: + // Required typedef LOr reducer; typedef typename std::remove_cv::type value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - LOr(value_type& value_): value(&value_),references_scalar_v(true) {} + LOr(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - LOr(const result_view_type& value_): value(value_),references_scalar_v(false) {} + LOr(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} - //Required + // Required KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { + void join(value_type& dest, const value_type& src) const { dest = dest || src; } @@ -364,51 +326,45 @@ public: } KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { + void init(value_type& val) const { val = reduction_identity::lor(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -template +template struct BAnd { -public: - //Required + public: + // Required typedef BAnd reducer; typedef typename std::remove_cv::type value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - BAnd(value_type& value_): value(&value_),references_scalar_v(true) {} + BAnd(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - BAnd(const result_view_type& value_): value(value_),references_scalar_v(false) {} + BAnd(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} - //Required + // Required KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { - dest = dest & src; + void join(value_type& dest, const value_type& src) const { + dest = dest & src; } KOKKOS_INLINE_FUNCTION @@ -417,51 +373,45 @@ public: } KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { + void init(value_type& val) const { val = reduction_identity::band(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -template +template struct BOr { -public: - //Required + public: + // Required typedef BOr reducer; typedef typename std::remove_cv::type value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - BOr(value_type& value_): value(&value_),references_scalar_v(true) {} + BOr(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - BOr(const result_view_type& value_): value(value_),references_scalar_v(false) {} + BOr(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} - //Required + // Required KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { - dest = dest | src; + void join(value_type& dest, const value_type& src) const { + dest = dest | src; } KOKKOS_INLINE_FUNCTION @@ -470,256 +420,229 @@ public: } KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { + void init(value_type& val) const { val = reduction_identity::bor(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -template +template struct ValLocScalar { Scalar val; Index loc; KOKKOS_INLINE_FUNCTION - void operator = (const ValLocScalar& rhs) { + void operator=(const ValLocScalar& rhs) { val = rhs.val; loc = rhs.loc; } KOKKOS_INLINE_FUNCTION - void operator = (const volatile ValLocScalar& rhs) volatile { + void operator=(const volatile ValLocScalar& rhs) volatile { val = rhs.val; loc = rhs.loc; } }; -template +template struct MinLoc { -private: + private: typedef typename std::remove_cv::type scalar_type; typedef typename std::remove_cv::type index_type; -public: - //Required + public: + // Required typedef MinLoc reducer; - typedef ValLocScalar value_type; + typedef ValLocScalar value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - MinLoc(value_type& value_): value(&value_),references_scalar_v(true) {} + MinLoc(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - MinLoc(const result_view_type& value_): value(value_),references_scalar_v(false) {} - + MinLoc(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} - //Required + // Required KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { - if ( src.val < dest.val ) - dest = src; + void join(value_type& dest, const value_type& src) const { + if (src.val < dest.val) dest = src; } KOKKOS_INLINE_FUNCTION void join(volatile value_type& dest, const volatile value_type& src) const { - if ( src.val < dest.val ) - dest = src; + if (src.val < dest.val) dest = src; } KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { + void init(value_type& val) const { val.val = reduction_identity::min(); val.loc = reduction_identity::min(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -template +template struct MaxLoc { -private: + private: typedef typename std::remove_cv::type scalar_type; typedef typename std::remove_cv::type index_type; -public: - //Required + public: + // Required typedef MaxLoc reducer; - typedef ValLocScalar value_type; + typedef ValLocScalar value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - MaxLoc(value_type& value_): value(&value_),references_scalar_v(true) {} + MaxLoc(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - MaxLoc(const result_view_type& value_): value(value_),references_scalar_v(false) {} + MaxLoc(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} - //Required + // Required KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { - if ( src.val > dest.val ) - dest = src; + void join(value_type& dest, const value_type& src) const { + if (src.val > dest.val) dest = src; } KOKKOS_INLINE_FUNCTION void join(volatile value_type& dest, const volatile value_type& src) const { - if ( src.val > dest.val ) - dest = src; + if (src.val > dest.val) dest = src; } KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { - val.val = reduction_identity::max();; + void init(value_type& val) const { + val.val = reduction_identity::max(); + ; val.loc = reduction_identity::min(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -template +template struct MinMaxScalar { - Scalar min_val,max_val; + Scalar min_val, max_val; KOKKOS_INLINE_FUNCTION - void operator = (const MinMaxScalar& rhs) { + void operator=(const MinMaxScalar& rhs) { min_val = rhs.min_val; max_val = rhs.max_val; } KOKKOS_INLINE_FUNCTION - void operator = (const volatile MinMaxScalar& rhs) volatile { + void operator=(const volatile MinMaxScalar& rhs) volatile { min_val = rhs.min_val; max_val = rhs.max_val; } }; -template +template struct MinMax { -private: + private: typedef typename std::remove_cv::type scalar_type; -public: - //Required + public: + // Required typedef MinMax reducer; typedef MinMaxScalar value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - MinMax(value_type& value_): value(&value_),references_scalar_v(true) {} + MinMax(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - MinMax(const result_view_type& value_): value(value_),references_scalar_v(false) {} + MinMax(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} - //Required + // Required KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { - if ( src.min_val < dest.min_val ) { + void join(value_type& dest, const value_type& src) const { + if (src.min_val < dest.min_val) { dest.min_val = src.min_val; } - if ( src.max_val > dest.max_val ) { + if (src.max_val > dest.max_val) { dest.max_val = src.max_val; } } KOKKOS_INLINE_FUNCTION void join(volatile value_type& dest, const volatile value_type& src) const { - if ( src.min_val < dest.min_val ) { + if (src.min_val < dest.min_val) { dest.min_val = src.min_val; } - if ( src.max_val > dest.max_val ) { + if (src.max_val > dest.max_val) { dest.max_val = src.max_val; } } KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { - val.max_val = reduction_identity::max();; + void init(value_type& val) const { + val.max_val = reduction_identity::max(); + ; val.min_val = reduction_identity::min(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -template +template struct MinMaxLocScalar { - Scalar min_val,max_val; - Index min_loc,max_loc; + Scalar min_val, max_val; + Index min_loc, max_loc; KOKKOS_INLINE_FUNCTION - void operator = (const MinMaxLocScalar& rhs) { + void operator=(const MinMaxLocScalar& rhs) { min_val = rhs.min_val; min_loc = rhs.min_loc; max_val = rhs.max_val; @@ -727,7 +650,7 @@ struct MinMaxLocScalar { } KOKKOS_INLINE_FUNCTION - void operator = (const volatile MinMaxLocScalar& rhs) volatile { + void operator=(const volatile MinMaxLocScalar& rhs) volatile { min_val = rhs.min_val; min_loc = rhs.min_loc; max_val = rhs.max_val; @@ -735,39 +658,39 @@ struct MinMaxLocScalar { } }; -template +template struct MinMaxLoc { -private: + private: typedef typename std::remove_cv::type scalar_type; typedef typename std::remove_cv::type index_type; -public: - //Required + public: + // Required typedef MinMaxLoc reducer; - typedef MinMaxLocScalar value_type; + typedef MinMaxLocScalar value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - MinMaxLoc(value_type& value_): value(&value_),references_scalar_v(true) {} + MinMaxLoc(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - MinMaxLoc(const result_view_type& value_): value(value_),references_scalar_v(false) {} + MinMaxLoc(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} - //Required + // Required KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { - if ( src.min_val < dest.min_val ) { + void join(value_type& dest, const value_type& src) const { + if (src.min_val < dest.min_val) { dest.min_val = src.min_val; dest.min_loc = src.min_loc; } - if ( src.max_val > dest.max_val ) { + if (src.max_val > dest.max_val) { dest.max_val = src.max_val; dest.max_loc = src.max_loc; } @@ -775,71 +698,68 @@ public: KOKKOS_INLINE_FUNCTION void join(volatile value_type& dest, const volatile value_type& src) const { - if ( src.min_val < dest.min_val ) { + if (src.min_val < dest.min_val) { dest.min_val = src.min_val; dest.min_loc = src.min_loc; } - if ( src.max_val > dest.max_val ) { + if (src.max_val > dest.max_val) { dest.max_val = src.max_val; dest.max_loc = src.max_loc; } } KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { - val.max_val = reduction_identity::max();; + void init(value_type& val) const { + val.max_val = reduction_identity::max(); + ; val.min_val = reduction_identity::min(); val.max_loc = reduction_identity::min(); val.min_loc = reduction_identity::min(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -} -namespace Kokkos{ +} // namespace Kokkos +namespace Kokkos { namespace Impl { -template< class T, class ReturnType , class ValueTraits> +template struct ParallelReduceReturnValue; -template< class ReturnType , class FunctorType > -struct ParallelReduceReturnValue::value>::type, ReturnType, FunctorType> { +template +struct ParallelReduceReturnValue< + typename std::enable_if::value>::type, + ReturnType, FunctorType> { typedef ReturnType return_type; typedef InvalidType reducer_type; typedef typename return_type::value_type value_type_scalar; typedef typename return_type::value_type* const value_type_array; - typedef typename if_c::type value_type; + typedef typename if_c::type value_type; static return_type& return_value(ReturnType& return_val, const FunctorType&) { return return_val; } }; -template< class ReturnType , class FunctorType> -struct ParallelReduceReturnValue::value && - (!std::is_array::value && !std::is_pointer::value) && - !Kokkos::is_reducer_type::value - >::type, ReturnType, FunctorType> { - typedef Kokkos::View< ReturnType - , Kokkos::HostSpace - , Kokkos::MemoryUnmanaged - > return_type; +template +struct ParallelReduceReturnValue< + typename std::enable_if::value && + (!std::is_array::value && + !std::is_pointer::value) && + !Kokkos::is_reducer_type::value>::type, + ReturnType, FunctorType> { + typedef Kokkos::View + return_type; typedef InvalidType reducer_type; @@ -850,14 +770,14 @@ struct ParallelReduceReturnValue -struct ParallelReduceReturnValue::value || std::is_pointer::value) - >::type, ReturnType, FunctorType> { - typedef Kokkos::View< typename std::remove_const::type - , Kokkos::HostSpace - , Kokkos::MemoryUnmanaged - > return_type; +template +struct ParallelReduceReturnValue< + typename std::enable_if<(is_array::value || + std::is_pointer::value)>::type, + ReturnType, FunctorType> { + typedef Kokkos::View::type, + Kokkos::HostSpace, Kokkos::MemoryUnmanaged> + return_type; typedef InvalidType reducer_type; @@ -866,150 +786,154 @@ struct ParallelReduceReturnValue::value ) + if (is_array::value) return return_type(return_val); else - return return_type(return_val,functor.value_count); + return return_type(return_val, functor.value_count); #endif } }; -template< class ReturnType , class FunctorType> -struct ParallelReduceReturnValue::value - >::type, ReturnType, FunctorType> { +template +struct ParallelReduceReturnValue< + typename std::enable_if::value>::type, + ReturnType, FunctorType> { typedef ReturnType return_type; typedef ReturnType reducer_type; typedef typename return_type::value_type value_type; - static return_type return_value(ReturnType& return_val, - const FunctorType&) { + static return_type return_value(ReturnType& return_val, const FunctorType&) { return return_val; } }; -template< class T, class ReturnType , class FunctorType> +template struct ParallelReducePolicyType; -template< class PolicyType , class FunctorType > -struct ParallelReducePolicyType::value>::type, PolicyType,FunctorType> { - +template +struct ParallelReducePolicyType< + typename std::enable_if< + Kokkos::Impl::is_execution_policy::value>::type, + PolicyType, FunctorType> { typedef PolicyType policy_type; - static PolicyType policy(const PolicyType& policy_) { - return policy_; - } + static PolicyType policy(const PolicyType& policy_) { return policy_; } }; -template< class PolicyType , class FunctorType > -struct ParallelReducePolicyType::value>::type, PolicyType,FunctorType> { - typedef typename - Impl::FunctorPolicyExecutionSpace< FunctorType , void >::execution_space - execution_space ; +template +struct ParallelReducePolicyType< + typename std::enable_if::value>::type, + PolicyType, FunctorType> { + typedef typename Impl::FunctorPolicyExecutionSpace< + FunctorType, void>::execution_space execution_space; typedef Kokkos::RangePolicy policy_type; static policy_type policy(const PolicyType& policy_) { - return policy_type(0,policy_); + return policy_type(0, policy_); } }; +template +struct ParallelReduceFunctorType { + typedef FunctorType functor_type; + static const functor_type& functor(const functor_type& functor) { + return functor; + } +}; - template< class FunctorType, class ExecPolicy, class ValueType, class ExecutionSpace> - struct ParallelReduceFunctorType { - typedef FunctorType functor_type; - static const functor_type& functor(const functor_type& functor) { - return functor; +template +struct ParallelReduceAdaptor { + typedef Impl::ParallelReduceReturnValue + return_value_adapter; +#ifdef KOKKOS_IMPL_NEED_FUNCTOR_WRAPPER + typedef Impl::ParallelReduceFunctorType< + FunctorType, PolicyType, typename return_value_adapter::value_type, + typename PolicyType::execution_space> + functor_adaptor; +#endif + static inline void execute(const std::string& label, const PolicyType& policy, + const FunctorType& functor, + ReturnType& return_value) { +#if defined(KOKKOS_ENABLE_PROFILING) + uint64_t kpID = 0; + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Impl::ParallelConstructName + name(label); + Kokkos::Profiling::beginParallelReduce(name.get(), 0, &kpID); } - }; +#endif - template< class PolicyType, class FunctorType, class ReturnType > - struct ParallelReduceAdaptor { - typedef Impl::ParallelReduceReturnValue return_value_adapter; - #ifdef KOKKOS_IMPL_NEED_FUNCTOR_WRAPPER - typedef Impl::ParallelReduceFunctorType functor_adaptor; - #endif - static inline - void execute(const std::string& label, - const PolicyType& policy, - const FunctorType& functor, - ReturnType& return_value) { - #if defined(KOKKOS_ENABLE_PROFILING) - uint64_t kpID = 0; - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Impl::ParallelConstructName name(label); - Kokkos::Profiling::beginParallelReduce(name.get(), 0, &kpID); - } - #endif - - Kokkos::Impl::shared_allocation_tracking_disable(); - #ifdef KOKKOS_IMPL_NEED_FUNCTOR_WRAPPER - Impl::ParallelReduce - closure(functor_adaptor::functor(functor), - policy, - return_value_adapter::return_value(return_value,functor)); - #else - Impl::ParallelReduce - closure(functor, - policy, - return_value_adapter::return_value(return_value,functor)); - #endif - Kokkos::Impl::shared_allocation_tracking_enable(); - closure.execute(); - - #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::endParallelReduce(kpID); - } - #endif - } + Kokkos::Impl::shared_allocation_tracking_disable(); +#ifdef KOKKOS_IMPL_NEED_FUNCTOR_WRAPPER + Impl::ParallelReduce + closure(functor_adaptor::functor(functor), policy, + return_value_adapter::return_value(return_value, functor)); +#else + Impl::ParallelReduce + closure(functor, policy, + return_value_adapter::return_value(return_value, functor)); +#endif + Kokkos::Impl::shared_allocation_tracking_enable(); + closure.execute(); - }; -} +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endParallelReduce(kpID); + } +#endif + } +}; +} // namespace Impl //---------------------------------------------------------------------------- /*! \fn void parallel_reduce(label,policy,functor,return_argument) \brief Perform a parallel reduction. - \param label An optional Label giving the call name. Must be able to construct a std::string from the argument. - \param policy A Kokkos Execution Policy, such as an integer, a RangePolicy or a TeamPolicy. - \param functor A functor with a reduction operator, and optional init, join and final functions. - \param return_argument A return argument which can be a scalar, a View, or a ReducerStruct. This argument can be left out if the functor has a final function. + \param label An optional Label giving the call name. Must be able to + construct a std::string from the argument. \param policy A Kokkos Execution + Policy, such as an integer, a RangePolicy or a TeamPolicy. \param functor A + functor with a reduction operator, and optional init, join and final + functions. \param return_argument A return argument which can be a scalar, a + View, or a ReducerStruct. This argument can be left out if the functor has a + final function. */ // Parallel Reduce Blocking behavior namespace Impl { template - struct ReducerHasTestReferenceFunction - { - template static std::true_type test_func( decltype(&E::references_scalar) ) ; - template static std::false_type test_func(...); - - enum { value = std::is_same(0))>::value }; +struct ReducerHasTestReferenceFunction { + template + static std::true_type test_func(decltype(&E::references_scalar)); + template + static std::false_type test_func(...); + + enum { + value = std::is_same(0))>::value }; +}; - template::value> - struct ParallelReduceFence { - static void fence(const T&) { - Kokkos::fence(); - } - }; - template - struct ParallelReduceFence, false> { - static void fence(const View) {}; - }; - template - struct ParallelReduceFence { - static void fence(const T& reducer) { - if(reducer.references_scalar()) - Kokkos::fence(); - } - }; -} +template ::value> +struct ParallelReduceFence { + static void fence(const T&) { Kokkos::fence(); } +}; +template +struct ParallelReduceFence, false> { + static void fence(const View){}; +}; +template +struct ParallelReduceFence { + static void fence(const T& reducer) { + if (reducer.references_scalar()) Kokkos::fence(); + } +}; +} // namespace Impl /** \brief Parallel reduction * @@ -1033,16 +957,12 @@ template * }; * \endcode * - * Example of a parallel_reduce functor for an array of POD (plain old data) values: - * \code - * class FunctorType { // For array of POD value - * public: - * typedef ... execution_space ; - * typedef value_type[] ; - * void operator()( , update[] ) const ; - * void init( update[] ) const ; - * void join( volatile update[] , - * volatile const input[] ) const ; + * Example of a parallel_reduce functor for an array of POD (plain old data) + * values: \code class FunctorType { // For array of POD value public: typedef + * ... execution_space ; typedef value_type[] ; void operator()( + * , update[] ) const ; void init( update[] ) + * const ; void join( volatile update[] , volatile const + * input[] ) const ; * * typedef true_type has_final ; * void final( update[] ) const ; @@ -1052,226 +972,223 @@ template // ReturnValue is scalar or array: take by reference -template< class PolicyType, class FunctorType, class ReturnType > -inline -void parallel_reduce(const std::string& label, - const PolicyType& policy, - const FunctorType& functor, - ReturnType& return_value, - typename Impl::enable_if< - Kokkos::Impl::is_execution_policy::value - >::type * = 0) { - Impl::ParallelReduceAdaptor::execute(label,policy,functor,return_value); +template +inline void parallel_reduce( + const std::string& label, const PolicyType& policy, + const FunctorType& functor, ReturnType& return_value, + typename Impl::enable_if< + Kokkos::Impl::is_execution_policy::value>::type* = 0) { + Impl::ParallelReduceAdaptor::execute( + label, policy, functor, return_value); Impl::ParallelReduceFence::fence(return_value); } -template< class PolicyType, class FunctorType, class ReturnType > -inline -void parallel_reduce(const PolicyType& policy, - const FunctorType& functor, - ReturnType& return_value, - typename Impl::enable_if< - Kokkos::Impl::is_execution_policy::value - >::type * = 0) { - Impl::ParallelReduceAdaptor::execute("",policy,functor,return_value); +template +inline void parallel_reduce( + const PolicyType& policy, const FunctorType& functor, + ReturnType& return_value, + typename Impl::enable_if< + Kokkos::Impl::is_execution_policy::value>::type* = 0) { + Impl::ParallelReduceAdaptor::execute( + "", policy, functor, return_value); Impl::ParallelReduceFence::fence(return_value); } -template< class FunctorType, class ReturnType > -inline -void parallel_reduce(const size_t& policy, - const FunctorType& functor, - ReturnType& return_value) { - typedef typename Impl::ParallelReducePolicyType::policy_type policy_type; - Impl::ParallelReduceAdaptor::execute("",policy_type(0,policy),functor,return_value); +template +inline void parallel_reduce(const size_t& policy, const FunctorType& functor, + ReturnType& return_value) { + typedef typename Impl::ParallelReducePolicyType< + void, size_t, FunctorType>::policy_type policy_type; + Impl::ParallelReduceAdaptor::execute( + "", policy_type(0, policy), functor, return_value); Impl::ParallelReduceFence::fence(return_value); } -template< class FunctorType, class ReturnType > -inline -void parallel_reduce(const std::string& label, - const size_t& policy, - const FunctorType& functor, - ReturnType& return_value) { - typedef typename Impl::ParallelReducePolicyType::policy_type policy_type; - Impl::ParallelReduceAdaptor::execute(label,policy_type(0,policy),functor,return_value); +template +inline void parallel_reduce(const std::string& label, const size_t& policy, + const FunctorType& functor, + ReturnType& return_value) { + typedef typename Impl::ParallelReducePolicyType< + void, size_t, FunctorType>::policy_type policy_type; + Impl::ParallelReduceAdaptor::execute( + label, policy_type(0, policy), functor, return_value); Impl::ParallelReduceFence::fence(return_value); } // ReturnValue as View or Reducer: take by copy to allow for inline construction -template< class PolicyType, class FunctorType, class ReturnType > -inline -void parallel_reduce(const std::string& label, - const PolicyType& policy, - const FunctorType& functor, - const ReturnType& return_value, - typename Impl::enable_if< - Kokkos::Impl::is_execution_policy::value - >::type * = 0) { +template +inline void parallel_reduce( + const std::string& label, const PolicyType& policy, + const FunctorType& functor, const ReturnType& return_value, + typename Impl::enable_if< + Kokkos::Impl::is_execution_policy::value>::type* = 0) { ReturnType return_value_impl = return_value; - Impl::ParallelReduceAdaptor::execute(label,policy,functor,return_value_impl); + Impl::ParallelReduceAdaptor::execute( + label, policy, functor, return_value_impl); Impl::ParallelReduceFence::fence(return_value); } -template< class PolicyType, class FunctorType, class ReturnType > -inline -void parallel_reduce(const PolicyType& policy, - const FunctorType& functor, - const ReturnType& return_value, - typename Impl::enable_if< - Kokkos::Impl::is_execution_policy::value - >::type * = 0) { +template +inline void parallel_reduce( + const PolicyType& policy, const FunctorType& functor, + const ReturnType& return_value, + typename Impl::enable_if< + Kokkos::Impl::is_execution_policy::value>::type* = 0) { ReturnType return_value_impl = return_value; - Impl::ParallelReduceAdaptor::execute("",policy,functor,return_value_impl); + Impl::ParallelReduceAdaptor::execute( + "", policy, functor, return_value_impl); Impl::ParallelReduceFence::fence(return_value); } -template< class FunctorType, class ReturnType > -inline -void parallel_reduce(const size_t& policy, - const FunctorType& functor, - const ReturnType& return_value) { - typedef typename Impl::ParallelReducePolicyType::policy_type policy_type; +template +inline void parallel_reduce(const size_t& policy, const FunctorType& functor, + const ReturnType& return_value) { + typedef typename Impl::ParallelReducePolicyType< + void, size_t, FunctorType>::policy_type policy_type; ReturnType return_value_impl = return_value; - Impl::ParallelReduceAdaptor::execute("",policy_type(0,policy),functor,return_value_impl); + Impl::ParallelReduceAdaptor::execute( + "", policy_type(0, policy), functor, return_value_impl); Impl::ParallelReduceFence::fence(return_value); } -template< class FunctorType, class ReturnType > -inline -void parallel_reduce(const std::string& label, - const size_t& policy, - const FunctorType& functor, - const ReturnType& return_value) { - typedef typename Impl::ParallelReducePolicyType::policy_type policy_type; +template +inline void parallel_reduce(const std::string& label, const size_t& policy, + const FunctorType& functor, + const ReturnType& return_value) { + typedef typename Impl::ParallelReducePolicyType< + void, size_t, FunctorType>::policy_type policy_type; ReturnType return_value_impl = return_value; - Impl::ParallelReduceAdaptor::execute(label,policy_type(0,policy),functor,return_value_impl); + Impl::ParallelReduceAdaptor::execute( + label, policy_type(0, policy), functor, return_value_impl); Impl::ParallelReduceFence::fence(return_value); } // No Return Argument -template< class PolicyType, class FunctorType> -inline -void parallel_reduce(const std::string& label, - const PolicyType& policy, - const FunctorType& functor, - typename Impl::enable_if< - Kokkos::Impl::is_execution_policy::value - >::type * = 0) { - typedef Kokkos::Impl::FunctorValueTraits< FunctorType , void > ValueTraits ; - typedef typename Kokkos::Impl::if_c< (ValueTraits::StaticValueSize != 0) - , typename ValueTraits::value_type - , typename ValueTraits::pointer_type - >::type value_type ; - - static_assert(Impl::FunctorAnalysis:: - has_final_member_function,"Calling parallel_reduce without either return value or final function."); - - typedef Kokkos::View< value_type - , Kokkos::HostSpace - , Kokkos::MemoryUnmanaged - > result_view_type; - result_view_type result_view ; - - Impl::ParallelReduceAdaptor::execute(label,policy,functor,result_view); +template +inline void parallel_reduce( + const std::string& label, const PolicyType& policy, + const FunctorType& functor, + typename Impl::enable_if< + Kokkos::Impl::is_execution_policy::value>::type* = 0) { + typedef Kokkos::Impl::FunctorValueTraits ValueTraits; + typedef typename Kokkos::Impl::if_c< + (ValueTraits::StaticValueSize != 0), typename ValueTraits::value_type, + typename ValueTraits::pointer_type>::type value_type; + + static_assert( + Impl::FunctorAnalysis::has_final_member_function, + "Calling parallel_reduce without either return value or final function."); + + typedef Kokkos::View + result_view_type; + result_view_type result_view; + + Impl::ParallelReduceAdaptor::execute(label, policy, functor, + result_view); } -template< class PolicyType, class FunctorType > -inline -void parallel_reduce(const PolicyType& policy, - const FunctorType& functor, - typename Impl::enable_if< - Kokkos::Impl::is_execution_policy::value - >::type * = 0) { - typedef Kokkos::Impl::FunctorValueTraits< FunctorType , void > ValueTraits ; - typedef typename Kokkos::Impl::if_c< (ValueTraits::StaticValueSize != 0) - , typename ValueTraits::value_type - , typename ValueTraits::pointer_type - >::type value_type ; - - static_assert(Impl::FunctorAnalysis:: - has_final_member_function,"Calling parallel_reduce without either return value or final function."); - - typedef Kokkos::View< value_type - , Kokkos::HostSpace - , Kokkos::MemoryUnmanaged - > result_view_type; - result_view_type result_view ; - - Impl::ParallelReduceAdaptor::execute("",policy,functor,result_view); +template +inline void parallel_reduce( + const PolicyType& policy, const FunctorType& functor, + typename Impl::enable_if< + Kokkos::Impl::is_execution_policy::value>::type* = 0) { + typedef Kokkos::Impl::FunctorValueTraits ValueTraits; + typedef typename Kokkos::Impl::if_c< + (ValueTraits::StaticValueSize != 0), typename ValueTraits::value_type, + typename ValueTraits::pointer_type>::type value_type; + + static_assert( + Impl::FunctorAnalysis::has_final_member_function, + "Calling parallel_reduce without either return value or final function."); + + typedef Kokkos::View + result_view_type; + result_view_type result_view; + + Impl::ParallelReduceAdaptor::execute("", policy, functor, + result_view); } -template< class FunctorType > -inline -void parallel_reduce(const size_t& policy, - const FunctorType& functor) { - typedef typename Impl::ParallelReducePolicyType::policy_type policy_type; - typedef Kokkos::Impl::FunctorValueTraits< FunctorType , void > ValueTraits ; - typedef typename Kokkos::Impl::if_c< (ValueTraits::StaticValueSize != 0) - , typename ValueTraits::value_type - , typename ValueTraits::pointer_type - >::type value_type ; - - static_assert(Impl::FunctorAnalysis,FunctorType>:: - has_final_member_function,"Calling parallel_reduce without either return value or final function."); - - typedef Kokkos::View< value_type - , Kokkos::HostSpace - , Kokkos::MemoryUnmanaged - > result_view_type; - result_view_type result_view ; - - Impl::ParallelReduceAdaptor::execute("",policy_type(0,policy),functor,result_view); +template +inline void parallel_reduce(const size_t& policy, const FunctorType& functor) { + typedef typename Impl::ParallelReducePolicyType< + void, size_t, FunctorType>::policy_type policy_type; + typedef Kokkos::Impl::FunctorValueTraits ValueTraits; + typedef typename Kokkos::Impl::if_c< + (ValueTraits::StaticValueSize != 0), typename ValueTraits::value_type, + typename ValueTraits::pointer_type>::type value_type; + + static_assert( + Impl::FunctorAnalysis, + FunctorType>::has_final_member_function, + "Calling parallel_reduce without either return value or final function."); + + typedef Kokkos::View + result_view_type; + result_view_type result_view; + + Impl::ParallelReduceAdaptor::execute("", + policy_type(0, policy), + functor, result_view); } -template< class FunctorType> -inline -void parallel_reduce(const std::string& label, - const size_t& policy, - const FunctorType& functor) { - typedef typename Impl::ParallelReducePolicyType::policy_type policy_type; - typedef Kokkos::Impl::FunctorValueTraits< FunctorType , void > ValueTraits ; - typedef typename Kokkos::Impl::if_c< (ValueTraits::StaticValueSize != 0) - , typename ValueTraits::value_type - , typename ValueTraits::pointer_type - >::type value_type ; - - static_assert(Impl::FunctorAnalysis,FunctorType>:: - has_final_member_function,"Calling parallel_reduce without either return value or final function."); - - typedef Kokkos::View< value_type - , Kokkos::HostSpace - , Kokkos::MemoryUnmanaged - > result_view_type; - result_view_type result_view ; - - Impl::ParallelReduceAdaptor::execute(label,policy_type(0,policy),functor,result_view); +template +inline void parallel_reduce(const std::string& label, const size_t& policy, + const FunctorType& functor) { + typedef typename Impl::ParallelReducePolicyType< + void, size_t, FunctorType>::policy_type policy_type; + typedef Kokkos::Impl::FunctorValueTraits ValueTraits; + typedef typename Kokkos::Impl::if_c< + (ValueTraits::StaticValueSize != 0), typename ValueTraits::value_type, + typename ValueTraits::pointer_type>::type value_type; + + static_assert( + Impl::FunctorAnalysis, + FunctorType>::has_final_member_function, + "Calling parallel_reduce without either return value or final function."); + + typedef Kokkos::View + result_view_type; + result_view_type result_view; + + Impl::ParallelReduceAdaptor::execute(label, + policy_type(0, policy), + functor, result_view); } -} //namespace Kokkos +} // namespace Kokkos #ifdef KOKKOS_ENABLE_DEPRECATED_CODE -//backwards compatibility for Kokkos::Experimental reducers -namespace Kokkos { namespace Experimental { -using Kokkos::Sum; -using Kokkos::Prod; -using Kokkos::Min; -using Kokkos::Max; -using Kokkos::LAnd; -using Kokkos::LOr; +// backwards compatiblity for Kokkos::Experimental reducers +namespace Kokkos { +namespace Experimental { using Kokkos::BAnd; using Kokkos::BOr; -using Kokkos::ValLocScalar; -using Kokkos::MinLoc; +using Kokkos::LAnd; +using Kokkos::LOr; +using Kokkos::Max; using Kokkos::MaxLoc; -using Kokkos::MinMaxScalar; +using Kokkos::Min; +using Kokkos::MinLoc; using Kokkos::MinMax; -using Kokkos::MinMaxLocScalar; using Kokkos::MinMaxLoc; -}} //namespace Kokkos::Experimental +using Kokkos::MinMaxLocScalar; +using Kokkos::MinMaxScalar; +using Kokkos::Prod; +using Kokkos::Sum; +using Kokkos::ValLocScalar; +} // namespace Experimental +} // namespace Kokkos #endif -#endif // KOKKOS_PARALLEL_REDUCE_HPP - +#endif // KOKKOS_PARALLEL_REDUCE_HPP diff --git a/lib/kokkos/core/src/Kokkos_PointerOwnership.hpp b/lib/kokkos/core/src/Kokkos_PointerOwnership.hpp index be76ec3def..f1f168c38f 100644 --- a/lib/kokkos/core/src/Kokkos_PointerOwnership.hpp +++ b/lib/kokkos/core/src/Kokkos_PointerOwnership.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -63,12 +64,9 @@ using OwningRawPtr = T*; template using ObservingRawPtr = T*; -} // end namespace Kokkos +} // end namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- - - #endif /* #ifndef KOKKOS_IMPL_POINTEROWNERSHIP_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_Profiling_ProfileSection.hpp b/lib/kokkos/core/src/Kokkos_Profiling_ProfileSection.hpp index b3fd3af70b..3c667f4432 100644 --- a/lib/kokkos/core/src/Kokkos_Profiling_ProfileSection.hpp +++ b/lib/kokkos/core/src/Kokkos_Profiling_ProfileSection.hpp @@ -1,45 +1,46 @@ /* - //@HEADER - // ************************************************************************ - // - // Kokkos v. 2.0 - // Copyright (2014) Sandia Corporation - // - // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, - // the U.S. Government retains certain rights in this software. - // - // Redistribution and use in source and binary forms, with or without - // modification, are permitted provided that the following conditions are - // met: - // - // 1. Redistributions of source code must retain the above copyright - // notice, this list of conditions and the following disclaimer. - // - // 2. Redistributions in binary form must reproduce the above copyright - // notice, this list of conditions and the following disclaimer in the - // documentation and/or other materials provided with the distribution. - // - // 3. Neither the name of the Corporation nor the names of the - // contributors may be used to endorse or promote products derived from - // this software without specific prior written permission. - // - // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY - // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE - // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // - // Questions? Contact Christian R. Trott (crtrott@sandia.gov) - // - // ************************************************************************ - //@HEADER - */ +//@HEADER +// ************************************************************************ +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the Corporation nor the names of the +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact Christian R. Trott (crtrott@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ #ifndef KOKKOSP_PROFILE_SECTION_HPP #define KOKKOSP_PROFILE_SECTION_HPP @@ -53,59 +54,51 @@ namespace Kokkos { namespace Profiling { class ProfilingSection { + public: + ProfilingSection(const std::string& sectionName) : secName(sectionName) { +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::createProfileSection(secName, &secID); + } +#else + secID = 0; +#endif + } -public: - ProfilingSection(const std::string& sectionName) : - secName(sectionName) { + void start() { +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::startSection(secID); + } +#endif + } - #if defined( KOKKOS_ENABLE_PROFILING ) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::createProfileSection(secName, &secID); - } - #else - secID = 0; - #endif - } - - void start() { - #if defined( KOKKOS_ENABLE_PROFILING ) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::startSection(secID); - } - #endif - } - - void stop() { - #if defined( KOKKOS_ENABLE_PROFILING ) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::stopSection(secID); - } - #endif - } - - ~ProfilingSection() { - #if defined( KOKKOS_ENABLE_PROFILING ) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::destroyProfileSection(secID); - } - #endif - } - - std::string getName() { - return secName; - } - - uint32_t getSectionID() { - return secID; - } - -protected: - const std::string secName; - uint32_t secID; + void stop() { +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::stopSection(secID); + } +#endif + } + ~ProfilingSection() { +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::destroyProfileSection(secID); + } +#endif + } + + std::string getName() { return secName; } + + uint32_t getSectionID() { return secID; } + + protected: + const std::string secName; + uint32_t secID; }; -} -} +} // namespace Profiling +} // namespace Kokkos -#endif \ No newline at end of file +#endif diff --git a/lib/kokkos/core/src/Kokkos_Qthreads.hpp b/lib/kokkos/core/src/Kokkos_Qthreads.hpp index 16702f8647..e10bd48593 100644 --- a/lib/kokkos/core/src/Kokkos_Qthreads.hpp +++ b/lib/kokkos/core/src/Kokkos_Qthreads.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,7 +46,7 @@ #define KOKKOS_QTHREADS_HPP #include -#if defined( KOKKOS_ENABLE_QTHREADS ) +#if defined(KOKKOS_ENABLE_QTHREADS) #include @@ -76,9 +77,9 @@ namespace Impl { class QthreadsExec; -} // namespace Impl +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos /*--------------------------------------------------------------------------*/ @@ -86,26 +87,26 @@ namespace Kokkos { /** \brief Execution space supported by Qthreads */ class Qthreads { -public: + public: //! \name Type declarations that all Kokkos devices must provide. //@{ //! Tag this class as an execution space - typedef Qthreads execution_space; - typedef Kokkos::HostSpace memory_space; + typedef Qthreads execution_space; + typedef Kokkos::HostSpace memory_space; //! This execution space preferred device_type - typedef Kokkos::Device< execution_space, memory_space > device_type; + typedef Kokkos::Device device_type; - typedef Kokkos::LayoutRight array_layout; - typedef memory_space::size_type size_type; + typedef Kokkos::LayoutRight array_layout; + typedef memory_space::size_type size_type; - typedef ScratchMemorySpace< Qthreads > scratch_memory_space; + typedef ScratchMemorySpace scratch_memory_space; //@} /*------------------------------------------------------------------------*/ /** \brief Initialization will construct one or more instances */ - static Qthreads & instance( int = 0 ); + static Qthreads& instance(int = 0); /** \brief Set the execution space to a "sleep" state. * @@ -143,11 +144,11 @@ public: /** \brief Return maximum amount of concurrency */ static int concurrency(); - static void initialize( int thread_count ); + static void initialize(int thread_count); static void finalize(); /** \brief Print configuration information to the given output stream. */ - static void print_configuration( std::ostream &, const bool detail = false ); + static void print_configuration(std::ostream&, const bool detail = false); int shepherd_size() const; int shepherd_worker_size() const; @@ -155,7 +156,7 @@ public: static const char* name(); }; -} // namespace Kokkos +} // namespace Kokkos /*--------------------------------------------------------------------------*/ @@ -163,39 +164,33 @@ namespace Kokkos { namespace Impl { -template<> -struct MemorySpaceAccess - < Kokkos::Qthreads::memory_space - , Kokkos::Qthreads::scratch_memory_space - > -{ +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = true }; - enum { deepcopy = false }; + enum { deepcopy = false }; }; -template<> -struct VerifyExecutionCanAccessMemorySpace - < Kokkos::Qthreads::memory_space - , Kokkos::Qthreads::scratch_memory_space - > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace< + Kokkos::Qthreads::memory_space, Kokkos::Qthreads::scratch_memory_space> { enum { value = true }; - inline static void verify( void ) {} - inline static void verify( const void * ) {} + inline static void verify(void) {} + inline static void verify(const void*) {} }; -} // namespace Impl +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos /*--------------------------------------------------------------------------*/ #include #include -//#include // Uncomment when Tasking working. -//#include // Uncomment when Tasking working. - -#endif // #define KOKKOS_ENABLE_QTHREADS -#endif // #define KOKKOS_QTHREADS_HPP +//#include // Uncomment when Tasking +// working. #include // Uncomment when +// Tasking working. +#endif // #define KOKKOS_ENABLE_QTHREADS +#endif // #define KOKKOS_QTHREADS_HPP diff --git a/lib/kokkos/core/src/Kokkos_ROCm.hpp b/lib/kokkos/core/src/Kokkos_ROCm.hpp index 96207e73c6..57113452b8 100644 --- a/lib/kokkos/core/src/Kokkos_ROCm.hpp +++ b/lib/kokkos/core/src/Kokkos_ROCm.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -46,12 +47,12 @@ #include -#if defined( KOKKOS_ENABLE_ROCM ) +#if defined(KOKKOS_ENABLE_ROCM) class dim3 { -public: -int x,y,z; -dim3(int _x, int _y, int _z):x(_x),y(_y),z(_z) {}; + public: + int x, y, z; + dim3(int _x, int _y, int _z) : x(_x), y(_y), z(_z){}; }; #include @@ -74,9 +75,9 @@ dim3(int _x, int _y, int _z):x(_x),y(_y),z(_z) {}; #include #include -#if defined( __HCC_ACCELERATOR__ ) +#if defined(__HCC_ACCELERATOR__) -using namespace ::Concurrency::precise_math ; +using namespace ::Concurrency::precise_math; #endif @@ -84,9 +85,9 @@ using namespace ::Concurrency::precise_math ; namespace Kokkos { namespace Impl { -class ROCmExec ; -} // namespace Impl -} // namespace Kokkos +class ROCmExec; +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ @@ -95,30 +96,29 @@ namespace Experimental { /// \class ROCm /// \brief Kokkos device for multicore processors in the host memory space. class ROCm { -public: + public: //------------------------------------ //! \name Type declarations that all Kokkos devices must provide. //@{ //! Tag this class as a kokkos execution space - typedef ROCm execution_space ; - typedef ROCmSpace memory_space ; - typedef Kokkos::Device device_type; + typedef ROCm execution_space; + typedef ROCmSpace memory_space; + typedef Kokkos::Device device_type; - typedef LayoutLeft array_layout ; - typedef HostSpace::size_type size_type ; + typedef LayoutLeft array_layout; + typedef HostSpace::size_type size_type; - typedef ScratchMemorySpace< ROCm > scratch_memory_space ; + typedef ScratchMemorySpace scratch_memory_space; ~ROCm() {} ROCm(); -// explicit ROCm( const int instance_id ); - - ROCm( ROCm && ) = default ; - ROCm( const ROCm & ) = default ; - ROCm & operator = ( ROCm && ) = default ; - ROCm & operator = ( const ROCm & ) = default ; + // explicit ROCm( const int instance_id ); + ROCm(ROCm&&) = default; + ROCm(const ROCm&) = default; + ROCm& operator=(ROCm&&) = default; + ROCm& operator=(const ROCm&) = default; //@} //------------------------------------ @@ -126,7 +126,7 @@ public: //@{ KOKKOS_INLINE_FUNCTION static int in_parallel() { -#if defined( __HCC_ACCELERATOR__ ) +#if defined(__HCC_ACCELERATOR__) return true; #else return false; @@ -134,122 +134,109 @@ public: } /** \brief Set the device in a "sleep" state. */ - static bool sleep() ; + static bool sleep(); /** \brief Wake the device from the 'sleep' state. A noop for OpenMP. */ - static bool wake() ; + static bool wake(); /** \brief Wait until all dispatched functors complete. A noop for OpenMP. */ static void impl_static_fence(); - #ifdef KOKKOS_ENABLE_DEPRECATED_CODE +#ifdef KOKKOS_ENABLE_DEPRECATED_CODE static void fence(); - #else +#else void fence() const; - #endif - +#endif /// \brief Print configuration information to the given output stream. - static void print_configuration( std::ostream & , const bool detail = false ); + static void print_configuration(std::ostream&, const bool detail = false); /// \brief Free any resources being consumed by the device. - static void finalize() ; + static void finalize(); /** \brief Initialize the device. * */ struct SelectDevice { - int rocm_device_id ; + int rocm_device_id; SelectDevice() : rocm_device_id(1) {} - explicit SelectDevice( int id ) : rocm_device_id( id+1 ) {} + explicit SelectDevice(int id) : rocm_device_id(id + 1) {} }; - int rocm_device() const { return m_device ; } - bool isAPU(); - bool isAPU(int device); + int rocm_device() const { return m_device; } + bool isAPU(); + bool isAPU(int device); - static void initialize( const SelectDevice = SelectDevice()); + static void initialize(const SelectDevice = SelectDevice()); static int is_initialized(); -// static size_type device_arch(); + // static size_type device_arch(); -// static size_type detect_device_count(); + // static size_type detect_device_count(); - - static int concurrency() ; + static int concurrency(); static const char* name(); -private: - int m_device ; + private: + int m_device; }; -} -} // namespace Kokkos +} // namespace Experimental +} // namespace Kokkos namespace Kokkos { namespace Impl { -template<> -struct MemorySpaceAccess - < Kokkos::Experimental::ROCmSpace - , Kokkos::Experimental::ROCm::scratch_memory_space - > -{ +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = true }; - enum { deepcopy = false }; + enum { deepcopy = false }; }; -template<> -struct VerifyExecutionCanAccessMemorySpace - < Kokkos::Experimental::ROCm::memory_space - , Kokkos::Experimental::ROCm::scratch_memory_space - > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace< + Kokkos::Experimental::ROCm::memory_space, + Kokkos::Experimental::ROCm::scratch_memory_space> { enum { value = true }; - KOKKOS_INLINE_FUNCTION static void verify( void ) { } - KOKKOS_INLINE_FUNCTION static void verify( const void * ) { } + KOKKOS_INLINE_FUNCTION static void verify(void) {} + KOKKOS_INLINE_FUNCTION static void verify(const void*) {} }; -template<> -struct VerifyExecutionCanAccessMemorySpace - < Kokkos::HostSpace - , Kokkos::Experimental::ROCm::scratch_memory_space - > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace< + Kokkos::HostSpace, Kokkos::Experimental::ROCm::scratch_memory_space> { enum { value = false }; - inline static void verify( void ) { Kokkos::Experimental::ROCmSpace::access_error(); } - inline static void verify( const void * p ) { Kokkos::Experimental::ROCmSpace::access_error(p); } + inline static void verify(void) { + Kokkos::Experimental::ROCmSpace::access_error(); + } + inline static void verify(const void* p) { + Kokkos::Experimental::ROCmSpace::access_error(p); + } }; -} // namespace Experimental -} // namespace Kokkos - - - - +} // namespace Impl +} // namespace Kokkos #define threadIdx_x (hc_get_workitem_id(0)) #define threadIdx_y (hc_get_workitem_id(1)) #define threadIdx_z (hc_get_workitem_id(2)) -#define blockIdx_x (hc_get_group_id(0)) -#define blockIdx_y (hc_get_group_id(1)) -#define blockIdx_z (hc_get_group_id(2)) +#define blockIdx_x (hc_get_group_id(0)) +#define blockIdx_y (hc_get_group_id(1)) +#define blockIdx_z (hc_get_group_id(2)) -#define blockDim_x (hc_get_group_size(0)) -#define blockDim_y (hc_get_group_size(1)) -#define blockDim_z (hc_get_group_size(2)) - -#define gridDim_x (hc_get_num_groups(0)) -#define gridDim_y (hc_get_num_groups(1)) -#define gridDim_z (hc_get_num_groups(2)) +#define blockDim_x (hc_get_group_size(0)) +#define blockDim_y (hc_get_group_size(1)) +#define blockDim_z (hc_get_group_size(2)) +#define gridDim_x (hc_get_num_groups(0)) +#define gridDim_y (hc_get_num_groups(1)) +#define gridDim_z (hc_get_num_groups(2)) #include #include #endif #endif - - diff --git a/lib/kokkos/core/src/Kokkos_ROCmSpace.hpp b/lib/kokkos/core/src/Kokkos_ROCmSpace.hpp index c0b7158fde..36017cd40f 100644 --- a/lib/kokkos/core/src/Kokkos_ROCmSpace.hpp +++ b/lib/kokkos/core/src/Kokkos_ROCmSpace.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -46,7 +47,7 @@ #include -#if defined( KOKKOS_ENABLE_ROCM ) +#if defined(KOKKOS_ENABLE_ROCM) #include #include @@ -54,7 +55,6 @@ #include - /*--------------------------------------------------------------------------*/ namespace Kokkos { @@ -62,30 +62,28 @@ namespace Experimental { /** \brief ROCm on-device memory management */ class ROCmSpace { -public: - + public: //! Tag this class as a kokkos memory space - typedef ROCmSpace memory_space ; - typedef Kokkos::Experimental::ROCm execution_space ; - typedef Kokkos::Device device_type; + typedef ROCmSpace memory_space; + typedef Kokkos::Experimental::ROCm execution_space; + typedef Kokkos::Device device_type; - typedef unsigned int size_type ; + typedef unsigned int size_type; /*--------------------------------*/ ROCmSpace(); - ROCmSpace( ROCmSpace && rhs ) = default ; - ROCmSpace( const ROCmSpace & rhs ) = default ; - ROCmSpace & operator = ( ROCmSpace && rhs ) = default ; - ROCmSpace & operator = ( const ROCmSpace & rhs ) = default ; - ~ROCmSpace() = default ; + ROCmSpace(ROCmSpace&& rhs) = default; + ROCmSpace(const ROCmSpace& rhs) = default; + ROCmSpace& operator=(ROCmSpace&& rhs) = default; + ROCmSpace& operator=(const ROCmSpace& rhs) = default; + ~ROCmSpace() = default; /**\brief Allocate untracked memory in the rocm space */ - void * allocate( const size_t arg_alloc_size ) const ; + void* allocate(const size_t arg_alloc_size) const; /**\brief Deallocate untracked memory in the rocm space */ - void deallocate( void * const arg_alloc_ptr - , const size_t arg_alloc_size ) const ; + void deallocate(void* const arg_alloc_ptr, const size_t arg_alloc_size) const; /**\brief Return Name of the MemorySpace */ static constexpr const char* name() { return m_name; }; @@ -93,23 +91,23 @@ public: /*--------------------------------*/ /** \brief Error reporting for HostSpace attempt to access ROCmSpace */ static void access_error(); - static void access_error( const void * const ); - -private: + static void access_error(const void* const); - int m_device ; ///< Which ROCm device + private: + int m_device; ///< Which ROCm device static constexpr const char* m_name = "ROCm"; - friend class Kokkos::Impl::SharedAllocationRecord< Kokkos::Experimental::ROCmSpace , void > ; + friend class Kokkos::Impl::SharedAllocationRecord< + Kokkos::Experimental::ROCmSpace, void>; }; -} // namespace Experimental +} // namespace Experimental namespace Impl { -void * rocm_device_allocate(int); -void * rocm_hostpinned_allocate(int); -void rocm_device_free(void * ); +void* rocm_device_allocate(int); +void* rocm_hostpinned_allocate(int); +void rocm_device_free(void*); /// \brief Initialize lock array for arbitrary size atomics. /// @@ -128,10 +126,11 @@ void init_lock_arrays_rocm_space(); /// If the array is not yet allocated it will do so. int* atomic_lock_array_rocm_space_ptr(bool deallocate = false); -/// \brief Retrieve the pointer to the scratch array for team and thread private global memory. +/// \brief Retrieve the pointer to the scratch array for team and thread private +/// global memory. /// /// Team and Thread private scratch allocations in -/// global memory are acquired via locks. +/// global memory are aquired via locks. /// This function retrieves the lock array pointer. /// If the array is not yet allocated it will do so. int* scratch_lock_array_rocm_space_ptr(bool deallocate = false); @@ -143,55 +142,51 @@ int* scratch_lock_array_rocm_space_ptr(bool deallocate = false); /// This function retrieves the lock array pointer. /// If the array is not yet allocated it will do so. int* threadid_lock_array_rocm_space_ptr(bool deallocate = false); -} -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ - namespace Kokkos { namespace Experimental { /** \brief Host memory that is accessible to ROCm execution space * through ROCm's host-pinned memory allocation. */ class ROCmHostPinnedSpace { -public: - + public: //! Tag this class as a kokkos memory space /** \brief Memory is in HostSpace so use the HostSpace::execution_space */ - typedef HostSpace::execution_space execution_space ; - typedef ROCmHostPinnedSpace memory_space ; - typedef Kokkos::Device device_type; - typedef unsigned int size_type ; + typedef HostSpace::execution_space execution_space; + typedef ROCmHostPinnedSpace memory_space; + typedef Kokkos::Device device_type; + typedef unsigned int size_type; /*--------------------------------*/ ROCmHostPinnedSpace(); - ROCmHostPinnedSpace( ROCmHostPinnedSpace && rhs ) = default ; - ROCmHostPinnedSpace( const ROCmHostPinnedSpace & rhs ) = default ; - ROCmHostPinnedSpace & operator = ( ROCmHostPinnedSpace && rhs ) = default ; - ROCmHostPinnedSpace & operator = ( const ROCmHostPinnedSpace & rhs ) = default ; - ~ROCmHostPinnedSpace() = default ; + ROCmHostPinnedSpace(ROCmHostPinnedSpace&& rhs) = default; + ROCmHostPinnedSpace(const ROCmHostPinnedSpace& rhs) = default; + ROCmHostPinnedSpace& operator=(ROCmHostPinnedSpace&& rhs) = default; + ROCmHostPinnedSpace& operator=(const ROCmHostPinnedSpace& rhs) = default; + ~ROCmHostPinnedSpace() = default; /**\brief Allocate untracked memory in the space */ - void * allocate( const size_t arg_alloc_size ) const ; + void* allocate(const size_t arg_alloc_size) const; /**\brief Deallocate untracked memory in the space */ - void deallocate( void * const arg_alloc_ptr - , const size_t arg_alloc_size ) const ; + void deallocate(void* const arg_alloc_ptr, const size_t arg_alloc_size) const; /**\brief Return Name of the MemorySpace */ static constexpr const char* name() { return m_name; }; -private: - + private: static constexpr const char* m_name = "ROCmHostPinned"; /*--------------------------------*/ }; -} // namespace Experimental -} // namespace Kokkos +} // namespace Experimental +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -199,65 +194,71 @@ private: namespace Kokkos { namespace Impl { -static_assert( Kokkos::Impl::MemorySpaceAccess< Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCmSpace >::assignable , "" ); +static_assert(Kokkos::Impl::MemorySpaceAccess< + Kokkos::Experimental::ROCmSpace, + Kokkos::Experimental::ROCmSpace>::assignable, + ""); //---------------------------------------- -template<> -struct MemorySpaceAccess< Kokkos::HostSpace , Kokkos::Experimental::ROCmSpace > { +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = false }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::HostSpace , Kokkos::Experimental::ROCmHostPinnedSpace > { +template <> +struct MemorySpaceAccess { // HostSpace::execution_space == ROCmHostPinnedSpace::execution_space enum { assignable = true }; enum { accessible = true }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; //---------------------------------------- -template<> -struct MemorySpaceAccess< Kokkos::Experimental::ROCmSpace , Kokkos::HostSpace > { +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = false }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCmHostPinnedSpace > { +template <> +struct MemorySpaceAccess { // ROCmSpace::execution_space != ROCmHostPinnedSpace::execution_space enum { assignable = false }; - enum { accessible = true }; // ROCmSpace::execution_space - enum { deepcopy = true }; + enum { accessible = true }; // ROCmSpace::execution_space + enum { deepcopy = true }; }; - //---------------------------------------- // ROCmHostPinnedSpace::execution_space == HostSpace::execution_space // ROCmHostPinnedSpace accessible to both ROCm and Host -template<> -struct MemorySpaceAccess< Kokkos::Experimental::ROCmHostPinnedSpace , Kokkos::HostSpace > { - enum { assignable = false }; // Cannot access from ROCm - enum { accessible = true }; // ROCmHostPinnedSpace::execution_space - enum { deepcopy = true }; +template <> +struct MemorySpaceAccess { + enum { assignable = false }; // Cannot access from ROCm + enum { accessible = true }; // ROCmHostPinnedSpace::execution_space + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::Experimental::ROCmHostPinnedSpace , Kokkos::Experimental::ROCmSpace > { - enum { assignable = false }; // Cannot access from Host +template <> +struct MemorySpaceAccess { + enum { assignable = false }; // Cannot access from Host enum { accessible = false }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -}; +}; // namespace Impl //---------------------------------------- -} // namespace Kokkos::Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -265,171 +266,187 @@ struct MemorySpaceAccess< Kokkos::Experimental::ROCmHostPinnedSpace , Kokkos::Ex namespace Kokkos { namespace Impl { -hc::completion_future DeepCopyAsyncROCm( void * dst , const void * src , size_t n); +hc::completion_future DeepCopyAsyncROCm(void* dst, const void* src, size_t n); -template<> struct DeepCopy< Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCm> -{ - DeepCopy( void * dst , const void * src , size_t ); - DeepCopy( const Kokkos::Experimental::ROCm & , void * dst , const void * src , size_t ); +template <> +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t); + DeepCopy(const Kokkos::Experimental::ROCm&, void* dst, const void* src, + size_t); }; -template<> struct DeepCopy< Kokkos::Experimental::ROCmSpace , HostSpace , Kokkos::Experimental::ROCm > -{ - DeepCopy( void * dst , const void * src , size_t ); - DeepCopy( const Kokkos::Experimental::ROCm & , void * dst , const void * src , size_t ); +template <> +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t); + DeepCopy(const Kokkos::Experimental::ROCm&, void* dst, const void* src, + size_t); }; -template<> struct DeepCopy< HostSpace , Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCm > -{ - DeepCopy( void * dst , const void * src , size_t ); - DeepCopy( const Kokkos::Experimental::ROCm & , void * dst , const void * src , size_t ); +template <> +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t); + DeepCopy(const Kokkos::Experimental::ROCm&, void* dst, const void* src, + size_t); }; -template struct DeepCopy< Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCmSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCm >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy( + dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - hc::completion_future fut = DeepCopyAsyncROCm (dst,src,n); + hc::completion_future fut = DeepCopyAsyncROCm(dst, src, n); fut.wait(); -// DeepCopy (dst,src,n); + // DeepCopy (dst,src,n); } }; -template struct DeepCopy< Kokkos::Experimental::ROCmSpace , HostSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< Kokkos::Experimental::ROCmSpace , HostSpace , Kokkos::Experimental::ROCm>( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopy (dst,src,n); + DeepCopy(dst, src, n); } }; -template -struct DeepCopy< HostSpace , Kokkos::Experimental::ROCmSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< HostSpace , Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCm >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopy (dst,src,n); + DeepCopy(dst, src, n); } }; -template<> struct DeepCopy< Kokkos::Experimental::ROCmHostPinnedSpace , Kokkos::Experimental::ROCmHostPinnedSpace , Kokkos::Experimental::ROCm> -{ - DeepCopy( void * dst , const void * src , size_t ); - DeepCopy( const Kokkos::Experimental::ROCm & , void * dst , const void * src , size_t ); +template <> +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t); + DeepCopy(const Kokkos::Experimental::ROCm&, void* dst, const void* src, + size_t); }; -template<> struct DeepCopy< Kokkos::Experimental::ROCmHostPinnedSpace , HostSpace , Kokkos::Experimental::ROCm > -{ - DeepCopy( void * dst , const void * src , size_t ); - DeepCopy( const Kokkos::Experimental::ROCm & , void * dst , const void * src , size_t ); +template <> +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t); + DeepCopy(const Kokkos::Experimental::ROCm&, void* dst, const void* src, + size_t); }; -template<> struct DeepCopy< HostSpace , Kokkos::Experimental::ROCmHostPinnedSpace , Kokkos::Experimental::ROCm > -{ - DeepCopy( void * dst , const void * src , size_t ); - DeepCopy( const Kokkos::Experimental::ROCm & , void * dst , const void * src , size_t ); +template <> +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t); + DeepCopy(const Kokkos::Experimental::ROCm&, void* dst, const void* src, + size_t); }; -template -struct DeepCopy< Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCmHostPinnedSpace , ExecutionSpace> -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< Kokkos::Experimental::ROCmSpace , HostSpace , Kokkos::Experimental::ROCm >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - hc::completion_future fut = DeepCopyAsyncROCm (dst,src,n); + hc::completion_future fut = DeepCopyAsyncROCm(dst, src, n); fut.wait(); -// DeepCopyROCm (dst,src,n); + // DeepCopyROCm (dst,src,n); } }; -template struct DeepCopy< Kokkos::Experimental::ROCmHostPinnedSpace , Kokkos::Experimental::ROCmSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< HostSpace , Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCm >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - hc::completion_future fut = DeepCopyAsyncROCm (dst,src,n); + hc::completion_future fut = DeepCopyAsyncROCm(dst, src, n); fut.wait(); -// DeepCopyROCm (dst,src,n); + // DeepCopyROCm (dst,src,n); } }; +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - -template struct DeepCopy< Kokkos::Experimental::ROCmHostPinnedSpace , Kokkos::Experimental::ROCmHostPinnedSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< Kokkos::Experimental::ROCmHostPinnedSpace , Kokkos::Experimental::ROCmHostPinnedSpace , Kokkos::Experimental::ROCm >( dst , src , n ); } - - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); -// hc::completion_future fut = DeepCopyAsyncROCm (dst,src,n); -// fut.wait(); -// DeepCopyAsyncROCm (dst,src,n); - DeepCopy (dst,src,n); + // hc::completion_future fut = DeepCopyAsyncROCm (dst,src,n); + // fut.wait(); + // DeepCopyAsyncROCm (dst,src,n); + DeepCopy(dst, src, n); } }; -template struct DeepCopy< Kokkos::Experimental::ROCmHostPinnedSpace , HostSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< Kokkos::Experimental::ROCmHostPinnedSpace , HostSpace , Kokkos::Experimental::ROCm>( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopy (dst,src,n); + DeepCopy(dst, src, n); } }; -template -struct DeepCopy< HostSpace , Kokkos::Experimental::ROCmHostPinnedSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< HostSpace , Kokkos::Experimental::ROCmHostPinnedSpace , Kokkos::Experimental::ROCm >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopy (dst,src,n); + DeepCopy(dst, src, n); } }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -438,60 +455,70 @@ namespace Kokkos { namespace Impl { /** Running in ROCmSpace attempting to access HostSpace: error */ -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::Experimental::ROCmSpace , Kokkos::HostSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = false }; - KOKKOS_INLINE_FUNCTION static void verify( void ) - { Kokkos::abort("ROCm code attempted to access HostSpace memory"); } + KOKKOS_INLINE_FUNCTION static void verify(void) { + Kokkos::abort("ROCm code attempted to access HostSpace memory"); + } - KOKKOS_INLINE_FUNCTION static void verify( const void * ) - { Kokkos::abort("ROCm code attempted to access HostSpace memory"); } + KOKKOS_INLINE_FUNCTION static void verify(const void*) { + Kokkos::abort("ROCm code attempted to access HostSpace memory"); + } }; /** Running in ROCmSpace accessing ROCmHostPinnedSpace: ok */ -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCmHostPinnedSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace< + Kokkos::Experimental::ROCmSpace, + Kokkos::Experimental::ROCmHostPinnedSpace> { enum { value = true }; - KOKKOS_INLINE_FUNCTION static void verify( void ) { } - KOKKOS_INLINE_FUNCTION static void verify( const void * ) { } + KOKKOS_INLINE_FUNCTION static void verify(void) {} + KOKKOS_INLINE_FUNCTION static void verify(const void*) {} }; /** Running in ROCmSpace attempting to access an unknown space: error */ -template< class OtherSpace > +template struct VerifyExecutionCanAccessMemorySpace< - typename enable_if< ! is_same::value , Kokkos::Experimental::ROCmSpace >::type , - OtherSpace > -{ + typename enable_if< + !is_same::value, + Kokkos::Experimental::ROCmSpace>::type, + OtherSpace> { enum { value = false }; - KOKKOS_INLINE_FUNCTION static void verify( void ) - { Kokkos::abort("ROCm code attempted to access unknown Space memory"); } + KOKKOS_INLINE_FUNCTION static void verify(void) { + Kokkos::abort("ROCm code attempted to access unknown Space memory"); + } - KOKKOS_INLINE_FUNCTION static void verify( const void * ) - { Kokkos::abort("ROCm code attempted to access unknown Space memory"); } + KOKKOS_INLINE_FUNCTION static void verify(const void*) { + Kokkos::abort("ROCm code attempted to access unknown Space memory"); + } }; //---------------------------------------------------------------------------- /** Running in HostSpace attempting to access ROCmSpace */ -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::HostSpace , Kokkos::Experimental::ROCmSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = false }; - inline static void verify( void ) { Kokkos::Experimental::ROCmSpace::access_error(); } - inline static void verify( const void * p ) { Kokkos::Experimental::ROCmSpace::access_error(p); } + inline static void verify(void) { + Kokkos::Experimental::ROCmSpace::access_error(); + } + inline static void verify(const void* p) { + Kokkos::Experimental::ROCmSpace::access_error(p); + } }; /** Running in HostSpace accessing ROCmHostPinnedSpace is OK */ -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::HostSpace , Kokkos::Experimental::ROCmHostPinnedSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace< + Kokkos::HostSpace, Kokkos::Experimental::ROCmHostPinnedSpace> { enum { value = true }; - KOKKOS_INLINE_FUNCTION static void verify( void ) {} - KOKKOS_INLINE_FUNCTION static void verify( const void * ) {} + KOKKOS_INLINE_FUNCTION static void verify(void) {} + KOKKOS_INLINE_FUNCTION static void verify(const void*) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -499,128 +526,112 @@ struct VerifyExecutionCanAccessMemorySpace< Kokkos::HostSpace , Kokkos::Experime namespace Kokkos { namespace Impl { -template<> -class SharedAllocationRecord< Kokkos::Experimental::ROCmSpace , void > - : public SharedAllocationRecord< void , void > -{ -private: +template <> +class SharedAllocationRecord + : public SharedAllocationRecord { + private: + typedef SharedAllocationRecord RecordBase; + SharedAllocationRecord(const SharedAllocationRecord&) = delete; + SharedAllocationRecord& operator=(const SharedAllocationRecord&) = delete; - typedef SharedAllocationRecord< void , void > RecordBase ; - - SharedAllocationRecord( const SharedAllocationRecord & ) = delete ; - SharedAllocationRecord & operator = ( const SharedAllocationRecord & ) = delete ; - - static void deallocate( RecordBase * ); + static void deallocate(RecordBase*); #ifdef KOKKOS_DEBUG - static RecordBase s_root_record ; + static RecordBase s_root_record; #endif - const Kokkos::Experimental::ROCmSpace m_space ; - -protected: + const Kokkos::Experimental::ROCmSpace m_space; + protected: ~SharedAllocationRecord(); - SharedAllocationRecord( const Kokkos::Experimental::ROCmSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - , const RecordBase::function_type arg_dealloc = & deallocate - ); + SharedAllocationRecord( + const Kokkos::Experimental::ROCmSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size, + const RecordBase::function_type arg_dealloc = &deallocate); -public: + public: + std::string get_label() const; - std::string get_label() const ; - - static SharedAllocationRecord * allocate( const Kokkos::Experimental::ROCmSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size ); + static SharedAllocationRecord* allocate( + const Kokkos::Experimental::ROCmSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size); /**\brief Allocate tracked memory in the space */ - static - void * allocate_tracked( const Kokkos::Experimental::ROCmSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size ); + static void* allocate_tracked( + const Kokkos::Experimental::ROCmSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size); /**\brief Reallocate tracked memory in the space */ - static - void * reallocate_tracked( void * const arg_alloc_ptr - , const size_t arg_alloc_size ); + static void* reallocate_tracked(void* const arg_alloc_ptr, + const size_t arg_alloc_size); /**\brief Deallocate tracked memory in the space */ - static - void deallocate_tracked( void * const arg_alloc_ptr ); + static void deallocate_tracked(void* const arg_alloc_ptr); - static SharedAllocationRecord * get_record( void * arg_alloc_ptr ); + static SharedAllocationRecord* get_record(void* arg_alloc_ptr); - static void print_records( std::ostream & , const Kokkos::Experimental::ROCmSpace & , bool detail = false ); + static void print_records(std::ostream&, + const Kokkos::Experimental::ROCmSpace&, + bool detail = false); }; -template<> -class SharedAllocationRecord< Kokkos::Experimental::ROCmHostPinnedSpace , void > - : public SharedAllocationRecord< void , void > -{ -private: - - typedef SharedAllocationRecord< void , void > RecordBase ; +template <> +class SharedAllocationRecord + : public SharedAllocationRecord { + private: + typedef SharedAllocationRecord RecordBase; - SharedAllocationRecord( const SharedAllocationRecord & ) = delete ; - SharedAllocationRecord & operator = ( const SharedAllocationRecord & ) = delete ; + SharedAllocationRecord(const SharedAllocationRecord&) = delete; + SharedAllocationRecord& operator=(const SharedAllocationRecord&) = delete; - static void deallocate( RecordBase * ); + static void deallocate(RecordBase*); #ifdef KOKKOS_DEBUG - static RecordBase s_root_record ; + static RecordBase s_root_record; #endif - const Kokkos::Experimental::ROCmHostPinnedSpace m_space ; - -protected: + const Kokkos::Experimental::ROCmHostPinnedSpace m_space; + protected: ~SharedAllocationRecord(); SharedAllocationRecord() : RecordBase(), m_space() {} - SharedAllocationRecord( const Kokkos::Experimental::ROCmHostPinnedSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - , const RecordBase::function_type arg_dealloc = & deallocate - ); - -public: + SharedAllocationRecord( + const Kokkos::Experimental::ROCmHostPinnedSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size, + const RecordBase::function_type arg_dealloc = &deallocate); - std::string get_label() const ; + public: + std::string get_label() const; - static SharedAllocationRecord * allocate( const Kokkos::Experimental::ROCmHostPinnedSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - ); + static SharedAllocationRecord* allocate( + const Kokkos::Experimental::ROCmHostPinnedSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size); /**\brief Allocate tracked memory in the space */ - static - void * allocate_tracked( const Kokkos::Experimental::ROCmHostPinnedSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size ); + static void* allocate_tracked( + const Kokkos::Experimental::ROCmHostPinnedSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size); /**\brief Reallocate tracked memory in the space */ - static - void * reallocate_tracked( void * const arg_alloc_ptr - , const size_t arg_alloc_size ); + static void* reallocate_tracked(void* const arg_alloc_ptr, + const size_t arg_alloc_size); /**\brief Deallocate tracked memory in the space */ - static - void deallocate_tracked( void * const arg_alloc_ptr ); + static void deallocate_tracked(void* const arg_alloc_ptr); + static SharedAllocationRecord* get_record(void* arg_alloc_ptr); - static SharedAllocationRecord * get_record( void * arg_alloc_ptr ); - - static void print_records( std::ostream & , const Kokkos::Experimental::ROCmHostPinnedSpace & , bool detail = false ); + static void print_records(std::ostream&, + const Kokkos::Experimental::ROCmHostPinnedSpace&, + bool detail = false); }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- #endif /* #if defined( KOKKOS_ENABLE_ROCM ) */ #endif /* #define KOKKOS_ROCMSPACE_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_ScratchSpace.hpp b/lib/kokkos/core/src/Kokkos_ScratchSpace.hpp index 86d803ccc9..c2337f08a1 100644 --- a/lib/kokkos/core/src/Kokkos_ScratchSpace.hpp +++ b/lib/kokkos/core/src/Kokkos_ScratchSpace.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -55,158 +56,157 @@ namespace Kokkos { /** \brief Scratch memory space associated with an execution space. * */ -template< class ExecSpace > +template class ScratchMemorySpace { - static_assert (is_execution_space::value,"Instantiating ScratchMemorySpace on non-execution-space type."); -public: + static_assert( + is_execution_space::value, + "Instantiating ScratchMemorySpace on non-execution-space type."); + public: // Alignment of memory chunks returned by 'get' // must be a power of two enum { ALIGN = 8 }; -private: - - mutable char * m_iter_L0 ; - char * m_end_L0 ; - mutable char * m_iter_L1 ; - char * m_end_L1 ; - + private: + mutable char* m_iter_L0; + char* m_end_L0; + mutable char* m_iter_L1; + char* m_end_L1; mutable int m_multiplier; mutable int m_offset; mutable int m_default_level; ScratchMemorySpace(); - ScratchMemorySpace & operator = ( const ScratchMemorySpace & ); - - enum { MASK = ALIGN - 1 }; // Alignment used by View::shmem_size + ScratchMemorySpace& operator=(const ScratchMemorySpace&); -public: + enum { MASK = ALIGN - 1 }; // Alignment used by View::shmem_size + public: //! Tag this class as a memory space - typedef ScratchMemorySpace memory_space ; - typedef ExecSpace execution_space ; + typedef ScratchMemorySpace memory_space; + typedef ExecSpace execution_space; //! This execution space preferred device_type - typedef Kokkos::Device device_type; + typedef Kokkos::Device device_type; - typedef typename ExecSpace::array_layout array_layout ; - typedef typename ExecSpace::size_type size_type ; + typedef typename ExecSpace::array_layout array_layout; + typedef typename ExecSpace::size_type size_type; - template< typename IntType > - KOKKOS_INLINE_FUNCTION static - IntType align( const IntType & size ) - { return ( size + MASK ) & ~MASK ; } + template + KOKKOS_INLINE_FUNCTION static IntType align(const IntType& size) { + return (size + MASK) & ~MASK; + } - template< typename IntType > - KOKKOS_INLINE_FUNCTION - void* get_shmem (const IntType& size, int level = -1) const { - if(level == -1) - level = m_default_level; - if(level == 0) { - void* tmp = m_iter_L0 + m_offset * align (size); - if (m_end_L0 < (m_iter_L0 += align (size) * m_multiplier)) { - m_iter_L0 -= align (size) * m_multiplier; // put it back like it was - #ifdef KOKKOS_DEBUG + template + KOKKOS_INLINE_FUNCTION void* get_shmem(const IntType& size, + int level = -1) const { + if (level == -1) level = m_default_level; + if (level == 0) { + void* tmp = m_iter_L0 + m_offset * align(size); + if (m_end_L0 < (m_iter_L0 += align(size) * m_multiplier)) { + m_iter_L0 -= align(size) * m_multiplier; // put it back like it was +#ifdef KOKKOS_DEBUG // mfh 23 Jun 2015: printf call consumes 25 registers // in a CUDA build, so only print in debug mode. The // function still returns NULL if not enough memory. - printf ("ScratchMemorySpace<...>::get_shmem: Failed to allocate " - "%ld byte(s); remaining capacity is %ld byte(s)\n", long(size), - long(m_end_L0-m_iter_L0)); - #endif // KOKKOS_DEBUG + printf( + "ScratchMemorySpace<...>::get_shmem: Failed to allocate " + "%ld byte(s); remaining capacity is %ld byte(s)\n", + long(size), long(m_end_L0 - m_iter_L0)); +#endif // KOKKOS_DEBUG tmp = 0; } return tmp; } else { - void* tmp = m_iter_L1 + m_offset * align (size); - if (m_end_L1 < (m_iter_L1 += align (size) * m_multiplier)) { - m_iter_L1 -= align (size) * m_multiplier; // put it back like it was - #ifdef KOKKOS_DEBUG + void* tmp = m_iter_L1 + m_offset * align(size); + if (m_end_L1 < (m_iter_L1 += align(size) * m_multiplier)) { + m_iter_L1 -= align(size) * m_multiplier; // put it back like it was +#ifdef KOKKOS_DEBUG // mfh 23 Jun 2015: printf call consumes 25 registers // in a CUDA build, so only print in debug mode. The // function still returns NULL if not enough memory. - printf ("ScratchMemorySpace<...>::get_shmem: Failed to allocate " - "%ld byte(s); remaining capacity is %ld byte(s)\n", long(size), - long(m_end_L1-m_iter_L1)); - #endif // KOKKOS_DEBUG + printf( + "ScratchMemorySpace<...>::get_shmem: Failed to allocate " + "%ld byte(s); remaining capacity is %ld byte(s)\n", + long(size), long(m_end_L1 - m_iter_L1)); +#endif // KOKKOS_DEBUG tmp = 0; } return tmp; - } } - KOKKOS_INLINE_FUNCTION - void* get_shmem_aligned (const ptrdiff_t size, const ptrdiff_t alignment, int level = -1) const { - if(level == -1) - level = m_default_level; - if(level == 0) { - - char* previous = m_iter_L0; - const ptrdiff_t missalign = size_t(m_iter_L0)%alignment; - if(missalign) m_iter_L0 += alignment-missalign; + void* get_shmem_aligned(const ptrdiff_t size, const ptrdiff_t alignment, + int level = -1) const { + if (level == -1) level = m_default_level; + if (level == 0) { + char* previous = m_iter_L0; + const ptrdiff_t missalign = size_t(m_iter_L0) % alignment; + if (missalign) m_iter_L0 += alignment - missalign; void* tmp = m_iter_L0 + m_offset * size; if (m_end_L0 < (m_iter_L0 += size * m_multiplier)) { - m_iter_L0 = previous; // put it back like it was - #ifdef KOKKOS_DEBUG + m_iter_L0 = previous; // put it back like it was +#ifdef KOKKOS_DEBUG // mfh 23 Jun 2015: printf call consumes 25 registers // in a CUDA build, so only print in debug mode. The // function still returns NULL if not enough memory. - printf ("ScratchMemorySpace<...>::get_shmem: Failed to allocate " - "%ld byte(s); remaining capacity is %ld byte(s)\n", long(size), - long(m_end_L0-m_iter_L0)); - #endif // KOKKOS_DEBUG + printf( + "ScratchMemorySpace<...>::get_shmem: Failed to allocate " + "%ld byte(s); remaining capacity is %ld byte(s)\n", + long(size), long(m_end_L0 - m_iter_L0)); +#endif // KOKKOS_DEBUG tmp = 0; } return tmp; } else { - - char* previous = m_iter_L1; - const ptrdiff_t missalign = size_t(m_iter_L1)%alignment; - if(missalign) m_iter_L1 += alignment-missalign; + char* previous = m_iter_L1; + const ptrdiff_t missalign = size_t(m_iter_L1) % alignment; + if (missalign) m_iter_L1 += alignment - missalign; void* tmp = m_iter_L1 + m_offset * size; if (m_end_L1 < (m_iter_L1 += size * m_multiplier)) { - m_iter_L1 = previous; // put it back like it was - #ifdef KOKKOS_DEBUG + m_iter_L1 = previous; // put it back like it was +#ifdef KOKKOS_DEBUG // mfh 23 Jun 2015: printf call consumes 25 registers // in a CUDA build, so only print in debug mode. The // function still returns NULL if not enough memory. - printf ("ScratchMemorySpace<...>::get_shmem: Failed to allocate " - "%ld byte(s); remaining capacity is %ld byte(s)\n", long(size), - long(m_end_L1-m_iter_L1)); - #endif // KOKKOS_DEBUG + printf( + "ScratchMemorySpace<...>::get_shmem: Failed to allocate " + "%ld byte(s); remaining capacity is %ld byte(s)\n", + long(size), long(m_end_L1 - m_iter_L1)); +#endif // KOKKOS_DEBUG tmp = 0; } return tmp; - } } - template< typename IntType > - KOKKOS_INLINE_FUNCTION - ScratchMemorySpace( void * ptr_L0 , const IntType & size_L0 , void * ptr_L1 = NULL , const IntType & size_L1 = 0) - : m_iter_L0( (char *) ptr_L0 ) - , m_end_L0( m_iter_L0 + size_L0 ) - , m_iter_L1( (char *) ptr_L1 ) - , m_end_L1( m_iter_L1 + size_L1 ) - , m_multiplier( 1 ) - , m_offset( 0 ) - , m_default_level( 0 ) - {} + template + KOKKOS_INLINE_FUNCTION ScratchMemorySpace(void* ptr_L0, + const IntType& size_L0, + void* ptr_L1 = NULL, + const IntType& size_L1 = 0) + : m_iter_L0((char*)ptr_L0), + m_end_L0(m_iter_L0 + size_L0), + m_iter_L1((char*)ptr_L1), + m_end_L1(m_iter_L1 + size_L1), + m_multiplier(1), + m_offset(0), + m_default_level(0) {} KOKKOS_INLINE_FUNCTION - const ScratchMemorySpace& set_team_thread_mode(const int& level, const int& multiplier, const int& offset) const { + const ScratchMemorySpace& set_team_thread_mode(const int& level, + const int& multiplier, + const int& offset) const { m_default_level = level; - m_multiplier = multiplier; - m_offset = offset; + m_multiplier = multiplier; + m_offset = offset; return *this; } }; -} // namespace Kokkos +} // namespace Kokkos #endif /* #ifndef KOKKOS_SCRATCHSPACE_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_Serial.hpp b/lib/kokkos/core/src/Kokkos_Serial.hpp index 5821b0c0c5..e30598be21 100644 --- a/lib/kokkos/core/src/Kokkos_Serial.hpp +++ b/lib/kokkos/core/src/Kokkos_Serial.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,7 +49,7 @@ #define KOKKOS_SERIAL_HPP #include -#if defined( KOKKOS_ENABLE_SERIAL ) +#if defined(KOKKOS_ENABLE_SERIAL) #include #include @@ -83,24 +84,24 @@ namespace Kokkos { /// threads, or if you want to explore different combinations of MPI /// and shared-memory parallel programming models. class Serial { -public: + public: //! \name Type declarations that all Kokkos devices must provide. //@{ //! Tag this class as an execution space: - typedef Serial execution_space ; + typedef Serial execution_space; //! The size_type typedef best suited for this device. - typedef HostSpace::size_type size_type ; + typedef HostSpace::size_type size_type; //! This device's preferred memory space. - typedef HostSpace memory_space ; + typedef HostSpace memory_space; //! This execution space preferred device_type - typedef Kokkos::Device device_type; + typedef Kokkos::Device device_type; //! This device's preferred array layout. - typedef LayoutRight array_layout ; + typedef LayoutRight array_layout; /// \brief Scratch memory space - typedef ScratchMemorySpace< Kokkos::Serial > scratch_memory_space ; + typedef ScratchMemorySpace scratch_memory_space; //@} @@ -110,7 +111,7 @@ public: /// For the Serial device, this method always returns false, /// because parallel_for or parallel_reduce with the Serial device /// always execute sequentially. - inline static int in_parallel() { return false ; } + inline static int in_parallel() { return false; } /// \brief Wait until all dispatched functors complete. /// @@ -120,26 +121,27 @@ public: /// device have completed. static void impl_static_fence() {} - #ifdef KOKKOS_ENABLE_DEPRECATED_CODE +#ifdef KOKKOS_ENABLE_DEPRECATED_CODE static void fence() {} - #else +#else void fence() const {} - #endif +#endif /** \brief Return the maximum amount of concurrency. */ - static int concurrency() {return 1;} + static int concurrency() { return 1; } //! Print configuration information to the given output stream. - static void print_configuration( std::ostream & , const bool /* detail */ = false ) {} + static void print_configuration(std::ostream&, + const bool /* detail */ = false) {} #ifdef KOKKOS_ENABLE_DEPRECATED_CODE static bool sleep(); static bool wake(); - static void initialize( unsigned threads_count = 1 , - unsigned use_numa_count = 0 , - unsigned use_cores_per_numa = 0 , - bool allow_asynchronous_threadpool = false); + static void initialize(unsigned threads_count = 1, + unsigned use_numa_count = 0, + unsigned use_cores_per_numa = 0, + bool allow_asynchronous_threadpool = false); static bool is_initialized(); @@ -148,12 +150,14 @@ public: //-------------------------------------------------------------------------- - inline static int thread_pool_size( int = 0 ) { return 1 ; } - KOKKOS_INLINE_FUNCTION static int thread_pool_rank() { return 0 ; } + inline static int thread_pool_size(int = 0) { return 1; } + KOKKOS_INLINE_FUNCTION static int thread_pool_rank() { return 0; } //-------------------------------------------------------------------------- - KOKKOS_INLINE_FUNCTION static unsigned hardware_thread_id() { return thread_pool_rank(); } + KOKKOS_INLINE_FUNCTION static unsigned hardware_thread_id() { + return thread_pool_rank(); + } inline static unsigned max_hardware_threads() { return thread_pool_size(0); } #else static void impl_initialize(); @@ -165,20 +169,24 @@ public: //-------------------------------------------------------------------------- - inline static int impl_thread_pool_size( int = 0 ) { return 1 ; } - KOKKOS_INLINE_FUNCTION static int impl_thread_pool_rank() { return 0 ; } + inline static int impl_thread_pool_size(int = 0) { return 1; } + KOKKOS_INLINE_FUNCTION static int impl_thread_pool_rank() { return 0; } //-------------------------------------------------------------------------- - KOKKOS_INLINE_FUNCTION static unsigned impl_hardware_thread_id() { return impl_thread_pool_rank(); } - inline static unsigned impl_max_hardware_threads() { return impl_thread_pool_size(0); } + KOKKOS_INLINE_FUNCTION static unsigned impl_hardware_thread_id() { + return impl_thread_pool_rank(); + } + inline static unsigned impl_max_hardware_threads() { + return impl_thread_pool_size(0); + } #endif static const char* name(); //-------------------------------------------------------------------------- }; -} // namespace Kokkos +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -186,30 +194,24 @@ public: namespace Kokkos { namespace Impl { -template<> -struct MemorySpaceAccess - < Kokkos::Serial::memory_space - , Kokkos::Serial::scratch_memory_space - > -{ +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = true }; - enum { deepcopy = false }; + enum { deepcopy = false }; }; -template<> -struct VerifyExecutionCanAccessMemorySpace - < Kokkos::Serial::memory_space - , Kokkos::Serial::scratch_memory_space - > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace< + Kokkos::Serial::memory_space, Kokkos::Serial::scratch_memory_space> { enum { value = true }; - inline static void verify( void ) { } - inline static void verify( const void * ) { } + inline static void verify(void) {} + inline static void verify(const void*) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -218,247 +220,294 @@ namespace Kokkos { namespace Impl { // Resize thread team data scratch memory -void serial_resize_thread_team_data( size_t pool_reduce_bytes - , size_t team_reduce_bytes - , size_t team_shared_bytes - , size_t thread_local_bytes ); +void serial_resize_thread_team_data(size_t pool_reduce_bytes, + size_t team_reduce_bytes, + size_t team_shared_bytes, + size_t thread_local_bytes); -HostThreadTeamData * serial_get_thread_team_data(); +HostThreadTeamData* serial_get_thread_team_data(); } /* namespace Impl */ } /* namespace Kokkos */ - namespace Kokkos { namespace Impl { /* * < Kokkos::Serial , WorkArgTag > - * < WorkArgTag , Impl::enable_if< std::is_same< Kokkos::Serial , Kokkos::DefaultExecutionSpace >::value >::type > + * < WorkArgTag , Impl::enable_if< std::is_same< Kokkos::Serial , + * Kokkos::DefaultExecutionSpace >::value >::type > * */ -template< class ... Properties > -class TeamPolicyInternal< Kokkos::Serial , Properties ... >:public PolicyTraits -{ -private: - - size_t m_team_scratch_size[2] ; - size_t m_thread_scratch_size[2] ; - int m_league_size ; - int m_chunk_size; - -public: - +template +class TeamPolicyInternal + : public PolicyTraits { + private: + size_t m_team_scratch_size[2]; + size_t m_thread_scratch_size[2]; + int m_league_size; + int m_chunk_size; + + public: //! Tag this class as a kokkos execution policy - typedef TeamPolicyInternal execution_policy ; + typedef TeamPolicyInternal execution_policy; - typedef PolicyTraits traits; + typedef PolicyTraits traits; //! Execution space of this execution policy: - typedef Kokkos::Serial execution_space ; + typedef Kokkos::Serial execution_space; - TeamPolicyInternal& operator = (const TeamPolicyInternal& p) { - m_league_size = p.m_league_size; - m_team_scratch_size[0] = p.m_team_scratch_size[0]; + TeamPolicyInternal& operator=(const TeamPolicyInternal& p) { + m_league_size = p.m_league_size; + m_team_scratch_size[0] = p.m_team_scratch_size[0]; m_thread_scratch_size[0] = p.m_thread_scratch_size[0]; - m_team_scratch_size[1] = p.m_team_scratch_size[1]; + m_team_scratch_size[1] = p.m_team_scratch_size[1]; m_thread_scratch_size[1] = p.m_thread_scratch_size[1]; - m_chunk_size = p.m_chunk_size; + m_chunk_size = p.m_chunk_size; return *this; } - template + template friend class TeamPolicyInternal; - template< class ... OtherProperties > - TeamPolicyInternal(const TeamPolicyInternal& p) { - m_league_size = p.m_league_size; - m_team_scratch_size[0] = p.m_team_scratch_size[0]; + template + TeamPolicyInternal( + const TeamPolicyInternal& p) { + m_league_size = p.m_league_size; + m_team_scratch_size[0] = p.m_team_scratch_size[0]; m_thread_scratch_size[0] = p.m_thread_scratch_size[0]; - m_team_scratch_size[1] = p.m_team_scratch_size[1]; + m_team_scratch_size[1] = p.m_team_scratch_size[1]; m_thread_scratch_size[1] = p.m_thread_scratch_size[1]; - m_chunk_size = p.m_chunk_size; + m_chunk_size = p.m_chunk_size; } - //---------------------------------------- #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - template< class FunctorType > - static - int team_size_max( const FunctorType & ) { return 1 ; } + template + static int team_size_max(const FunctorType&) { + return 1; + } - template< class FunctorType > - static - int team_size_recommended( const FunctorType & ) { return 1 ; } + template + static int team_size_recommended(const FunctorType&) { + return 1; + } - template< class FunctorType > - static - int team_size_recommended( const FunctorType & , const int& ) { return 1 ; } + template + static int team_size_recommended(const FunctorType&, const int&) { + return 1; + } #endif - template - int team_size_max( const FunctorType&, const ParallelForTag& ) const { return 1 ; } - template - int team_size_max( const FunctorType&, const ParallelReduceTag& ) const { return 1 ; } - template - int team_size_recommended( const FunctorType&, const ParallelForTag& ) const { return 1 ; } - template - int team_size_recommended( const FunctorType&, const ParallelReduceTag& ) const { return 1 ; } + template + int team_size_max(const FunctorType&, const ParallelForTag&) const { + return 1; + } + template + int team_size_max(const FunctorType&, const ParallelReduceTag&) const { + return 1; + } + template + int team_size_max(const FunctorType&, const ReducerType&, + const ParallelReduceTag&) const { + return 1; + } + template + int team_size_recommended(const FunctorType&, const ParallelForTag&) const { + return 1; + } + template + int team_size_recommended(const FunctorType&, + const ParallelReduceTag&) const { + return 1; + } + template + int team_size_recommended(const FunctorType&, const ReducerType&, + const ParallelReduceTag&) const { + return 1; + } //---------------------------------------- - inline int team_size() const { return 1 ; } - inline int league_size() const { return m_league_size ; } - inline size_t scratch_size(const int& level, int = 0) const { return m_team_scratch_size[level] + m_thread_scratch_size[level]; } + inline int team_size() const { return 1; } + inline int league_size() const { return m_league_size; } + inline size_t scratch_size(const int& level, int = 0) const { + return m_team_scratch_size[level] + m_thread_scratch_size[level]; + } - inline static - int vector_length_max() - { return 1024; } // Use arbitrary large number, is meant as a vectorizable length + inline static int vector_length_max() { + return 1024; + } // Use arbitrary large number, is meant as a vectorizable length - inline static - int scratch_size_max(int level) - { return (level==0? - 1024*32: - 20*1024*1024); + inline static int scratch_size_max(int level) { + return (level == 0 ? 1024 * 32 : 20 * 1024 * 1024); } /** \brief Specify league size, request team size */ - TeamPolicyInternal( const execution_space & - , int league_size_request + TeamPolicyInternal(const execution_space&, int league_size_request #ifndef KOKKOS_ENABLE_DEPRECATED_CODE - , int team_size_request + , + int team_size_request #else - , int /* team_size_request */ + , + int /* team_size_request */ #endif - , int /* vector_length_request */ = 1 ) - : m_team_scratch_size { 0 , 0 } - , m_thread_scratch_size { 0 , 0 } - , m_league_size( league_size_request ) - , m_chunk_size ( 32 ) - { - #ifndef KOKKOS_ENABLE_DEPRECATED_CODE - if(team_size_request > 1) Kokkos::abort("Kokkos::abort: Requested Team Size is too large!"); - #endif - } + , + int /* vector_length_request */ = 1) + : m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, + m_league_size(league_size_request), + m_chunk_size(32) { +#ifndef KOKKOS_ENABLE_DEPRECATED_CODE + if (team_size_request > 1) + Kokkos::abort("Kokkos::abort: Requested Team Size is too large!"); +#endif + } + + TeamPolicyInternal(const execution_space&, int league_size_request, + const Kokkos::AUTO_t& /* team_size_request */ + , + int /* vector_length_request */ = 1) + : m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, + m_league_size(league_size_request), + m_chunk_size(32) {} - TeamPolicyInternal( const execution_space & - , int league_size_request - , const Kokkos::AUTO_t & /* team_size_request */ - , int /* vector_length_request */ = 1 ) - : m_team_scratch_size { 0 , 0 } - , m_thread_scratch_size { 0 , 0 } - , m_league_size( league_size_request ) - , m_chunk_size ( 32 ) - {} - - TeamPolicyInternal( int league_size_request + TeamPolicyInternal(int league_size_request #ifndef KOKKOS_ENABLE_DEPRECATED_CODE - , int team_size_request + , + int team_size_request #else - , int /* team_size_request */ + , + int /* team_size_request */ #endif - , int /* vector_length_request */ = 1 ) - : m_team_scratch_size { 0 , 0 } - , m_thread_scratch_size { 0 , 0 } - , m_league_size( league_size_request ) - , m_chunk_size ( 32 ) - { - #ifndef KOKKOS_ENABLE_DEPRECATED_CODE - if(team_size_request > 1) Kokkos::abort("Kokkos::abort: Requested Team Size is too large!"); - #endif - } + , + int /* vector_length_request */ = 1) + : m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, + m_league_size(league_size_request), + m_chunk_size(32) { +#ifndef KOKKOS_ENABLE_DEPRECATED_CODE + if (team_size_request > 1) + Kokkos::abort("Kokkos::abort: Requested Team Size is too large!"); +#endif + } - TeamPolicyInternal( int league_size_request - , const Kokkos::AUTO_t & /* team_size_request */ - , int /* vector_length_request */ = 1 ) - : m_team_scratch_size { 0 , 0 } - , m_thread_scratch_size { 0 , 0 } - , m_league_size( league_size_request ) - , m_chunk_size ( 32 ) - {} + TeamPolicyInternal(int league_size_request, + const Kokkos::AUTO_t& /* team_size_request */ + , + int /* vector_length_request */ = 1) + : m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, + m_league_size(league_size_request), + m_chunk_size(32) {} - inline int chunk_size() const { return m_chunk_size ; } + inline int chunk_size() const { return m_chunk_size; } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE /** \brief set chunk_size to a discrete value*/ - inline TeamPolicyInternal set_chunk_size(typename traits::index_type chunk_size_) const { + inline TeamPolicyInternal set_chunk_size( + typename traits::index_type chunk_size_) const { TeamPolicyInternal p = *this; - p.m_chunk_size = chunk_size_; + p.m_chunk_size = chunk_size_; return p; } - /** \brief set per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal set_scratch_size(const int& level, const PerTeamValue& per_team) const { - TeamPolicyInternal p = *this; + /** \brief set per team scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal set_scratch_size( + const int& level, const PerTeamValue& per_team) const { + TeamPolicyInternal p = *this; p.m_team_scratch_size[level] = per_team.value; return p; } - /** \brief set per thread scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal set_scratch_size(const int& level, const PerThreadValue& per_thread) const { - TeamPolicyInternal p = *this; + /** \brief set per thread scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal set_scratch_size( + const int& level, const PerThreadValue& per_thread) const { + TeamPolicyInternal p = *this; p.m_thread_scratch_size[level] = per_thread.value; return p; } - /** \brief set per thread and per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal set_scratch_size(const int& level, const PerTeamValue& per_team, const PerThreadValue& per_thread) const { - TeamPolicyInternal p = *this; - p.m_team_scratch_size[level] = per_team.value; + /** \brief set per thread and per team scratch size for a specific level of + * the scratch hierarchy */ + inline TeamPolicyInternal set_scratch_size( + const int& level, const PerTeamValue& per_team, + const PerThreadValue& per_thread) const { + TeamPolicyInternal p = *this; + p.m_team_scratch_size[level] = per_team.value; p.m_thread_scratch_size[level] = per_thread.value; return p; } #else /** \brief set chunk_size to a discrete value*/ - inline TeamPolicyInternal& set_chunk_size(typename traits::index_type chunk_size_) { + inline TeamPolicyInternal& set_chunk_size( + typename traits::index_type chunk_size_) { m_chunk_size = chunk_size_; return *this; } - /** \brief set per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal& set_scratch_size(const int& level, const PerTeamValue& per_team) { + /** \brief set per team scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal& set_scratch_size(const int& level, + const PerTeamValue& per_team) { m_team_scratch_size[level] = per_team.value; return *this; } - /** \brief set per thread scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal& set_scratch_size(const int& level, const PerThreadValue& per_thread) { + /** \brief set per thread scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal& set_scratch_size( + const int& level, const PerThreadValue& per_thread) { m_thread_scratch_size[level] = per_thread.value; return *this; } - /** \brief set per thread and per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal& set_scratch_size(const int& level, const PerTeamValue& per_team, const PerThreadValue& per_thread) { - m_team_scratch_size[level] = per_team.value; + /** \brief set per thread and per team scratch size for a specific level of + * the scratch hierarchy */ + inline TeamPolicyInternal& set_scratch_size( + const int& level, const PerTeamValue& per_team, + const PerThreadValue& per_thread) { + m_team_scratch_size[level] = per_team.value; m_thread_scratch_size[level] = per_thread.value; return *this; } #endif - typedef Impl::HostThreadTeamMember< Kokkos::Serial > member_type ; + typedef Impl::HostThreadTeamMember member_type; -protected: + protected: #ifdef KOKKOS_ENABLE_DEPRECATED_CODE /** \brief set chunk_size to a discrete value*/ - inline TeamPolicyInternal internal_set_chunk_size(typename traits::index_type chunk_size_) { + inline TeamPolicyInternal internal_set_chunk_size( + typename traits::index_type chunk_size_) { m_chunk_size = chunk_size_; return *this; } - /** \brief set per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal internal_set_scratch_size(const int& level, const PerTeamValue& per_team) { + /** \brief set per team scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal internal_set_scratch_size( + const int& level, const PerTeamValue& per_team) { m_team_scratch_size[level] = per_team.value; return *this; } - /** \brief set per thread scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal internal_set_scratch_size(const int& level, const PerThreadValue& per_thread) { + /** \brief set per thread scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal internal_set_scratch_size( + const int& level, const PerThreadValue& per_thread) { m_thread_scratch_size[level] = per_thread.value; return *this; } - /** \brief set per thread and per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal internal_set_scratch_size(const int& level, const PerTeamValue& per_team, const PerThreadValue& per_thread) { - m_team_scratch_size[level] = per_team.value; + /** \brief set per thread and per team scratch size for a specific level of + * the scratch hierarchy */ + inline TeamPolicyInternal internal_set_scratch_size( + const int& level, const PerTeamValue& per_team, + const PerThreadValue& per_thread) { + m_team_scratch_size[level] = per_team.value; m_thread_scratch_size[level] = per_thread.value; return *this; } @@ -474,339 +523,280 @@ protected: namespace Kokkos { namespace Impl { -template< class FunctorType , class ... Traits > -class ParallelFor< FunctorType , - Kokkos::RangePolicy< Traits ... > , - Kokkos::Serial - > -{ -private: - - typedef Kokkos::RangePolicy< Traits ... > Policy ; - - const FunctorType m_functor ; - const Policy m_policy ; - - template< class TagType > - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec() const - { - const typename Policy::member_type e = m_policy.end(); - for ( typename Policy::member_type i = m_policy.begin() ; i < e ; ++i ) { - m_functor( i ); - } - } +template +class ParallelFor, Kokkos::Serial> { + private: + typedef Kokkos::RangePolicy Policy; + + const FunctorType m_functor; + const Policy m_policy; - template< class TagType > - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec() const - { - const TagType t{} ; - const typename Policy::member_type e = m_policy.end(); - for ( typename Policy::member_type i = m_policy.begin() ; i < e ; ++i ) { - m_functor( t , i ); - } + template + typename std::enable_if::value>::type exec() + const { + const typename Policy::member_type e = m_policy.end(); + for (typename Policy::member_type i = m_policy.begin(); i < e; ++i) { + m_functor(i); } + } -public: + template + typename std::enable_if::value>::type exec() + const { + const TagType t{}; + const typename Policy::member_type e = m_policy.end(); + for (typename Policy::member_type i = m_policy.begin(); i < e; ++i) { + m_functor(t, i); + } + } - inline - void execute() const - { this-> template exec< typename Policy::work_tag >(); } + public: + inline void execute() const { + this->template exec(); + } - inline - ParallelFor( const FunctorType & arg_functor - , const Policy & arg_policy ) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - {} + inline ParallelFor(const FunctorType& arg_functor, const Policy& arg_policy) + : m_functor(arg_functor), m_policy(arg_policy) {} }; /*--------------------------------------------------------------------------*/ -template< class FunctorType , class ReducerType , class ... Traits > -class ParallelReduce< FunctorType - , Kokkos::RangePolicy< Traits ... > - , ReducerType - , Kokkos::Serial - > -{ -private: - - typedef Kokkos::RangePolicy< Traits ... > Policy ; - typedef typename Policy::work_tag WorkTag ; +template +class ParallelReduce, ReducerType, + Kokkos::Serial> { + private: + typedef Kokkos::RangePolicy Policy; + typedef typename Policy::work_tag WorkTag; - typedef Kokkos::Impl::if_c< std::is_same::value, FunctorType, ReducerType> ReducerConditional; + typedef Kokkos::Impl::if_c::value, + FunctorType, ReducerType> + ReducerConditional; typedef typename ReducerConditional::type ReducerTypeFwd; - typedef typename Kokkos::Impl::if_c< std::is_same::value, WorkTag, void>::type WorkTagFwd; + typedef + typename Kokkos::Impl::if_c::value, + WorkTag, void>::type WorkTagFwd; - typedef FunctorAnalysis< FunctorPatternInterface::REDUCE , Policy , FunctorType > Analysis ; + typedef FunctorAnalysis + Analysis; - typedef Kokkos::Impl::FunctorValueInit< ReducerTypeFwd , WorkTagFwd > ValueInit ; + typedef Kokkos::Impl::FunctorValueInit ValueInit; - typedef typename Analysis::pointer_type pointer_type ; - typedef typename Analysis::reference_type reference_type ; + typedef typename Analysis::pointer_type pointer_type; + typedef typename Analysis::reference_type reference_type; - const FunctorType m_functor ; - const Policy m_policy ; - const ReducerType m_reducer ; - const pointer_type m_result_ptr ; + const FunctorType m_functor; + const Policy m_policy; + const ReducerType m_reducer; + const pointer_type m_result_ptr; - template< class TagType > - inline - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec( reference_type update ) const - { - const typename Policy::member_type e = m_policy.end(); - for ( typename Policy::member_type i = m_policy.begin() ; i < e ; ++i ) { - m_functor( i , update ); - } + template + inline typename std::enable_if::value>::type exec( + reference_type update) const { + const typename Policy::member_type e = m_policy.end(); + for (typename Policy::member_type i = m_policy.begin(); i < e; ++i) { + m_functor(i, update); } + } - template< class TagType > - inline - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec( reference_type update ) const - { - const TagType t{} ; - - const typename Policy::member_type e = m_policy.end(); - for ( typename Policy::member_type i = m_policy.begin() ; i < e ; ++i ) { - m_functor( t , i , update ); - } - } + template + inline typename std::enable_if::value>::type + exec(reference_type update) const { + const TagType t{}; -public: + const typename Policy::member_type e = m_policy.end(); + for (typename Policy::member_type i = m_policy.begin(); i < e; ++i) { + m_functor(t, i, update); + } + } - inline - void execute() const - { - const size_t pool_reduce_size = - Analysis::value_size( ReducerConditional::select(m_functor , m_reducer) ); - const size_t team_reduce_size = 0 ; // Never shrinks - const size_t team_shared_size = 0 ; // Never shrinks - const size_t thread_local_size = 0 ; // Never shrinks + public: + inline void execute() const { + const size_t pool_reduce_size = + Analysis::value_size(ReducerConditional::select(m_functor, m_reducer)); + const size_t team_reduce_size = 0; // Never shrinks + const size_t team_shared_size = 0; // Never shrinks + const size_t thread_local_size = 0; // Never shrinks - serial_resize_thread_team_data( pool_reduce_size - , team_reduce_size - , team_shared_size - , thread_local_size ); + serial_resize_thread_team_data(pool_reduce_size, team_reduce_size, + team_shared_size, thread_local_size); - HostThreadTeamData & data = *serial_get_thread_team_data(); + HostThreadTeamData& data = *serial_get_thread_team_data(); - pointer_type ptr = + pointer_type ptr = m_result_ptr ? m_result_ptr : pointer_type(data.pool_reduce_local()); - reference_type update = - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , ptr ); + reference_type update = + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), ptr); - this-> template exec< WorkTag >( update ); + this->template exec(update); - Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTagFwd >:: - final( ReducerConditional::select(m_functor , m_reducer) , ptr ); - } + Kokkos::Impl::FunctorFinal::final( + ReducerConditional::select(m_functor, m_reducer), ptr); + } - template< class HostViewType > - ParallelReduce( const FunctorType & arg_functor , - const Policy & arg_policy , - const HostViewType & arg_result_view , - typename std::enable_if< - Kokkos::is_view< HostViewType >::value && - !Kokkos::is_reducer_type::value - ,void*>::type = NULL) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - , m_reducer( InvalidType() ) - , m_result_ptr( arg_result_view.data() ) - { - static_assert( Kokkos::is_view< HostViewType >::value - , "Kokkos::Serial reduce result must be a View" ); - - static_assert( std::is_same< typename HostViewType::memory_space , HostSpace >::value - , "Kokkos::Serial reduce result must be a View in HostSpace" ); - } + template + ParallelReduce( + const FunctorType& arg_functor, const Policy& arg_policy, + const HostViewType& arg_result_view, + typename std::enable_if::value && + !Kokkos::is_reducer_type::value, + void*>::type = NULL) + : m_functor(arg_functor), + m_policy(arg_policy), + m_reducer(InvalidType()), + m_result_ptr(arg_result_view.data()) { + static_assert(Kokkos::is_view::value, + "Kokkos::Serial reduce result must be a View"); + + static_assert( + std::is_same::value, + "Kokkos::Serial reduce result must be a View in HostSpace"); + } - inline - ParallelReduce( const FunctorType & arg_functor - , Policy arg_policy - , const ReducerType& reducer ) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - , m_reducer( reducer ) - , m_result_ptr( reducer.view().data() ) - { - /*static_assert( std::is_same< typename ViewType::memory_space - , Kokkos::HostSpace >::value - , "Reduction result on Kokkos::OpenMP must be a Kokkos::View in HostSpace" );*/ - } + inline ParallelReduce(const FunctorType& arg_functor, Policy arg_policy, + const ReducerType& reducer) + : m_functor(arg_functor), + m_policy(arg_policy), + m_reducer(reducer), + m_result_ptr(reducer.view().data()) { + /*static_assert( std::is_same< typename ViewType::memory_space + , Kokkos::HostSpace >::value + , "Reduction result on Kokkos::OpenMP must be a Kokkos::View in HostSpace" + );*/ + } }; - /*--------------------------------------------------------------------------*/ -template< class FunctorType , class ... Traits > -class ParallelScan< FunctorType - , Kokkos::RangePolicy< Traits ... > - , Kokkos::Serial - > -{ -private: +template +class ParallelScan, + Kokkos::Serial> { + private: + typedef Kokkos::RangePolicy Policy; + typedef typename Policy::work_tag WorkTag; - typedef Kokkos::RangePolicy< Traits ... > Policy ; - typedef typename Policy::work_tag WorkTag ; + typedef FunctorAnalysis + Analysis; - typedef FunctorAnalysis< FunctorPatternInterface::SCAN , Policy , FunctorType > Analysis ; + typedef Kokkos::Impl::FunctorValueInit ValueInit; - typedef Kokkos::Impl::FunctorValueInit< FunctorType , WorkTag > ValueInit ; + typedef typename Analysis::pointer_type pointer_type; + typedef typename Analysis::reference_type reference_type; - typedef typename Analysis::pointer_type pointer_type ; - typedef typename Analysis::reference_type reference_type ; + const FunctorType m_functor; + const Policy m_policy; - const FunctorType m_functor ; - const Policy m_policy ; - - template< class TagType > - inline - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec( reference_type update ) const - { - const typename Policy::member_type e = m_policy.end(); - for ( typename Policy::member_type i = m_policy.begin() ; i < e ; ++i ) { - m_functor( i , update , true ); - } + template + inline typename std::enable_if::value>::type exec( + reference_type update) const { + const typename Policy::member_type e = m_policy.end(); + for (typename Policy::member_type i = m_policy.begin(); i < e; ++i) { + m_functor(i, update, true); } + } - template< class TagType > - inline - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec( reference_type update ) const - { - const TagType t{} ; - const typename Policy::member_type e = m_policy.end(); - for ( typename Policy::member_type i = m_policy.begin() ; i < e ; ++i ) { - m_functor( t , i , update , true ); - } + template + inline typename std::enable_if::value>::type + exec(reference_type update) const { + const TagType t{}; + const typename Policy::member_type e = m_policy.end(); + for (typename Policy::member_type i = m_policy.begin(); i < e; ++i) { + m_functor(t, i, update, true); } + } -public: - - inline - void execute() const - { - const size_t pool_reduce_size = Analysis::value_size( m_functor ); - const size_t team_reduce_size = 0 ; // Never shrinks - const size_t team_shared_size = 0 ; // Never shrinks - const size_t thread_local_size = 0 ; // Never shrinks + public: + inline void execute() const { + const size_t pool_reduce_size = Analysis::value_size(m_functor); + const size_t team_reduce_size = 0; // Never shrinks + const size_t team_shared_size = 0; // Never shrinks + const size_t thread_local_size = 0; // Never shrinks - serial_resize_thread_team_data( pool_reduce_size - , team_reduce_size - , team_shared_size - , thread_local_size ); + serial_resize_thread_team_data(pool_reduce_size, team_reduce_size, + team_shared_size, thread_local_size); - HostThreadTeamData & data = *serial_get_thread_team_data(); + HostThreadTeamData& data = *serial_get_thread_team_data(); - reference_type update = - ValueInit::init( m_functor , pointer_type(data.pool_reduce_local()) ); + reference_type update = + ValueInit::init(m_functor, pointer_type(data.pool_reduce_local())); - this-> template exec< WorkTag >( update ); - } + this->template exec(update); + } - inline - ParallelScan( const FunctorType & arg_functor - , const Policy & arg_policy - ) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - {} + inline ParallelScan(const FunctorType& arg_functor, const Policy& arg_policy) + : m_functor(arg_functor), m_policy(arg_policy) {} }; /*--------------------------------------------------------------------------*/ -template< class FunctorType , class ReturnType, class ... Traits > -class ParallelScanWithTotal< FunctorType - , Kokkos::RangePolicy< Traits ... > - , ReturnType - , Kokkos::Serial - > -{ -private: - - typedef Kokkos::RangePolicy< Traits ... > Policy ; - typedef typename Policy::work_tag WorkTag ; - - typedef FunctorAnalysis< FunctorPatternInterface::SCAN , Policy , FunctorType > Analysis ; - - typedef Kokkos::Impl::FunctorValueInit< FunctorType , WorkTag > ValueInit ; - - typedef typename Analysis::pointer_type pointer_type ; - typedef typename Analysis::reference_type reference_type ; - - const FunctorType m_functor ; - const Policy m_policy ; - ReturnType & m_returnvalue; - - template< class TagType > - inline - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec( reference_type update ) const - { - const typename Policy::member_type e = m_policy.end(); - for ( typename Policy::member_type i = m_policy.begin() ; i < e ; ++i ) { - m_functor( i , update , true ); - } +template +class ParallelScanWithTotal, + ReturnType, Kokkos::Serial> { + private: + typedef Kokkos::RangePolicy Policy; + typedef typename Policy::work_tag WorkTag; + + typedef FunctorAnalysis + Analysis; + + typedef Kokkos::Impl::FunctorValueInit ValueInit; + + typedef typename Analysis::pointer_type pointer_type; + typedef typename Analysis::reference_type reference_type; + + const FunctorType m_functor; + const Policy m_policy; + ReturnType& m_returnvalue; + + template + inline typename std::enable_if::value>::type exec( + reference_type update) const { + const typename Policy::member_type e = m_policy.end(); + for (typename Policy::member_type i = m_policy.begin(); i < e; ++i) { + m_functor(i, update, true); } + } - template< class TagType > - inline - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec( reference_type update ) const - { - const TagType t{} ; - const typename Policy::member_type e = m_policy.end(); - for ( typename Policy::member_type i = m_policy.begin() ; i < e ; ++i ) { - m_functor( t , i , update , true ); - } + template + inline typename std::enable_if::value>::type + exec(reference_type update) const { + const TagType t{}; + const typename Policy::member_type e = m_policy.end(); + for (typename Policy::member_type i = m_policy.begin(); i < e; ++i) { + m_functor(t, i, update, true); } + } -public: - - inline - void execute() - { - const size_t pool_reduce_size = Analysis::value_size( m_functor ); - const size_t team_reduce_size = 0 ; // Never shrinks - const size_t team_shared_size = 0 ; // Never shrinks - const size_t thread_local_size = 0 ; // Never shrinks + public: + inline void execute() { + const size_t pool_reduce_size = Analysis::value_size(m_functor); + const size_t team_reduce_size = 0; // Never shrinks + const size_t team_shared_size = 0; // Never shrinks + const size_t thread_local_size = 0; // Never shrinks - serial_resize_thread_team_data( pool_reduce_size - , team_reduce_size - , team_shared_size - , thread_local_size ); + serial_resize_thread_team_data(pool_reduce_size, team_reduce_size, + team_shared_size, thread_local_size); - HostThreadTeamData & data = *serial_get_thread_team_data(); + HostThreadTeamData& data = *serial_get_thread_team_data(); - reference_type update = - ValueInit::init( m_functor , pointer_type(data.pool_reduce_local()) ); + reference_type update = + ValueInit::init(m_functor, pointer_type(data.pool_reduce_local())); - this-> template exec< WorkTag >( update ); + this->template exec(update); - m_returnvalue = update; - } + m_returnvalue = update; + } - inline - ParallelScanWithTotal( const FunctorType & arg_functor - , const Policy & arg_policy - , ReturnType & arg_returnvalue - ) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - , m_returnvalue( arg_returnvalue ) - {} + inline ParallelScanWithTotal(const FunctorType& arg_functor, + const Policy& arg_policy, + ReturnType& arg_returnvalue) + : m_functor(arg_functor), + m_policy(arg_policy), + m_returnvalue(arg_returnvalue) {} }; -} // namespace Impl -} // namespace Kokkos - +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -815,169 +805,143 @@ public: namespace Kokkos { namespace Impl { -template< class FunctorType , class ... Traits > -class ParallelFor< FunctorType , - Kokkos::MDRangePolicy< Traits ... > , - Kokkos::Serial - > -{ -private: - - typedef Kokkos::MDRangePolicy< Traits ... > MDRangePolicy ; - typedef typename MDRangePolicy::impl_range_policy Policy ; - - typedef typename Kokkos::Impl::HostIterateTile< MDRangePolicy, FunctorType, typename MDRangePolicy::work_tag, void > iterate_type; - - const FunctorType m_functor ; - const MDRangePolicy m_mdr_policy ; - const Policy m_policy ; - - void - exec() const - { - const typename Policy::member_type e = m_policy.end(); - for ( typename Policy::member_type i = m_policy.begin() ; i < e ; ++i ) { - iterate_type( m_mdr_policy, m_functor )( i ); - } +template +class ParallelFor, + Kokkos::Serial> { + private: + typedef Kokkos::MDRangePolicy MDRangePolicy; + typedef typename MDRangePolicy::impl_range_policy Policy; + + typedef typename Kokkos::Impl::HostIterateTile< + MDRangePolicy, FunctorType, typename MDRangePolicy::work_tag, void> + iterate_type; + + const FunctorType m_functor; + const MDRangePolicy m_mdr_policy; + const Policy m_policy; + + void exec() const { + const typename Policy::member_type e = m_policy.end(); + for (typename Policy::member_type i = m_policy.begin(); i < e; ++i) { + iterate_type(m_mdr_policy, m_functor)(i); } + } -public: - - inline - void execute() const - { this->exec(); } + public: + inline void execute() const { this->exec(); } - inline - ParallelFor( const FunctorType & arg_functor - , const MDRangePolicy & arg_policy ) - : m_functor( arg_functor ) - , m_mdr_policy( arg_policy ) - , m_policy( Policy(0, m_mdr_policy.m_num_tiles).set_chunk_size(1) ) - {} + inline ParallelFor(const FunctorType& arg_functor, + const MDRangePolicy& arg_policy) + : m_functor(arg_functor), + m_mdr_policy(arg_policy), + m_policy(Policy(0, m_mdr_policy.m_num_tiles).set_chunk_size(1)) {} }; +template +class ParallelReduce, ReducerType, + Kokkos::Serial> { + private: + typedef Kokkos::MDRangePolicy MDRangePolicy; + typedef typename MDRangePolicy::impl_range_policy Policy; -template< class FunctorType , class ReducerType , class ... Traits > -class ParallelReduce< FunctorType - , Kokkos::MDRangePolicy< Traits ... > - , ReducerType - , Kokkos::Serial - > -{ -private: + typedef typename MDRangePolicy::work_tag WorkTag; - typedef Kokkos::MDRangePolicy< Traits ... > MDRangePolicy ; - typedef typename MDRangePolicy::impl_range_policy Policy ; - - typedef typename MDRangePolicy::work_tag WorkTag ; - - typedef Kokkos::Impl::if_c< std::is_same::value, FunctorType, ReducerType> ReducerConditional; + typedef Kokkos::Impl::if_c::value, + FunctorType, ReducerType> + ReducerConditional; typedef typename ReducerConditional::type ReducerTypeFwd; - typedef typename Kokkos::Impl::if_c< std::is_same::value, WorkTag, void>::type WorkTagFwd; - - typedef FunctorAnalysis< FunctorPatternInterface::REDUCE , MDRangePolicy , FunctorType > Analysis ; - - typedef Kokkos::Impl::FunctorValueInit< ReducerTypeFwd , WorkTagFwd > ValueInit ; - - typedef typename Analysis::pointer_type pointer_type ; - typedef typename Analysis::value_type value_type ; - typedef typename Analysis::reference_type reference_type ; - - - using iterate_type = typename Kokkos::Impl::HostIterateTile< MDRangePolicy - , FunctorType - , WorkTag - , reference_type - >; - - - const FunctorType m_functor ; - const MDRangePolicy m_mdr_policy ; - const Policy m_policy ; - const ReducerType m_reducer ; - const pointer_type m_result_ptr ; - - inline - void - exec( reference_type update ) const - { - const typename Policy::member_type e = m_policy.end(); - for ( typename Policy::member_type i = m_policy.begin() ; i < e ; ++i ) { - iterate_type( m_mdr_policy, m_functor, update )( i ); - } + typedef + typename Kokkos::Impl::if_c::value, + WorkTag, void>::type WorkTagFwd; + + typedef FunctorAnalysis + Analysis; + + typedef Kokkos::Impl::FunctorValueInit ValueInit; + + typedef typename Analysis::pointer_type pointer_type; + typedef typename Analysis::value_type value_type; + typedef typename Analysis::reference_type reference_type; + + using iterate_type = + typename Kokkos::Impl::HostIterateTile; + + const FunctorType m_functor; + const MDRangePolicy m_mdr_policy; + const Policy m_policy; + const ReducerType m_reducer; + const pointer_type m_result_ptr; + + inline void exec(reference_type update) const { + const typename Policy::member_type e = m_policy.end(); + for (typename Policy::member_type i = m_policy.begin(); i < e; ++i) { + iterate_type(m_mdr_policy, m_functor, update)(i); } + } -public: - - inline - void execute() const - { - const size_t pool_reduce_size = - Analysis::value_size( ReducerConditional::select(m_functor , m_reducer) ); - const size_t team_reduce_size = 0 ; // Never shrinks - const size_t team_shared_size = 0 ; // Never shrinks - const size_t thread_local_size = 0 ; // Never shrinks + public: + inline void execute() const { + const size_t pool_reduce_size = + Analysis::value_size(ReducerConditional::select(m_functor, m_reducer)); + const size_t team_reduce_size = 0; // Never shrinks + const size_t team_shared_size = 0; // Never shrinks + const size_t thread_local_size = 0; // Never shrinks - serial_resize_thread_team_data( pool_reduce_size - , team_reduce_size - , team_shared_size - , thread_local_size ); + serial_resize_thread_team_data(pool_reduce_size, team_reduce_size, + team_shared_size, thread_local_size); - HostThreadTeamData & data = *serial_get_thread_team_data(); + HostThreadTeamData& data = *serial_get_thread_team_data(); - pointer_type ptr = + pointer_type ptr = m_result_ptr ? m_result_ptr : pointer_type(data.pool_reduce_local()); - reference_type update = - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , ptr ); + reference_type update = + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), ptr); - this-> exec( update ); + this->exec(update); - Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTagFwd >:: - final( ReducerConditional::select(m_functor , m_reducer) , ptr ); - } + Kokkos::Impl::FunctorFinal::final( + ReducerConditional::select(m_functor, m_reducer), ptr); + } - template< class HostViewType > - ParallelReduce( const FunctorType & arg_functor , - const MDRangePolicy & arg_policy , - const HostViewType & arg_result_view , - typename std::enable_if< - Kokkos::is_view< HostViewType >::value && - !Kokkos::is_reducer_type::value - ,void*>::type = NULL) - : m_functor( arg_functor ) - , m_mdr_policy( arg_policy ) - , m_policy( Policy(0, m_mdr_policy.m_num_tiles).set_chunk_size(1) ) - , m_reducer( InvalidType() ) - , m_result_ptr( arg_result_view.data() ) - { - static_assert( Kokkos::is_view< HostViewType >::value - , "Kokkos::Serial reduce result must be a View" ); - - static_assert( std::is_same< typename HostViewType::memory_space , HostSpace >::value - , "Kokkos::Serial reduce result must be a View in HostSpace" ); - } + template + ParallelReduce( + const FunctorType& arg_functor, const MDRangePolicy& arg_policy, + const HostViewType& arg_result_view, + typename std::enable_if::value && + !Kokkos::is_reducer_type::value, + void*>::type = NULL) + : m_functor(arg_functor), + m_mdr_policy(arg_policy), + m_policy(Policy(0, m_mdr_policy.m_num_tiles).set_chunk_size(1)), + m_reducer(InvalidType()), + m_result_ptr(arg_result_view.data()) { + static_assert(Kokkos::is_view::value, + "Kokkos::Serial reduce result must be a View"); + + static_assert( + std::is_same::value, + "Kokkos::Serial reduce result must be a View in HostSpace"); + } - inline - ParallelReduce( const FunctorType & arg_functor - , MDRangePolicy arg_policy - , const ReducerType& reducer ) - : m_functor( arg_functor ) - , m_mdr_policy( arg_policy ) - , m_policy( Policy(0, m_mdr_policy.m_num_tiles).set_chunk_size(1) ) - , m_reducer( reducer ) - , m_result_ptr( reducer.view().data() ) - { - /*static_assert( std::is_same< typename ViewType::memory_space - , Kokkos::HostSpace >::value - , "Reduction result on Kokkos::OpenMP must be a Kokkos::View in HostSpace" );*/ - } + inline ParallelReduce(const FunctorType& arg_functor, + MDRangePolicy arg_policy, const ReducerType& reducer) + : m_functor(arg_functor), + m_mdr_policy(arg_policy), + m_policy(Policy(0, m_mdr_policy.m_num_tiles).set_chunk_size(1)), + m_reducer(reducer), + m_result_ptr(reducer.view().data()) { + /*static_assert( std::is_same< typename ViewType::memory_space + , Kokkos::HostSpace >::value + , "Reduction result on Kokkos::OpenMP must be a Kokkos::View in HostSpace" + );*/ + } }; - - -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -986,225 +950,193 @@ public: namespace Kokkos { namespace Impl { -template< class FunctorType , class ... Properties > -class ParallelFor< FunctorType - , Kokkos::TeamPolicy< Properties ... > - , Kokkos::Serial - > -{ -private: - +template +class ParallelFor, + Kokkos::Serial> { + private: enum { TEAM_REDUCE_SIZE = 512 }; - typedef TeamPolicyInternal< Kokkos::Serial , Properties ...> Policy ; - typedef typename Policy::member_type Member ; - - const FunctorType m_functor ; - const int m_league ; - const int m_shared ; - - template< class TagType > - inline - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec( HostThreadTeamData & data ) const - { - for ( int ileague = 0 ; ileague < m_league ; ++ileague ) { - m_functor( Member(data,ileague,m_league) ); - } - } + typedef TeamPolicyInternal Policy; + typedef typename Policy::member_type Member; - template< class TagType > - inline - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec( HostThreadTeamData & data ) const - { - const TagType t{} ; - for ( int ileague = 0 ; ileague < m_league ; ++ileague ) { - m_functor( t , Member(data,ileague,m_league) ); - } + const FunctorType m_functor; + const int m_league; + const int m_shared; + + template + inline typename std::enable_if::value>::type exec( + HostThreadTeamData& data) const { + for (int ileague = 0; ileague < m_league; ++ileague) { + m_functor(Member(data, ileague, m_league)); } + } -public: + template + inline typename std::enable_if::value>::type + exec(HostThreadTeamData& data) const { + const TagType t{}; + for (int ileague = 0; ileague < m_league; ++ileague) { + m_functor(t, Member(data, ileague, m_league)); + } + } - inline - void execute() const - { - const size_t pool_reduce_size = 0 ; // Never shrinks - const size_t team_reduce_size = TEAM_REDUCE_SIZE ; - const size_t team_shared_size = m_shared ; - const size_t thread_local_size = 0 ; // Never shrinks + public: + inline void execute() const { + const size_t pool_reduce_size = 0; // Never shrinks + const size_t team_reduce_size = TEAM_REDUCE_SIZE; + const size_t team_shared_size = m_shared; + const size_t thread_local_size = 0; // Never shrinks - serial_resize_thread_team_data( pool_reduce_size - , team_reduce_size - , team_shared_size - , thread_local_size ); + serial_resize_thread_team_data(pool_reduce_size, team_reduce_size, + team_shared_size, thread_local_size); - HostThreadTeamData & data = *serial_get_thread_team_data(); + HostThreadTeamData& data = *serial_get_thread_team_data(); - this->template exec< typename Policy::work_tag >( data ); - } + this->template exec(data); + } - ParallelFor( const FunctorType & arg_functor - , const Policy & arg_policy ) - : m_functor( arg_functor ) - , m_league( arg_policy.league_size() ) - , m_shared( arg_policy.scratch_size(0) + - arg_policy.scratch_size(1) + - FunctorTeamShmemSize< FunctorType >::value( arg_functor , 1 ) ) - { } + ParallelFor(const FunctorType& arg_functor, const Policy& arg_policy) + : m_functor(arg_functor), + m_league(arg_policy.league_size()), + m_shared(arg_policy.scratch_size(0) + arg_policy.scratch_size(1) + + FunctorTeamShmemSize::value(arg_functor, 1)) {} }; /*--------------------------------------------------------------------------*/ -template< class FunctorType , class ReducerType , class ... Properties > -class ParallelReduce< FunctorType - , Kokkos::TeamPolicy< Properties ... > - , ReducerType - , Kokkos::Serial - > -{ -private: - +template +class ParallelReduce, + ReducerType, Kokkos::Serial> { + private: enum { TEAM_REDUCE_SIZE = 512 }; - typedef TeamPolicyInternal< Kokkos::Serial, Properties ... > Policy ; + typedef TeamPolicyInternal Policy; - typedef FunctorAnalysis< FunctorPatternInterface::REDUCE , Policy , FunctorType > Analysis ; + typedef FunctorAnalysis + Analysis; - typedef typename Policy::member_type Member ; - typedef typename Policy::work_tag WorkTag ; + typedef typename Policy::member_type Member; + typedef typename Policy::work_tag WorkTag; - typedef Kokkos::Impl::if_c< std::is_same::value, FunctorType, ReducerType> ReducerConditional; + typedef Kokkos::Impl::if_c::value, + FunctorType, ReducerType> + ReducerConditional; typedef typename ReducerConditional::type ReducerTypeFwd; - typedef typename Kokkos::Impl::if_c< std::is_same::value, WorkTag, void>::type WorkTagFwd; - - typedef Kokkos::Impl::FunctorValueInit< ReducerTypeFwd , WorkTagFwd > ValueInit ; - - typedef typename Analysis::pointer_type pointer_type ; - typedef typename Analysis::reference_type reference_type ; - - const FunctorType m_functor ; - const int m_league ; - const ReducerType m_reducer ; - pointer_type m_result_ptr ; - const int m_shared ; - - template< class TagType > - inline - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec( HostThreadTeamData & data , reference_type update ) const - { - for ( int ileague = 0 ; ileague < m_league ; ++ileague ) { - m_functor( Member(data,ileague,m_league) , update ); - } + typedef + typename Kokkos::Impl::if_c::value, + WorkTag, void>::type WorkTagFwd; + + typedef Kokkos::Impl::FunctorValueInit ValueInit; + + typedef typename Analysis::pointer_type pointer_type; + typedef typename Analysis::reference_type reference_type; + + const FunctorType m_functor; + const int m_league; + const ReducerType m_reducer; + pointer_type m_result_ptr; + const int m_shared; + + template + inline typename std::enable_if::value>::type exec( + HostThreadTeamData& data, reference_type update) const { + for (int ileague = 0; ileague < m_league; ++ileague) { + m_functor(Member(data, ileague, m_league), update); } + } - template< class TagType > - inline - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec( HostThreadTeamData & data , reference_type update ) const - { - const TagType t{} ; + template + inline typename std::enable_if::value>::type + exec(HostThreadTeamData& data, reference_type update) const { + const TagType t{}; - for ( int ileague = 0 ; ileague < m_league ; ++ileague ) { - m_functor( t , Member(data,ileague,m_league) , update ); - } + for (int ileague = 0; ileague < m_league; ++ileague) { + m_functor(t, Member(data, ileague, m_league), update); } + } -public: - - inline - void execute() const - { - const size_t pool_reduce_size = - Analysis::value_size( ReducerConditional::select(m_functor, m_reducer)); - - const size_t team_reduce_size = TEAM_REDUCE_SIZE ; - const size_t team_shared_size = m_shared ; - const size_t thread_local_size = 0 ; // Never shrinks + public: + inline void execute() const { + const size_t pool_reduce_size = + Analysis::value_size(ReducerConditional::select(m_functor, m_reducer)); - serial_resize_thread_team_data( pool_reduce_size - , team_reduce_size - , team_shared_size - , thread_local_size ); + const size_t team_reduce_size = TEAM_REDUCE_SIZE; + const size_t team_shared_size = m_shared; + const size_t thread_local_size = 0; // Never shrinks + serial_resize_thread_team_data(pool_reduce_size, team_reduce_size, + team_shared_size, thread_local_size); - HostThreadTeamData & data = *serial_get_thread_team_data(); + HostThreadTeamData& data = *serial_get_thread_team_data(); - pointer_type ptr = + pointer_type ptr = m_result_ptr ? m_result_ptr : pointer_type(data.pool_reduce_local()); - reference_type update = - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , ptr ); + reference_type update = + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), ptr); - this-> template exec< WorkTag >( data , update ); + this->template exec(data, update); - Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTagFwd >:: - final( ReducerConditional::select(m_functor , m_reducer) , ptr ); - } - - template< class ViewType > - ParallelReduce( const FunctorType & arg_functor - , const Policy & arg_policy - , const ViewType & arg_result , - typename std::enable_if< - Kokkos::is_view< ViewType >::value && - !Kokkos::is_reducer_type::value - ,void*>::type = NULL) - : m_functor( arg_functor ) - , m_league( arg_policy.league_size() ) - , m_reducer( InvalidType() ) - , m_result_ptr( arg_result.data() ) - , m_shared( arg_policy.scratch_size(0) + - arg_policy.scratch_size(1) + - FunctorTeamShmemSize< FunctorType >::value( m_functor , 1 ) ) - { - static_assert( Kokkos::is_view< ViewType >::value - , "Reduction result on Kokkos::Serial must be a Kokkos::View" ); - - static_assert( std::is_same< typename ViewType::memory_space - , Kokkos::HostSpace >::value - , "Reduction result on Kokkos::Serial must be a Kokkos::View in HostSpace" ); - } + Kokkos::Impl::FunctorFinal::final( + ReducerConditional::select(m_functor, m_reducer), ptr); + } - inline - ParallelReduce( const FunctorType & arg_functor - , Policy arg_policy - , const ReducerType& reducer ) - : m_functor( arg_functor ) - , m_league( arg_policy.league_size() ) - , m_reducer( reducer ) - , m_result_ptr( reducer.view().data() ) - , m_shared( arg_policy.scratch_size(0) + - arg_policy.scratch_size(1) + - FunctorTeamShmemSize< FunctorType >::value( arg_functor , 1 ) ) - { - /*static_assert( std::is_same< typename ViewType::memory_space - , Kokkos::HostSpace >::value - , "Reduction result on Kokkos::OpenMP must be a Kokkos::View in HostSpace" );*/ + template + ParallelReduce( + const FunctorType& arg_functor, const Policy& arg_policy, + const ViewType& arg_result, + typename std::enable_if::value && + !Kokkos::is_reducer_type::value, + void*>::type = NULL) + : m_functor(arg_functor), + m_league(arg_policy.league_size()), + m_reducer(InvalidType()), + m_result_ptr(arg_result.data()), + m_shared(arg_policy.scratch_size(0) + arg_policy.scratch_size(1) + + FunctorTeamShmemSize::value(m_functor, 1)) { + static_assert(Kokkos::is_view::value, + "Reduction result on Kokkos::Serial must be a Kokkos::View"); + + static_assert( + std::is_same::value, + "Reduction result on Kokkos::Serial must be a Kokkos::View in " + "HostSpace"); } + inline ParallelReduce(const FunctorType& arg_functor, Policy arg_policy, + const ReducerType& reducer) + : m_functor(arg_functor), + m_league(arg_policy.league_size()), + m_reducer(reducer), + m_result_ptr(reducer.view().data()), + m_shared(arg_policy.scratch_size(0) + arg_policy.scratch_size(1) + + FunctorTeamShmemSize::value(arg_functor, 1)) { + /*static_assert( std::is_same< typename ViewType::memory_space + , Kokkos::HostSpace >::value + , "Reduction result on Kokkos::OpenMP must be a Kokkos::View in HostSpace" + );*/ + } }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ -namespace Kokkos { namespace Experimental { +namespace Kokkos { +namespace Experimental { -template<> -class UniqueToken< Serial, UniqueTokenScope::Instance> -{ -public: +template <> +class UniqueToken { + public: using execution_space = Serial; using size_type = int; /// \brief create object size for concurrency on the given instance /// /// This object should not be shared between instances - UniqueToken( execution_space const& = execution_space() ) noexcept {} + UniqueToken(execution_space const& = execution_space()) noexcept {} /// \brief upper bound for acquired values, i.e. 0 <= value < size() KOKKOS_INLINE_FUNCTION @@ -1212,24 +1144,23 @@ public: /// \brief acquire value such that 0 <= value < size() KOKKOS_INLINE_FUNCTION - int acquire() const noexcept { return 0; } + int acquire() const noexcept { return 0; } /// \brief release a value acquired by generate KOKKOS_INLINE_FUNCTION - void release( int ) const noexcept {} + void release(int) const noexcept {} }; -template<> -class UniqueToken< Serial, UniqueTokenScope::Global> -{ -public: +template <> +class UniqueToken { + public: using execution_space = Serial; using size_type = int; /// \brief create object size for concurrency on the given instance /// /// This object should not be shared between instances - UniqueToken( execution_space const& = execution_space() ) noexcept {} + UniqueToken(execution_space const& = execution_space()) noexcept {} /// \brief upper bound for acquired values, i.e. 0 <= value < size() KOKKOS_INLINE_FUNCTION @@ -1237,17 +1168,17 @@ public: /// \brief acquire value such that 0 <= value < size() KOKKOS_INLINE_FUNCTION - int acquire() const noexcept { return 0; } + int acquire() const noexcept { return 0; } /// \brief release a value acquired by generate KOKKOS_INLINE_FUNCTION - void release( int ) const noexcept {} + void release(int) const noexcept {} }; -}} // namespace Kokkos::Experimental +} // namespace Experimental +} // namespace Kokkos #include -#endif // defined( KOKKOS_ENABLE_SERIAL ) -#endif /* #define KOKKOS_SERIAL_HPP */ - +#endif // defined( KOKKOS_ENABLE_SERIAL ) +#endif /* #define KOKKOS_SERIAL_HPP */ diff --git a/lib/kokkos/core/src/Kokkos_TaskPolicy.hpp b/lib/kokkos/core/src/Kokkos_TaskPolicy.hpp index 00bceec2b5..91e079a0e7 100644 --- a/lib/kokkos/core/src/Kokkos_TaskPolicy.hpp +++ b/lib/kokkos/core/src/Kokkos_TaskPolicy.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -44,4 +45,3 @@ // For backward compatibility: #include - diff --git a/lib/kokkos/core/src/Kokkos_TaskScheduler.hpp b/lib/kokkos/core/src/Kokkos_TaskScheduler.hpp index 1c3d58af08..4a78d6aca1 100644 --- a/lib/kokkos/core/src/Kokkos_TaskScheduler.hpp +++ b/lib/kokkos/core/src/Kokkos_TaskScheduler.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -47,7 +48,7 @@ //---------------------------------------------------------------------------- #include -#if defined( KOKKOS_ENABLE_TASKDAG ) +#if defined(KOKKOS_ENABLE_TASKDAG) #include #include @@ -74,36 +75,33 @@ namespace Impl { template class TaskExec; -} // end namespace Impl - - -template -class BasicTaskScheduler : public Impl::TaskSchedulerBase -{ -public: - - using scheduler_type = BasicTaskScheduler; - using execution_space = ExecSpace; - using queue_type = QueueType; - using memory_space = typename queue_type::memory_space; - using memory_pool = typename queue_type::memory_pool; - using specialization = Impl::TaskQueueSpecialization; - using member_type = typename specialization::member_type; +} // end namespace Impl + +template +class BasicTaskScheduler : public Impl::TaskSchedulerBase { + public: + using scheduler_type = BasicTaskScheduler; + using execution_space = ExecSpace; + using queue_type = QueueType; + using memory_space = typename queue_type::memory_space; + using memory_pool = typename queue_type::memory_pool; + using specialization = Impl::TaskQueueSpecialization; + using member_type = typename specialization::member_type; using team_scheduler_type = BasicTaskScheduler; template - using runnable_task_type = Impl::Task; + using runnable_task_type = + Impl::Task; template using future_type = Kokkos::BasicFuture; template using future_type_for_functor = future_type; -private: - - using track_type = Kokkos::Impl::SharedAllocationTracker ; + private: + using track_type = Kokkos::Impl::SharedAllocationTracker; using task_base = Impl::TaskBase; track_type m_track; - queue_type * m_queue; + queue_type* m_queue; //---------------------------------------- @@ -121,17 +119,12 @@ private: //---------------------------------------- KOKKOS_INLINE_FUNCTION - BasicTaskScheduler( - track_type arg_track, - queue_type* arg_queue - ) - : m_track(std::move(arg_track)), - m_queue(std::move(arg_queue)) - { } + BasicTaskScheduler(track_type arg_track, queue_type* arg_queue) + : m_track(std::move(arg_track)), m_queue(std::move(arg_queue)) {} KOKKOS_INLINE_FUNCTION team_scheduler_type get_team_scheduler(int team_rank) const { - return { m_track, &m_queue->get_team_queue(team_rank) }; + return {m_track, &m_queue->get_team_queue(team_rank)}; } //---------------------------------------- @@ -140,25 +133,23 @@ private: static constexpr task_base* _get_task_ptr(std::nullptr_t) { return nullptr; } template - KOKKOS_INLINE_FUNCTION - static constexpr task_base* _get_task_ptr(future_type&& f) - { + KOKKOS_INLINE_FUNCTION static constexpr task_base* _get_task_ptr( + future_type&& f) { return f.m_task; } - template< int TaskEnum , typename DepTaskType , typename FunctorType > + template KOKKOS_FUNCTION - Kokkos::BasicFuture - _spawn_impl( - DepTaskType* arg_predecessor_task, - TaskPriority arg_priority, - typename task_base::function_type arg_function, - typename task_base::destroy_type arg_destroy, - FunctorType&& arg_functor - ) - { - using functor_future_type = future_type_for_functor::type>; - using task_type = Impl::Task; + Kokkos::BasicFuture + _spawn_impl(DepTaskType* arg_predecessor_task, TaskPriority arg_priority, + typename task_base::function_type arg_function, + typename task_base::destroy_type arg_destroy, + FunctorType&& arg_functor) { + using functor_future_type = + future_type_for_functor::type>; + using task_type = + Impl::Task; //---------------------------------------- // Give single-thread back-ends an opportunity to clear @@ -169,25 +160,25 @@ private: //---------------------------------------- - functor_future_type f ; + functor_future_type f; // Allocate task from memory pool const size_t alloc_size = - m_queue->template spawn_allocation_size< FunctorType >(); + m_queue->template spawn_allocation_size(); void* task_storage = m_queue->allocate(alloc_size); if (task_storage) { - // Placement new construction // Reference count starts at two: // +1 for the matching decrement when task is complete // +1 for the future - f.m_task = new (task_storage) task_type( std::forward(arg_functor) ); + f.m_task = + new (task_storage) task_type(std::forward(arg_functor)); - f.m_task->m_apply = arg_function; - //f.m_task->m_destroy = arg_destroy; + f.m_task->m_apply = arg_function; + // f.m_task->m_destroy = arg_destroy; f.m_task->m_queue = m_queue; f.m_task->m_next = arg_predecessor_task; f.m_task->m_ref_count = 2; @@ -202,81 +193,70 @@ private: // reference count does not need to be incremented for // the assignment. - m_queue->schedule_runnable( f.m_task ); + m_queue->schedule_runnable(f.m_task); // This task may be updated or executed at any moment, // even during the call to 'schedule'. } return f; - } -public: - - + public: KOKKOS_INLINE_FUNCTION BasicTaskScheduler() : m_track(), m_queue(0) {} KOKKOS_INLINE_FUNCTION - BasicTaskScheduler( BasicTaskScheduler && rhs ) noexcept - : m_track(rhs.m_track), // probably should be a move, but this is deprecated code anyway - m_queue(std::move(rhs.m_queue)) - { } + BasicTaskScheduler(BasicTaskScheduler&& rhs) noexcept + : m_track(rhs.m_track), // probably should be a move, but this is + // deprecated code anyway + m_queue(std::move(rhs.m_queue)) {} KOKKOS_INLINE_FUNCTION - BasicTaskScheduler( BasicTaskScheduler const & rhs ) - : m_track(rhs.m_track), - m_queue(rhs.m_queue) - { } + BasicTaskScheduler(BasicTaskScheduler const& rhs) + : m_track(rhs.m_track), m_queue(rhs.m_queue) {} KOKKOS_INLINE_FUNCTION - BasicTaskScheduler& operator=(BasicTaskScheduler&& rhs) noexcept - { - m_track = rhs.m_track; // probably should be a move, but this is deprecated code anyway + BasicTaskScheduler& operator=(BasicTaskScheduler&& rhs) noexcept { + m_track = rhs.m_track; // probably should be a move, but this is deprecated + // code anyway m_queue = std::move(rhs.m_queue); return *this; } KOKKOS_INLINE_FUNCTION - BasicTaskScheduler& operator=(BasicTaskScheduler const& rhs) - { + BasicTaskScheduler& operator=(BasicTaskScheduler const& rhs) { m_track = rhs.m_track; m_queue = rhs.m_queue; return *this; } - explicit BasicTaskScheduler(memory_pool const & arg_memory_pool) noexcept - : m_track(), m_queue(0) - { - typedef Kokkos::Impl::SharedAllocationRecord - < memory_space , typename queue_type::Destroy > - record_type ; + explicit BasicTaskScheduler(memory_pool const& arg_memory_pool) noexcept + : m_track(), m_queue(0) { + typedef Kokkos::Impl::SharedAllocationRecord + record_type; - record_type * record = - record_type::allocate( memory_space() - , "TaskQueue" - , sizeof(queue_type) - ); + record_type* record = + record_type::allocate(memory_space(), "TaskQueue", sizeof(queue_type)); - m_queue = new( record->data() ) queue_type( arg_memory_pool ); + m_queue = new (record->data()) queue_type(arg_memory_pool); - record->m_destroy.m_queue = m_queue ; + record->m_destroy.m_queue = m_queue; - m_track.assign_allocated_record_to_uninitialized( record ); - } + m_track.assign_allocated_record_to_uninitialized(record); + } - BasicTaskScheduler( memory_space const & arg_memory_space - , size_t const mempool_capacity - , unsigned const mempool_min_block_size // = 1u << 6 - , unsigned const mempool_max_block_size // = 1u << 10 - , unsigned const mempool_superblock_size // = 1u << 12 - ) - : BasicTaskScheduler( memory_pool( arg_memory_space - , mempool_capacity - , mempool_min_block_size - , mempool_max_block_size - , mempool_superblock_size ) ) - {} + BasicTaskScheduler(memory_space const& arg_memory_space, + size_t const mempool_capacity, + unsigned const mempool_min_block_size // = 1u << 6 + , + unsigned const mempool_max_block_size // = 1u << 10 + , + unsigned const mempool_superblock_size // = 1u << 12 + ) + : BasicTaskScheduler(memory_pool( + arg_memory_space, mempool_capacity, mempool_min_block_size, + mempool_max_block_size, mempool_superblock_size)) {} //---------------------------------------- @@ -287,104 +267,89 @@ public: } KOKKOS_INLINE_FUNCTION - memory_pool * memory() const noexcept - { return m_queue ? &( m_queue->m_memory ) : (memory_pool*) 0 ; } + memory_pool* memory() const noexcept { + return m_queue ? &(m_queue->m_memory) : (memory_pool*)0; + } //---------------------------------------- /**\brief Allocation size for a spawned task */ - template< typename FunctorType > - KOKKOS_FUNCTION - size_t spawn_allocation_size() const - { return m_queue->template spawn_allocation_size< FunctorType >(); } + template + KOKKOS_FUNCTION size_t spawn_allocation_size() const { + return m_queue->template spawn_allocation_size(); + } /**\brief Allocation size for a when_all aggregate */ KOKKOS_FUNCTION - size_t when_all_allocation_size( int narg ) const - { return m_queue->when_all_allocation_size( narg ); } - + size_t when_all_allocation_size(int narg) const { + return m_queue->when_all_allocation_size(narg); + } //---------------------------------------- template - KOKKOS_FUNCTION static - Kokkos::BasicFuture - spawn( - Impl::TaskPolicyWithScheduler&& arg_policy, - typename task_base::function_type arg_function, - typename task_base::destroy_type arg_destroy, - FunctorType&& arg_functor - ) - { - return std::move(arg_policy.scheduler()).template _spawn_impl( - _get_task_ptr(std::move(arg_policy.predecessor())), - arg_policy.priority(), - arg_function, - arg_destroy, - std::forward(arg_functor) - ); + KOKKOS_FUNCTION static Kokkos::BasicFuture + spawn(Impl::TaskPolicyWithScheduler&& + arg_policy, + typename task_base::function_type arg_function, + typename task_base::destroy_type arg_destroy, + FunctorType&& arg_functor) { + return std::move(arg_policy.scheduler()) + .template _spawn_impl( + _get_task_ptr(std::move(arg_policy.predecessor())), + arg_policy.priority(), arg_function, arg_destroy, + std::forward(arg_functor)); } template KOKKOS_FUNCTION - future_type_for_functor::type> - spawn( - Impl::TaskPolicyWithPredecessor&& arg_policy, - FunctorType&& arg_functor - ) - { + future_type_for_functor::type> + spawn( + Impl::TaskPolicyWithPredecessor&& arg_policy, + FunctorType&& arg_functor) { using task_type = runnable_task_type; typename task_type::function_type const ptr = task_type::apply; typename task_type::destroy_type const dtor = task_type::destroy; return _spawn_impl( - _get_task_ptr(std::move(arg_policy).predecessor()), - arg_policy.priority(), - ptr, dtor, - std::forward(arg_functor) - ); + _get_task_ptr(std::move(arg_policy).predecessor()), + arg_policy.priority(), ptr, dtor, + std::forward(arg_functor)); } - template - KOKKOS_FUNCTION static - void - respawn( - FunctorType* arg_self, - BasicFuture const & arg_dependence, - TaskPriority const & arg_priority - ) { + template + KOKKOS_FUNCTION static void respawn( + FunctorType* arg_self, + BasicFuture const& arg_dependence, + TaskPriority const& arg_priority) { // Precondition: task is in Executing state - using value_type = typename FunctorType::value_type ; - using task_type = Impl::Task; + using value_type = typename FunctorType::value_type; + using task_type = Impl::Task; - task_type * const task = static_cast< task_type * >( arg_self ); + task_type* const task = static_cast(arg_self); task->m_priority = static_cast(arg_priority); - task->add_dependence( arg_dependence.m_task ); + task->add_dependence(arg_dependence.m_task); // Postcondition: task is in Executing-Respawn state } - template< typename FunctorType > - KOKKOS_FUNCTION static - void - respawn( - FunctorType* arg_self, - BasicTaskScheduler const &, - TaskPriority const & arg_priority - ) - { + template + KOKKOS_FUNCTION static void respawn(FunctorType* arg_self, + BasicTaskScheduler const&, + TaskPriority const& arg_priority) { // Precondition: task is in Executing state using value_type = typename FunctorType::value_type; - using task_type = Impl::Task; + using task_type = Impl::Task; - task_type * const task = static_cast< task_type * >( arg_self ); + task_type* const task = static_cast(arg_self); task->m_priority = static_cast(arg_priority); - task->add_dependence( (task_base*) 0 ); + task->add_dependence((task_base*)0); // Postcondition: task is in Executing-Respawn state } @@ -393,162 +358,153 @@ public: /**\brief Return a future that is complete * when all input futures are complete. */ - template - KOKKOS_FUNCTION - BasicFuture< void, scheduler_type > - when_all(BasicFuture const arg[], int narg) - { - - future_type f ; - - if ( narg ) { + template + KOKKOS_FUNCTION BasicFuture when_all( + BasicFuture const arg[], int narg) { + future_type f; + if (narg) { queue_type* q = m_queue; - //BasicTaskScheduler const* scheduler_ptr = nullptr; + // BasicTaskScheduler const* scheduler_ptr = nullptr; - for ( int i = 0 ; i < narg ; ++i ) { - task_base * const t = arg[i].m_task ; - if ( nullptr != t ) { + for (int i = 0; i < narg; ++i) { + task_base* const t = arg[i].m_task; + if (nullptr != t) { // Increment reference count to track subsequent assignment. - Kokkos::atomic_increment( &(t->m_ref_count) ); - if(q != static_cast< queue_type const* >(t->m_queue)) { - Kokkos::abort("Kokkos when_all Futures must be in the same scheduler" ); + Kokkos::atomic_increment(&(t->m_ref_count)); + if (q != static_cast(t->m_queue)) { + Kokkos::abort( + "Kokkos when_all Futures must be in the same scheduler"); } } } - if ( q != 0 ) { // this should probably handle the queue == 0 case, but this is deprecated code anyway - - size_t const alloc_size = q->when_all_allocation_size( narg ); + if (q != 0) { // this should probably handle the queue == 0 case, but + // this is deprecated code anyway - f.m_task = - reinterpret_cast< task_base * >( q->allocate( alloc_size ) ); - //f.m_scheduler = *scheduler_ptr; + size_t const alloc_size = q->when_all_allocation_size(narg); - if ( f.m_task ) { + f.m_task = reinterpret_cast(q->allocate(alloc_size)); + // f.m_scheduler = *scheduler_ptr; + if (f.m_task) { // Reference count starts at two: // +1 to match decrement when task completes // +1 for the future - new( f.m_task ) task_base(); + new (f.m_task) task_base(); - f.m_task->m_queue = q; - f.m_task->m_ref_count = 2 ; + f.m_task->m_queue = q; + f.m_task->m_ref_count = 2; f.m_task->m_alloc_size = static_cast(alloc_size); - f.m_task->m_dep_count = narg ; - f.m_task->m_task_type = task_base::Aggregate ; + f.m_task->m_dep_count = narg; + f.m_task->m_task_type = task_base::Aggregate; // Assign dependences, reference counts were already incremented - task_base * volatile * const dep = - f.m_task->aggregate_dependences(); + task_base* volatile* const dep = f.m_task->aggregate_dependences(); - for ( int i = 0 ; i < narg ; ++i ) { dep[i] = arg[i].m_task ; } + for (int i = 0; i < narg; ++i) { + dep[i] = arg[i].m_task; + } Kokkos::memory_fence(); - q->schedule_aggregate( f.m_task ); + q->schedule_aggregate(f.m_task); // this when_all may be processed at any moment } } } - return f ; + return f; } - template < class F > - KOKKOS_FUNCTION - BasicFuture< void, scheduler_type > - when_all( int narg , F const func ) - { - using input_type = decltype( func(0) ); + template + KOKKOS_FUNCTION BasicFuture when_all(int narg, + F const func) { + using input_type = decltype(func(0)); - static_assert( is_future< input_type >::value - , "Functor must return a Kokkos::Future" ); + static_assert(is_future::value, + "Functor must return a Kokkos::Future"); - future_type f ; + future_type f; - if ( 0 == narg ) return f ; + if (0 == narg) return f; - size_t const alloc_size = m_queue->when_all_allocation_size( narg ); + size_t const alloc_size = m_queue->when_all_allocation_size(narg); - f.m_task = - reinterpret_cast< task_base * >( m_queue->allocate( alloc_size ) ); - - if ( f.m_task ) { - - // Reference count starts at two: - // +1 to match decrement when task completes - // +1 for the future - - new( f.m_task ) task_base(); - //f.m_scheduler = *this; - - //f.m_task->m_scheduler = &f.m_scheduler; - f.m_task->m_queue = m_queue; - f.m_task->m_ref_count = 2 ; - f.m_task->m_alloc_size = static_cast(alloc_size); - f.m_task->m_dep_count = narg ; - f.m_task->m_task_type = task_base::Aggregate ; - //f.m_task->m_apply = nullptr; - //f.m_task->m_destroy = nullptr; - - // Assign dependences, reference counts were already incremented - - task_base * volatile * const dep = - f.m_task->aggregate_dependences(); - - for ( int i = 0 ; i < narg ; ++i ) { - const input_type arg_f = func(i); - if ( 0 != arg_f.m_task ) { - - // Not scheduled, so task scheduler is not yet set - //if ( m_queue != static_cast< BasicTaskScheduler const * >( arg_f.m_task->m_scheduler )->m_queue ) { - // Kokkos::abort("Kokkos when_all Futures must be in the same scheduler" ); - //} - // Increment reference count to track subsequent assignment. - Kokkos::atomic_increment( &(arg_f.m_task->m_ref_count) ); - dep[i] = arg_f.m_task ; - } - } + f.m_task = reinterpret_cast(m_queue->allocate(alloc_size)); - Kokkos::memory_fence(); + if (f.m_task) { + // Reference count starts at two: + // +1 to match decrement when task completes + // +1 for the future + + new (f.m_task) task_base(); + // f.m_scheduler = *this; - m_queue->schedule_aggregate( f.m_task ); - // this when_all may be processed at any moment + // f.m_task->m_scheduler = &f.m_scheduler; + f.m_task->m_queue = m_queue; + f.m_task->m_ref_count = 2; + f.m_task->m_alloc_size = static_cast(alloc_size); + f.m_task->m_dep_count = narg; + f.m_task->m_task_type = task_base::Aggregate; + // f.m_task->m_apply = nullptr; + // f.m_task->m_destroy = nullptr; + + // Assign dependences, reference counts were already incremented + + task_base* volatile* const dep = f.m_task->aggregate_dependences(); + + for (int i = 0; i < narg; ++i) { + const input_type arg_f = func(i); + if (0 != arg_f.m_task) { + // Not scheduled, so task scheduler is not yet set + // if ( m_queue != static_cast< BasicTaskScheduler const * >( + // arg_f.m_task->m_scheduler )->m_queue ) { + // Kokkos::abort("Kokkos when_all Futures must be in the same + // scheduler" ); + //} + // Increment reference count to track subsequent assignment. + Kokkos::atomic_increment(&(arg_f.m_task->m_ref_count)); + dep[i] = arg_f.m_task; + } } - return f ; + + Kokkos::memory_fence(); + + m_queue->schedule_aggregate(f.m_task); + // this when_all may be processed at any moment } + return f; + } //---------------------------------------- KOKKOS_INLINE_FUNCTION - int allocation_capacity() const noexcept - { return m_queue->m_memory.capacity(); } + int allocation_capacity() const noexcept { + return m_queue->m_memory.capacity(); + } KOKKOS_INLINE_FUNCTION - int allocated_task_count() const noexcept - { return m_queue->m_count_alloc ; } + int allocated_task_count() const noexcept { return m_queue->m_count_alloc; } KOKKOS_INLINE_FUNCTION - int allocated_task_count_max() const noexcept - { return m_queue->m_max_alloc ; } + int allocated_task_count_max() const noexcept { return m_queue->m_max_alloc; } KOKKOS_INLINE_FUNCTION - long allocated_task_count_accum() const noexcept - { return m_queue->m_accum_alloc ; } + long allocated_task_count_accum() const noexcept { + return m_queue->m_accum_alloc; + } //---------------------------------------- - template - friend - void wait(Kokkos::BasicTaskScheduler const&); - + template + friend void wait(Kokkos::BasicTaskScheduler const&); }; -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -559,121 +515,77 @@ namespace Kokkos { // Construct a TaskTeam execution policy template -Impl::TaskPolicyWithPredecessor< - Impl::TaskType::TaskTeam, - Kokkos::BasicFuture -> -KOKKOS_INLINE_FUNCTION -TaskTeam( - Kokkos::BasicFuture arg_future, - TaskPriority arg_priority = TaskPriority::Regular -) -{ - return { std::move(arg_future), arg_priority }; +Impl::TaskPolicyWithPredecessor > + KOKKOS_INLINE_FUNCTION + TaskTeam(Kokkos::BasicFuture arg_future, + TaskPriority arg_priority = TaskPriority::Regular) { + return {std::move(arg_future), arg_priority}; } template -Impl::TaskPolicyWithScheduler< - Impl::TaskType::TaskTeam, Scheduler -> -KOKKOS_INLINE_FUNCTION -TaskTeam( - Scheduler arg_scheduler, - typename std::enable_if< - Kokkos::is_scheduler::value, - TaskPriority - >::type arg_priority = TaskPriority::Regular -) -{ - return { std::move(arg_scheduler), arg_priority }; +Impl::TaskPolicyWithScheduler + KOKKOS_INLINE_FUNCTION + TaskTeam(Scheduler arg_scheduler, + typename std::enable_if::value, + TaskPriority>::type arg_priority = + TaskPriority::Regular) { + return {std::move(arg_scheduler), arg_priority}; } -template< - class Scheduler, - class PredecessorFuture -> -Impl::TaskPolicyWithScheduler< - Kokkos::Impl::TaskType::TaskTeam, - Scheduler, - PredecessorFuture -> -KOKKOS_INLINE_FUNCTION -TaskTeam( - Scheduler arg_scheduler, - PredecessorFuture arg_future, - typename std::enable_if< - Kokkos::is_scheduler::value - && Kokkos::is_future::value, - TaskPriority - >::type arg_priority = TaskPriority::Regular -) -{ - static_assert( - std::is_same::value, - "Can't create a task policy from a scheduler and a future from a different scheduler" - ); - - return { std::move(arg_scheduler), std::move(arg_future), arg_priority }; +template +Impl::TaskPolicyWithScheduler + KOKKOS_INLINE_FUNCTION TaskTeam( + Scheduler arg_scheduler, PredecessorFuture arg_future, + typename std::enable_if::value && + Kokkos::is_future::value, + TaskPriority>::type arg_priority = + TaskPriority::Regular) { + static_assert(std::is_same::value, + "Can't create a task policy from a scheduler and a future from " + "a different scheduler"); + + return {std::move(arg_scheduler), std::move(arg_future), arg_priority}; } // Construct a TaskSingle execution policy template -Impl::TaskPolicyWithPredecessor< - Impl::TaskType::TaskSingle, - Kokkos::BasicFuture -> -KOKKOS_INLINE_FUNCTION -TaskSingle( - Kokkos::BasicFuture arg_future, - TaskPriority arg_priority = TaskPriority::Regular -) -{ - return { std::move(arg_future), arg_priority }; +Impl::TaskPolicyWithPredecessor > + KOKKOS_INLINE_FUNCTION + TaskSingle(Kokkos::BasicFuture arg_future, + TaskPriority arg_priority = TaskPriority::Regular) { + return {std::move(arg_future), arg_priority}; } template -Impl::TaskPolicyWithScheduler< - Impl::TaskType::TaskSingle, Scheduler -> -KOKKOS_INLINE_FUNCTION -TaskSingle( - Scheduler arg_scheduler, - typename std::enable_if< - Kokkos::is_scheduler::value, - TaskPriority - >::type arg_priority = TaskPriority::Regular -) -{ - return { std::move(arg_scheduler), arg_priority }; +Impl::TaskPolicyWithScheduler + KOKKOS_INLINE_FUNCTION + TaskSingle(Scheduler arg_scheduler, + typename std::enable_if::value, + TaskPriority>::type arg_priority = + TaskPriority::Regular) { + return {std::move(arg_scheduler), arg_priority}; } -template< - class Scheduler, - class PredecessorFuture -> -Impl::TaskPolicyWithScheduler< - Kokkos::Impl::TaskType::TaskSingle, - Scheduler, - PredecessorFuture -> -KOKKOS_INLINE_FUNCTION -TaskSingle( - Scheduler arg_scheduler, - PredecessorFuture arg_future, - typename std::enable_if< - Kokkos::is_scheduler::value - && Kokkos::is_future::value, - TaskPriority - >::type arg_priority = TaskPriority::Regular -) -{ - static_assert( - std::is_same::value, - "Can't create a task policy from a scheduler and a future from a different scheduler" - ); - - return { std::move(arg_scheduler), std::move(arg_future), arg_priority }; +template +Impl::TaskPolicyWithScheduler + KOKKOS_INLINE_FUNCTION TaskSingle( + Scheduler arg_scheduler, PredecessorFuture arg_future, + typename std::enable_if::value && + Kokkos::is_future::value, + TaskPriority>::type arg_priority = + TaskPriority::Regular) { + static_assert(std::is_same::value, + "Can't create a task policy from a scheduler and a future from " + "a different scheduler"); + + return {std::move(arg_scheduler), std::move(arg_future), arg_priority}; } //---------------------------------------------------------------------------- @@ -684,31 +596,30 @@ TaskSingle( * 2) With scheduler or dependence * 3) High, Normal, or Low priority */ -template -typename Scheduler::template future_type_for_functor::type> -host_spawn( - Impl::TaskPolicyWithScheduler arg_policy, - FunctorType&& arg_functor -) { +template +typename Scheduler::template future_type_for_functor< + typename std::decay::type> +host_spawn(Impl::TaskPolicyWithScheduler + arg_policy, + FunctorType&& arg_functor) { using scheduler_type = Scheduler; using task_type = - typename scheduler_type::template runnable_task_type; + typename scheduler_type::template runnable_task_type; - static_assert( - TaskEnum == Impl::TaskType::TaskTeam || TaskEnum == Impl::TaskType::TaskSingle, - "Kokkos host_spawn requires TaskTeam or TaskSingle" - ); + static_assert(TaskEnum == Impl::TaskType::TaskTeam || + TaskEnum == Impl::TaskType::TaskSingle, + "Kokkos host_spawn requires TaskTeam or TaskSingle"); // May be spawning a Cuda task, must use the specialization // to query on-device function pointer. typename task_type::function_type ptr; typename task_type::destroy_type dtor; - Kokkos::Impl::TaskQueueSpecialization< scheduler_type >:: - template get_function_pointer< task_type >(ptr, dtor); + Kokkos::Impl::TaskQueueSpecialization< + scheduler_type>::template get_function_pointer(ptr, dtor); - return scheduler_type::spawn( - std::move(arg_policy), ptr, dtor, std::forward(arg_functor) - ); + return scheduler_type::spawn(std::move(arg_policy), ptr, dtor, + std::forward(arg_functor)); } /**\brief A task spawns a task with options @@ -717,38 +628,38 @@ host_spawn( * 2) With scheduler or dependence * 3) High, Normal, or Low priority */ -template -typename Scheduler::template future_type_for_functor::type> -KOKKOS_INLINE_FUNCTION -task_spawn( - Impl::TaskPolicyWithScheduler arg_policy, - FunctorType&& arg_functor -) -{ +template +typename Scheduler::template future_type_for_functor< + typename std::decay::type> + KOKKOS_INLINE_FUNCTION + task_spawn(Impl::TaskPolicyWithScheduler + arg_policy, + FunctorType&& arg_functor) { using scheduler_type = Scheduler; using task_type = - typename scheduler_type::template runnable_task_type; + typename scheduler_type::template runnable_task_type; - #if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) && \ - defined( KOKKOS_ENABLE_CUDA ) +#if defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST) && \ + defined(KOKKOS_ENABLE_CUDA) - static_assert( ! std::is_same< Kokkos::Cuda , typename Scheduler::execution_space >::value - , "Error calling Kokkos::task_spawn for Cuda space within Host code" ); + // This doesn't work with clang cuda + // static_assert( + // !std::is_same::value, + // "Error calling Kokkos::task_spawn for Cuda space within Host code"); - #endif +#endif - static_assert( - TaskEnum == Impl::TaskType::TaskTeam || TaskEnum == Impl::TaskType::TaskSingle, - "Kokkos task_spawn requires TaskTeam or TaskSingle" - ); + static_assert(TaskEnum == Impl::TaskType::TaskTeam || + TaskEnum == Impl::TaskType::TaskSingle, + "Kokkos task_spawn requires TaskTeam or TaskSingle"); - typename task_type::function_type const ptr = task_type::apply ; - typename task_type::destroy_type const dtor = task_type::destroy ; + typename task_type::function_type const ptr = task_type::apply; + typename task_type::destroy_type const dtor = task_type::destroy; return scheduler_type::spawn(std::move(arg_policy), ptr, dtor, - std::forward(arg_functor) - ); + std::forward(arg_functor)); } /**\brief A task respawns itself with options @@ -756,29 +667,22 @@ task_spawn( * 1) With scheduler or dependence * 2) High, Normal, or Low priority */ -template< typename FunctorType , typename T > -void -KOKKOS_INLINE_FUNCTION -respawn( FunctorType * arg_self - , T const & arg - , TaskPriority const & arg_priority = TaskPriority::Regular - ) -{ - static_assert( Kokkos::is_future::value || - Kokkos::is_scheduler::value - , "Kokkos respawn argument must be Future or TaskScheduler" ); - - T::scheduler_type::respawn( - arg_self , arg , arg_priority - ); +template +void KOKKOS_INLINE_FUNCTION +respawn(FunctorType* arg_self, T const& arg, + TaskPriority const& arg_priority = TaskPriority::Regular) { + static_assert(Kokkos::is_future::value || Kokkos::is_scheduler::value, + "Kokkos respawn argument must be Future or TaskScheduler"); + + T::scheduler_type::respawn(arg_self, arg, arg_priority); } //---------------------------------------------------------------------------- -//template -//KOKKOS_INLINE_FUNCTION -//BasicFuture -//when_all(BasicFuture const arg[], int narg) +// template +// KOKKOS_INLINE_FUNCTION +// BasicFuture +// when_all(BasicFuture const arg[], int narg) //{ // return BasicFuture::scheduler_type::when_all(arg, narg); //} @@ -786,16 +690,14 @@ respawn( FunctorType * arg_self //---------------------------------------------------------------------------- // Wait for all runnable tasks to complete -template -inline -void wait(BasicTaskScheduler const& scheduler) -{ +template +inline void wait(BasicTaskScheduler const& scheduler) { using scheduler_type = BasicTaskScheduler; scheduler_type::specialization::execute(scheduler); - //scheduler.m_queue->execute(); + // scheduler.m_queue->execute(); } -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -806,4 +708,3 @@ void wait(BasicTaskScheduler const& scheduler) #endif /* #if defined( KOKKOS_ENABLE_TASKDAG ) */ #endif /* #ifndef KOKKOS_TASKSCHEDULER_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_TaskScheduler_fwd.hpp b/lib/kokkos/core/src/Kokkos_TaskScheduler_fwd.hpp index 79d502c729..c5f880775d 100644 --- a/lib/kokkos/core/src/Kokkos_TaskScheduler_fwd.hpp +++ b/lib/kokkos/core/src/Kokkos_TaskScheduler_fwd.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -47,7 +48,7 @@ //---------------------------------------------------------------------------- #include -#if defined( KOKKOS_ENABLE_TASKDAG ) +#if defined(KOKKOS_ENABLE_TASKDAG) #include //---------------------------------------------------------------------------- @@ -65,22 +66,20 @@ class SimpleTaskScheduler; template class BasicTaskScheduler; -template< typename Space > +template struct is_scheduler : public std::false_type {}; -template -struct is_scheduler> : public std::true_type {}; - -template -struct is_scheduler> : public std::true_type {}; +template +struct is_scheduler> : public std::true_type { +}; -enum class TaskPriority : int { - High = 0, - Regular = 1, - Low = 2 +template +struct is_scheduler> : public std::true_type { }; -} // namespace Kokkos +enum class TaskPriority : int { High = 0, Regular = 1, Low = 2 }; + +} // namespace Kokkos //---------------------------------------------------------------------------- @@ -110,140 +109,124 @@ class TaskBase; * : TaskBase< Space , void , void > * { ... }; */ -template< typename Space , typename ResultType , typename FunctorType > +template class Task; class TaskQueueBase; -template< typename Space, typename MemorySpace> +template class TaskQueue; -template< typename ExecSpace, typename MemorySpace> +template class TaskQueueMultiple; -template< - typename ExecSpace, typename MemSpace, typename TaskQueueTraits, - class MemoryPool = Kokkos::MemoryPool> -> +template >> class SingleTaskQueue; -template< typename ExecSpace, typename MemSpace, typename TaskQueueTraits, class MemoryPool> +template class MultipleTaskQueue; struct TaskQueueTraitsLockBased; -template +template struct TaskQueueTraitsChaseLev; -template< typename ResultType > +template struct TaskResult; struct TaskSchedulerBase; template -struct default_tasking_memory_space_for_execution_space -{ +struct default_tasking_memory_space_for_execution_space { using type = typename ExecSpace::memory_space; }; -#if defined( KOKKOS_ENABLE_CUDA ) +#if defined(KOKKOS_ENABLE_CUDA) template <> -struct default_tasking_memory_space_for_execution_space -{ +struct default_tasking_memory_space_for_execution_space { using type = Kokkos::CudaUVMSpace; }; #endif template using default_tasking_memory_space_for_execution_space_t = - typename default_tasking_memory_space_for_execution_space::type; + typename default_tasking_memory_space_for_execution_space::type; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- namespace Kokkos { -template< typename Space > +template using DeprecatedTaskScheduler = BasicTaskScheduler< - Space, - Impl::TaskQueue> ->; + Space, + Impl::TaskQueue< + Space, + Impl::default_tasking_memory_space_for_execution_space_t>>; -template< typename Space > +template using DeprecatedTaskSchedulerMultiple = BasicTaskScheduler< - Space, - Impl::TaskQueueMultiple> ->; + Space, + Impl::TaskQueueMultiple< + Space, + Impl::default_tasking_memory_space_for_execution_space_t>>; -template< typename Space > +template using TaskScheduler = SimpleTaskScheduler< - Space, - Impl::SingleTaskQueue< Space, - Impl::default_tasking_memory_space_for_execution_space_t, - Impl::TaskQueueTraitsLockBased - > ->; + Impl::SingleTaskQueue< + Space, Impl::default_tasking_memory_space_for_execution_space_t, + Impl::TaskQueueTraitsLockBased>>; -template< typename Space > +template using TaskSchedulerMultiple = SimpleTaskScheduler< - Space, - Impl::MultipleTaskQueue< Space, - Impl::default_tasking_memory_space_for_execution_space_t, - Impl::TaskQueueTraitsLockBased, - Kokkos::MemoryPool< - Kokkos::Device< - Space, - Impl::default_tasking_memory_space_for_execution_space_t - > - > - > ->; - -template< typename Space > + Impl::MultipleTaskQueue< + Space, Impl::default_tasking_memory_space_for_execution_space_t, + Impl::TaskQueueTraitsLockBased, + Kokkos::MemoryPool>>>>; + +template using ChaseLevTaskScheduler = SimpleTaskScheduler< - Space, - Impl::MultipleTaskQueue< Space, - Impl::default_tasking_memory_space_for_execution_space_t, - Impl::TaskQueueTraitsChaseLev<>, - Kokkos::MemoryPool< - Kokkos::Device< - Space, - Impl::default_tasking_memory_space_for_execution_space_t - > - > - > ->; - -template + Impl::MultipleTaskQueue< + Space, Impl::default_tasking_memory_space_for_execution_space_t, + Impl::TaskQueueTraitsChaseLev<>, + Kokkos::MemoryPool>>>>; + +template void wait(BasicTaskScheduler const&); namespace Impl { -struct TaskSchedulerBase { }; +struct TaskSchedulerBase {}; -class TaskQueueBase { }; +class TaskQueueBase {}; -template -class TaskQueueSpecializationConstrained { }; +template +class TaskQueueSpecializationConstrained {}; template -struct TaskQueueSpecialization : TaskQueueSpecializationConstrained { }; +struct TaskQueueSpecialization : TaskQueueSpecializationConstrained { +}; template struct TaskPolicyData; +} // end namespace Impl -} // end namespace Impl - -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- #endif /* #if defined( KOKKOS_ENABLE_TASKDAG ) */ #endif /* #ifndef KOKKOS_TASKSCHEDULER_FWD_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_Threads.hpp b/lib/kokkos/core/src/Kokkos_Threads.hpp index 03dab1acaf..d44042b062 100644 --- a/lib/kokkos/core/src/Kokkos_Threads.hpp +++ b/lib/kokkos/core/src/Kokkos_Threads.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,7 +46,7 @@ #define KOKKOS_THREADS_HPP #include -#if defined( KOKKOS_ENABLE_THREADS ) +#if defined(KOKKOS_ENABLE_THREADS) #include @@ -61,9 +62,9 @@ namespace Kokkos { namespace Impl { -class ThreadsExec ; -} // namespace Impl -} // namespace Kokkos +class ThreadsExec; +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ @@ -71,21 +72,20 @@ namespace Kokkos { /** \brief Execution space for a pool of Pthreads or C11 threads on a CPU. */ class Threads { -public: + public: //! \name Type declarations that all Kokkos devices must provide. //@{ //! Tag this class as a kokkos execution space - typedef Threads execution_space ; - typedef Kokkos::HostSpace memory_space ; + typedef Threads execution_space; + typedef Kokkos::HostSpace memory_space; //! This execution space preferred device_type - typedef Kokkos::Device device_type; + typedef Kokkos::Device device_type; - typedef Kokkos::LayoutRight array_layout ; - typedef memory_space::size_type size_type ; - - typedef ScratchMemorySpace< Threads > scratch_memory_space ; + typedef Kokkos::LayoutRight array_layout; + typedef memory_space::size_type size_type; + typedef ScratchMemorySpace scratch_memory_space; //@} /*------------------------------------------------------------------------*/ @@ -97,7 +97,7 @@ public: static int in_parallel(); /// \brief Print configuration information to the given output stream. - static void print_configuration( std::ostream & , const bool detail = false ); + static void print_configuration(std::ostream&, const bool detail = false); /// \brief Wait until all dispatched functors complete. /// @@ -107,11 +107,11 @@ public: /// device have completed. static void impl_static_fence(); - #ifdef KOKKOS_ENABLE_DEPRECATED_CODE +#ifdef KOKKOS_ENABLE_DEPRECATED_CODE static void fence(); - #else +#else void fence() const; - #endif +#endif /** \brief Return the maximum amount of concurrency. */ static int concurrency(); @@ -123,26 +123,28 @@ public: static void finalize(); - static void initialize( unsigned threads_count = 0 , - unsigned use_numa_count = 0 , - unsigned use_cores_per_numa = 0 , - bool allow_asynchronous_threadpool = false ); + static void initialize(unsigned threads_count = 0, + unsigned use_numa_count = 0, + unsigned use_cores_per_numa = 0, + bool allow_asynchronous_threadpool = false); static int is_initialized(); - static Threads & instance( int = 0 ); + static Threads& instance(int = 0); //---------------------------------------- - static int thread_pool_size( int depth = 0 ); -#if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) + static int thread_pool_size(int depth = 0); +#if defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST) static int thread_pool_rank(); #else - KOKKOS_INLINE_FUNCTION static int thread_pool_rank() { return 0 ; } + KOKKOS_INLINE_FUNCTION static int thread_pool_rank() { return 0; } #endif inline static unsigned max_hardware_threads() { return thread_pool_size(0); } - KOKKOS_INLINE_FUNCTION static unsigned hardware_thread_id() { return thread_pool_rank(); } + KOKKOS_INLINE_FUNCTION static unsigned hardware_thread_id() { + return thread_pool_rank(); + } #else /// \brief Free any resources being consumed by the device. /// @@ -172,26 +174,30 @@ public: * If the 'use_' arguments are not supplied the hwloc is queried * to use all available cores. */ - static void impl_initialize( unsigned threads_count = 0 , - unsigned use_numa_count = 0 , - unsigned use_cores_per_numa = 0 , - bool allow_asynchronous_threadpool = false ); + static void impl_initialize(unsigned threads_count = 0, + unsigned use_numa_count = 0, + unsigned use_cores_per_numa = 0, + bool allow_asynchronous_threadpool = false); static int impl_is_initialized(); - static Threads & impl_instance( int = 0 ); + static Threads& impl_instance(int = 0); //---------------------------------------- - static int impl_thread_pool_size( int depth = 0 ); -#if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) + static int impl_thread_pool_size(int depth = 0); +#if defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST) static int impl_thread_pool_rank(); #else - KOKKOS_INLINE_FUNCTION static int impl_thread_pool_rank() { return 0 ; } + KOKKOS_INLINE_FUNCTION static int impl_thread_pool_rank() { return 0; } #endif - inline static unsigned impl_max_hardware_threads() { return impl_thread_pool_size(0); } - KOKKOS_INLINE_FUNCTION static unsigned impl_hardware_thread_id() { return impl_thread_pool_rank(); } + inline static unsigned impl_max_hardware_threads() { + return impl_thread_pool_size(0); + } + KOKKOS_INLINE_FUNCTION static unsigned impl_hardware_thread_id() { + return impl_thread_pool_rank(); + } #endif static const char* name(); @@ -199,37 +205,31 @@ public: //---------------------------------------- }; -} // namespace Kokkos +} // namespace Kokkos /*--------------------------------------------------------------------------*/ namespace Kokkos { namespace Impl { -template<> -struct MemorySpaceAccess - < Kokkos::Threads::memory_space - , Kokkos::Threads::scratch_memory_space - > -{ +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = true }; - enum { deepcopy = false }; + enum { deepcopy = false }; }; -template<> -struct VerifyExecutionCanAccessMemorySpace - < Kokkos::Threads::memory_space - , Kokkos::Threads::scratch_memory_space - > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace< + Kokkos::Threads::memory_space, Kokkos::Threads::scratch_memory_space> { enum { value = true }; - inline static void verify( void ) { } - inline static void verify( const void * ) { } + inline static void verify(void) {} + inline static void verify(const void*) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ @@ -246,4 +246,3 @@ struct VerifyExecutionCanAccessMemorySpace #endif /* #if defined( KOKKOS_ENABLE_THREADS ) */ #endif /* #define KOKKOS_THREADS_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_Timer.hpp b/lib/kokkos/core/src/Kokkos_Timer.hpp index eb869fd1b0..117f097f66 100644 --- a/lib/kokkos/core/src/Kokkos_Timer.hpp +++ b/lib/kokkos/core/src/Kokkos_Timer.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -51,33 +52,27 @@ namespace Kokkos { /** \brief Time since construction */ class Timer { -private: + private: std::chrono::high_resolution_clock::time_point m_old; - Timer( const Timer & ); - Timer & operator = ( const Timer & ); -public: + Timer(const Timer&); + Timer& operator=(const Timer&); - inline - void reset() { - m_old = std::chrono::high_resolution_clock::now(); - } + public: + inline void reset() { m_old = std::chrono::high_resolution_clock::now(); } - inline - ~Timer() {} + inline ~Timer() {} - inline - Timer() { reset(); } + inline Timer() { reset(); } - inline - double seconds() const - { + inline double seconds() const { std::chrono::high_resolution_clock::time_point m_new = std::chrono::high_resolution_clock::now(); - return std::chrono::duration_cast>(m_new - m_old).count(); + return std::chrono::duration_cast>(m_new - + m_old) + .count(); } }; -} // namespace Kokkos +} // namespace Kokkos #endif /* #ifndef KOKKOS_TIMER_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_UniqueToken.hpp b/lib/kokkos/core/src/Kokkos_UniqueToken.hpp index d89542631d..523ccad948 100644 --- a/lib/kokkos/core/src/Kokkos_UniqueToken.hpp +++ b/lib/kokkos/core/src/Kokkos_UniqueToken.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -46,43 +47,42 @@ #include -namespace Kokkos { namespace Experimental { +namespace Kokkos { +namespace Experimental { -enum class UniqueTokenScope : int -{ - Instance, - Global -}; +enum class UniqueTokenScope : int { Instance, Global }; -/// \brief class to generate unique ids base on the required amount of concurrency +/// \brief class to generate unique ids base on the required amount of +/// concurrency /// /// This object should behave like a ref-counted object, so that when the last /// instance is destroy resources are free if needed -template -class UniqueToken -{ -public: +template +class UniqueToken { + public: using execution_space = ExecutionSpace; using size_type = typename execution_space::size_type; /// \brief create object size for concurrency on the given instance /// /// This object should not be shared between instances - UniqueToken( execution_space const& = execution_space() ); + UniqueToken(execution_space const& = execution_space()); /// \brief upper bound for acquired values, i.e. 0 <= value < size() KOKKOS_INLINE_FUNCTION - size_type size() const ; + size_type size() const; /// \brief acquire value such that 0 <= value < size() KOKKOS_INLINE_FUNCTION - size_type acquire() const ; + size_type acquire() const; /// \brief release a value acquired by generate KOKKOS_INLINE_FUNCTION - void release( size_type ) const ; + void release(size_type) const; }; -}} // namespace Kokkos::Experimental +} // namespace Experimental +} // namespace Kokkos -#endif //KOKKOS_UNIQUE_TOKEN_HPP +#endif // KOKKOS_UNIQUE_TOKEN_HPP diff --git a/lib/kokkos/core/src/Kokkos_Vectorization.hpp b/lib/kokkos/core/src/Kokkos_Vectorization.hpp index f5b6cad4b7..2604538b1c 100644 --- a/lib/kokkos/core/src/Kokkos_Vectorization.hpp +++ b/lib/kokkos/core/src/Kokkos_Vectorization.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -46,9 +47,8 @@ #ifndef KOKKOS_VECTORIZATION_HPP #define KOKKOS_VECTORIZATION_HPP -#if defined( KOKKOS_ENABLE_CUDA ) +#if defined(KOKKOS_ENABLE_CUDA) #include #endif #endif - diff --git a/lib/kokkos/core/src/Kokkos_View.hpp b/lib/kokkos/core/src/Kokkos_View.hpp index 3fe8e6f067..6610bb842b 100644 --- a/lib/kokkos/core/src/Kokkos_View.hpp +++ b/lib/kokkos/core/src/Kokkos_View.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -64,122 +65,88 @@ namespace Kokkos { namespace Impl { -template< class DataType > -struct ViewArrayAnalysis ; +template +struct ViewArrayAnalysis; -template< class DataType , class ArrayLayout - , typename ValueType = - typename ViewArrayAnalysis< DataType >::non_const_value_type - > -struct ViewDataAnalysis ; +template ::non_const_value_type> +struct ViewDataAnalysis; -template< class , class ... > +template class ViewMapping { - public: + public: enum { is_assignable_data_type = false }; enum { is_assignable = false }; }; - - template -KOKKOS_INLINE_FUNCTION -std::size_t count_valid_integers(const IntType i0, - const IntType i1, - const IntType i2, - const IntType i3, - const IntType i4, - const IntType i5, - const IntType i6, - const IntType i7 ){ - static_assert(std::is_integral::value, "count_valid_integers() must have integer arguments."); - - return ( i0 !=KOKKOS_INVALID_INDEX ) + ( i1 !=KOKKOS_INVALID_INDEX ) + ( i2 !=KOKKOS_INVALID_INDEX ) + - ( i3 !=KOKKOS_INVALID_INDEX ) + ( i4 !=KOKKOS_INVALID_INDEX ) + ( i5 !=KOKKOS_INVALID_INDEX ) + - ( i6 !=KOKKOS_INVALID_INDEX ) + ( i7 !=KOKKOS_INVALID_INDEX ); - - +KOKKOS_INLINE_FUNCTION std::size_t count_valid_integers( + const IntType i0, const IntType i1, const IntType i2, const IntType i3, + const IntType i4, const IntType i5, const IntType i6, const IntType i7) { + static_assert(std::is_integral::value, + "count_valid_integers() must have integer arguments."); + + return (i0 != KOKKOS_INVALID_INDEX) + (i1 != KOKKOS_INVALID_INDEX) + + (i2 != KOKKOS_INVALID_INDEX) + (i3 != KOKKOS_INVALID_INDEX) + + (i4 != KOKKOS_INVALID_INDEX) + (i5 != KOKKOS_INVALID_INDEX) + + (i6 != KOKKOS_INVALID_INDEX) + (i7 != KOKKOS_INVALID_INDEX); } #ifndef KOKKOS_ENABLE_DEPRECATED_CODE KOKKOS_INLINE_FUNCTION -void runtime_check_rank_device(const size_t dyn_rank, - const bool is_void_spec, - const size_t i0, - const size_t i1, - const size_t i2, - const size_t i3, - const size_t i4, - const size_t i5, - const size_t i6, - const size_t i7 ){ - - if ( is_void_spec ) { - const size_t num_passed_args = count_valid_integers(i0, i1, i2, i3, - i4, i5, i6, i7); - - if ( num_passed_args != dyn_rank && is_void_spec ) { - - Kokkos::abort("Number of arguments passed to Kokkos::View() constructor must match the dynamic rank of the view.") ; - +void runtime_check_rank_device(const size_t dyn_rank, const bool is_void_spec, + const size_t i0, const size_t i1, + const size_t i2, const size_t i3, + const size_t i4, const size_t i5, + const size_t i6, const size_t i7) { + if (is_void_spec) { + const size_t num_passed_args = + count_valid_integers(i0, i1, i2, i3, i4, i5, i6, i7); + + if (num_passed_args != dyn_rank && is_void_spec) { + Kokkos::abort( + "Number of arguments passed to Kokkos::View() constructor must match " + "the dynamic rank of the view."); } } } #else KOKKOS_INLINE_FUNCTION -void runtime_check_rank_device(const size_t , - const bool , - const size_t , - const size_t , - const size_t , - const size_t , - const size_t , - const size_t , - const size_t , - const size_t ){ - -} +void runtime_check_rank_device(const size_t, const bool, const size_t, + const size_t, const size_t, const size_t, + const size_t, const size_t, const size_t, + const size_t) {} #endif #ifdef KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST #ifndef KOKKOS_ENABLE_DEPRECATED_CODE KOKKOS_INLINE_FUNCTION -void runtime_check_rank_host(const size_t dyn_rank, - const bool is_void_spec, - const size_t i0, - const size_t i1, - const size_t i2, - const size_t i3, - const size_t i4, - const size_t i5, - const size_t i6, - const size_t i7, const std::string & label ){ - - - if ( is_void_spec ) { - const size_t num_passed_args = count_valid_integers(i0, i1, i2, i3, - i4, i5, i6, i7); - - if ( num_passed_args != dyn_rank ) { - - const std::string message = "Constructor for Kokkos View '" + label + "' has mismatched number of arguments. Number of arguments = " - + std::to_string(num_passed_args) + " but dynamic rank = " + std::to_string(dyn_rank) + " \n"; - Kokkos::abort(message.c_str()) ; +void runtime_check_rank_host(const size_t dyn_rank, const bool is_void_spec, + const size_t i0, const size_t i1, const size_t i2, + const size_t i3, const size_t i4, const size_t i5, + const size_t i6, const size_t i7, + const std::string& label) { + if (is_void_spec) { + const size_t num_passed_args = + count_valid_integers(i0, i1, i2, i3, i4, i5, i6, i7); + + if (num_passed_args != dyn_rank) { + const std::string message = + "Constructor for Kokkos View '" + label + + "' has mismatched number of arguments. Number of arguments = " + + std::to_string(num_passed_args) + + " but dynamic rank = " + std::to_string(dyn_rank) + " \n"; + Kokkos::abort(message.c_str()); } } } #else KOKKOS_INLINE_FUNCTION -void runtime_check_rank_host(const size_t , - const bool , - const size_t , - const size_t , - const size_t , - const size_t , - const size_t , - const size_t , - const size_t , - const size_t , const std::string &){} +void runtime_check_rank_host(const size_t, const bool, const size_t, + const size_t, const size_t, const size_t, + const size_t, const size_t, const size_t, + const size_t, const std::string&) {} #endif #endif @@ -189,10 +156,10 @@ void runtime_check_rank_host(const size_t , // Class to provide a uniform type namespace Kokkos { namespace Impl { - template< class ViewType , int Traits = 0 > - struct ViewUniformType; -} +template +struct ViewUniformType; } +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -216,183 +183,183 @@ namespace Kokkos { * - View< DataType , MemoryTraits > */ -template< class DataType , class ... Properties > -struct ViewTraits ; - -template<> -struct ViewTraits< void > -{ - typedef void execution_space ; - typedef void memory_space ; - typedef void HostMirrorSpace ; - typedef void array_layout ; - typedef void memory_traits ; - typedef void specialize ; +template +struct ViewTraits; + +template <> +struct ViewTraits { + typedef void execution_space; + typedef void memory_space; + typedef void HostMirrorSpace; + typedef void array_layout; + typedef void memory_traits; + typedef void specialize; }; -template< class ... Prop > -struct ViewTraits< void , void , Prop ... > -{ +template +struct ViewTraits { // Ignore an extraneous 'void' - typedef typename ViewTraits::execution_space execution_space ; - typedef typename ViewTraits::memory_space memory_space ; - typedef typename ViewTraits::HostMirrorSpace HostMirrorSpace ; - typedef typename ViewTraits::array_layout array_layout ; - typedef typename ViewTraits::memory_traits memory_traits ; - typedef typename ViewTraits::specialize specialize ; + typedef typename ViewTraits::execution_space execution_space; + typedef typename ViewTraits::memory_space memory_space; + typedef typename ViewTraits::HostMirrorSpace HostMirrorSpace; + typedef typename ViewTraits::array_layout array_layout; + typedef typename ViewTraits::memory_traits memory_traits; + typedef typename ViewTraits::specialize specialize; }; -template< class ArrayLayout , class ... Prop > -struct ViewTraits< typename std::enable_if< Kokkos::Impl::is_array_layout::value >::type , ArrayLayout , Prop ... > -{ +template +struct ViewTraits::value>::type, + ArrayLayout, Prop...> { // Specify layout, keep subsequent space and memory traits arguments - typedef typename ViewTraits::execution_space execution_space ; - typedef typename ViewTraits::memory_space memory_space ; - typedef typename ViewTraits::HostMirrorSpace HostMirrorSpace ; - typedef ArrayLayout array_layout ; - typedef typename ViewTraits::memory_traits memory_traits ; - typedef typename ViewTraits::specialize specialize ; + typedef typename ViewTraits::execution_space execution_space; + typedef typename ViewTraits::memory_space memory_space; + typedef typename ViewTraits::HostMirrorSpace HostMirrorSpace; + typedef ArrayLayout array_layout; + typedef typename ViewTraits::memory_traits memory_traits; + typedef typename ViewTraits::specialize specialize; }; -template< class Space , class ... Prop > -struct ViewTraits< typename std::enable_if< Kokkos::Impl::is_space::value >::type , Space , Prop ... > -{ +template +struct ViewTraits< + typename std::enable_if::value>::type, Space, + Prop...> { // Specify Space, memory traits should be the only subsequent argument. - static_assert( std::is_same< typename ViewTraits::execution_space , void >::value && - std::is_same< typename ViewTraits::memory_space , void >::value && - std::is_same< typename ViewTraits::HostMirrorSpace , void >::value && - std::is_same< typename ViewTraits::array_layout , void >::value - , "Only one View Execution or Memory Space template argument" ); - - typedef typename Space::execution_space execution_space ; - typedef typename Space::memory_space memory_space ; - typedef typename Kokkos::Impl::HostMirror< Space >::Space HostMirrorSpace ; - typedef typename execution_space::array_layout array_layout ; - typedef typename ViewTraits::memory_traits memory_traits ; - typedef typename ViewTraits::specialize specialize ; + static_assert( + std::is_same::execution_space, + void>::value && + std::is_same::memory_space, + void>::value && + std::is_same::HostMirrorSpace, + void>::value && + std::is_same::array_layout, + void>::value, + "Only one View Execution or Memory Space template argument"); + + typedef typename Space::execution_space execution_space; + typedef typename Space::memory_space memory_space; + typedef typename Kokkos::Impl::HostMirror::Space::memory_space + HostMirrorSpace; + typedef typename execution_space::array_layout array_layout; + typedef typename ViewTraits::memory_traits memory_traits; + typedef typename ViewTraits::specialize specialize; }; -template< class MemoryTraits , class ... Prop > -struct ViewTraits< typename std::enable_if< Kokkos::Impl::is_memory_traits::value >::type , MemoryTraits , Prop ... > -{ +template +struct ViewTraits::value>::type, + MemoryTraits, Prop...> { // Specify memory trait, should not be any subsequent arguments - static_assert( std::is_same< typename ViewTraits::execution_space , void >::value && - std::is_same< typename ViewTraits::memory_space , void >::value && - std::is_same< typename ViewTraits::array_layout , void >::value && - std::is_same< typename ViewTraits::memory_traits , void >::value - , "MemoryTrait is the final optional template argument for a View" ); - - typedef void execution_space ; - typedef void memory_space ; - typedef void HostMirrorSpace ; - typedef void array_layout ; - typedef MemoryTraits memory_traits ; - typedef void specialize ; + static_assert( + std::is_same::execution_space, + void>::value && + std::is_same::memory_space, + void>::value && + std::is_same::array_layout, + void>::value && + std::is_same::memory_traits, + void>::value, + "MemoryTrait is the final optional template argument for a View"); + + typedef void execution_space; + typedef void memory_space; + typedef void HostMirrorSpace; + typedef void array_layout; + typedef MemoryTraits memory_traits; + typedef void specialize; }; - -template< class DataType , class ... Properties > +template struct ViewTraits { -private: - + private: // Unpack the properties arguments - typedef ViewTraits< void , Properties ... > prop ; - - typedef typename - std::conditional< ! std::is_same< typename prop::execution_space , void >::value - , typename prop::execution_space - , Kokkos::DefaultExecutionSpace - >::type - ExecutionSpace ; - - typedef typename - std::conditional< ! std::is_same< typename prop::memory_space , void >::value - , typename prop::memory_space - , typename ExecutionSpace::memory_space - >::type - MemorySpace ; - - typedef typename - std::conditional< ! std::is_same< typename prop::array_layout , void >::value - , typename prop::array_layout - , typename ExecutionSpace::array_layout - >::type - ArrayLayout ; - - typedef typename - std::conditional - < ! std::is_same< typename prop::HostMirrorSpace , void >::value - , typename prop::HostMirrorSpace - , typename Kokkos::Impl::HostMirror< ExecutionSpace >::Space - >::type - HostMirrorSpace ; - - typedef typename - std::conditional< ! std::is_same< typename prop::memory_traits , void >::value - , typename prop::memory_traits - , typename Kokkos::MemoryManaged - >::type - MemoryTraits ; + typedef ViewTraits prop; + + typedef typename std::conditional< + !std::is_same::value, + typename prop::execution_space, Kokkos::DefaultExecutionSpace>::type + ExecutionSpace; + + typedef typename std::conditional< + !std::is_same::value, + typename prop::memory_space, typename ExecutionSpace::memory_space>::type + MemorySpace; + + typedef typename std::conditional< + !std::is_same::value, + typename prop::array_layout, typename ExecutionSpace::array_layout>::type + ArrayLayout; + + typedef typename std::conditional< + !std::is_same::value, + typename prop::HostMirrorSpace, + typename Kokkos::Impl::HostMirror::Space>::type + HostMirrorSpace; + + typedef typename std::conditional< + !std::is_same::value, + typename prop::memory_traits, typename Kokkos::MemoryManaged>::type + MemoryTraits; // Analyze data type's properties, // May be specialized based upon the layout and value type - typedef Kokkos::Impl::ViewDataAnalysis< DataType , ArrayLayout > data_analysis ; - -public: + typedef Kokkos::Impl::ViewDataAnalysis data_analysis; + public: //------------------------------------ // Data type traits: - typedef typename data_analysis::type data_type ; - typedef typename data_analysis::const_type const_data_type ; - typedef typename data_analysis::non_const_type non_const_data_type ; + typedef typename data_analysis::type data_type; + typedef typename data_analysis::const_type const_data_type; + typedef typename data_analysis::non_const_type non_const_data_type; //------------------------------------ // Compatible array of trivial type traits: - typedef typename data_analysis::scalar_array_type scalar_array_type ; - typedef typename data_analysis::const_scalar_array_type const_scalar_array_type ; - typedef typename data_analysis::non_const_scalar_array_type non_const_scalar_array_type ; + typedef typename data_analysis::scalar_array_type scalar_array_type; + typedef + typename data_analysis::const_scalar_array_type const_scalar_array_type; + typedef typename data_analysis::non_const_scalar_array_type + non_const_scalar_array_type; //------------------------------------ // Value type traits: - typedef typename data_analysis::value_type value_type ; - typedef typename data_analysis::const_value_type const_value_type ; - typedef typename data_analysis::non_const_value_type non_const_value_type ; + typedef typename data_analysis::value_type value_type; + typedef typename data_analysis::const_value_type const_value_type; + typedef typename data_analysis::non_const_value_type non_const_value_type; //------------------------------------ // Mapping traits: - typedef ArrayLayout array_layout ; - typedef typename data_analysis::dimension dimension ; + typedef ArrayLayout array_layout; + typedef typename data_analysis::dimension dimension; typedef typename std::conditional< - std::is_same::value - ,typename prop::specialize - ,typename data_analysis::specialize>::type - specialize ; /* mapping specialization tag */ + std::is_same::value, + typename prop::specialize, typename data_analysis::specialize>::type + specialize; /* mapping specialization tag */ - enum { rank = dimension::rank }; + enum { rank = dimension::rank }; enum { rank_dynamic = dimension::rank_dynamic }; //------------------------------------ // Execution space, memory space, memory access traits, and host mirror space. - typedef ExecutionSpace execution_space ; - typedef MemorySpace memory_space ; - typedef Kokkos::Device device_type ; - typedef MemoryTraits memory_traits ; - typedef HostMirrorSpace host_mirror_space ; + typedef ExecutionSpace execution_space; + typedef MemorySpace memory_space; + typedef Kokkos::Device device_type; + typedef MemoryTraits memory_traits; + typedef HostMirrorSpace host_mirror_space; - typedef typename MemorySpace::size_type size_type ; + typedef typename MemorySpace::size_type size_type; - enum { is_hostspace = std::is_same< MemorySpace , HostSpace >::value }; - enum { is_managed = MemoryTraits::is_unmanaged == 0 }; - enum { is_random_access = MemoryTraits::is_random_access == 1 }; + enum { is_hostspace = std::is_same::value }; + enum { is_managed = MemoryTraits::is_unmanaged == 0 }; + enum { is_random_access = MemoryTraits::is_random_access == 1 }; //------------------------------------ }; @@ -450,7 +417,8 @@ public: * * \section Kokkos_View_MT MemoryTraits discussion * - * \subsection Kokkos_View_MT_Interp MemoryTraits interpretation depends on Space + * \subsection Kokkos_View_MT_Interp MemoryTraits interpretation depends on + * Space * * Some \c MemoryTraits options may have different interpretations for * different \c Space types. For example, with the Cuda device, @@ -479,8 +447,8 @@ public: * } * \endcode */ -template< class DataType , class ... Properties > -class View ; +template +class View; } /* namespace Kokkos */ @@ -497,16 +465,15 @@ namespace Kokkos { namespace { -constexpr Kokkos::Impl::ALL_t - ALL = Kokkos::Impl::ALL_t(); +constexpr Kokkos::Impl::ALL_t ALL = Kokkos::Impl::ALL_t(); -constexpr Kokkos::Impl::WithoutInitializing_t - WithoutInitializing = Kokkos::Impl::WithoutInitializing_t(); +constexpr Kokkos::Impl::WithoutInitializing_t WithoutInitializing = + Kokkos::Impl::WithoutInitializing_t(); -constexpr Kokkos::Impl::AllowPadding_t - AllowPadding = Kokkos::Impl::AllowPadding_t(); +constexpr Kokkos::Impl::AllowPadding_t AllowPadding = + Kokkos::Impl::AllowPadding_t(); -} +} // namespace /** \brief Create View allocation parameter bundle from argument list. * @@ -515,39 +482,34 @@ constexpr Kokkos::Impl::AllowPadding_t * 2) memory space instance of the View::memory_space type * 3) execution space instance compatible with the View::memory_space * 4) Kokkos::WithoutInitializing to bypass initialization - * 4) Kokkos::AllowPadding to allow allocation to pad dimensions for memory alignment + * 4) Kokkos::AllowPadding to allow allocation to pad dimensions for memory + * alignment */ -template< class ... Args > -inline -Impl::ViewCtorProp< typename Impl::ViewCtorProp< void , Args >::type ... > -view_alloc( Args const & ... args ) -{ - typedef - Impl::ViewCtorProp< typename Impl::ViewCtorProp< void , Args >::type ... > - return_type ; +template +inline Impl::ViewCtorProp::type...> +view_alloc(Args const&... args) { + typedef Impl::ViewCtorProp::type...> + return_type; - static_assert( ! return_type::has_pointer - , "Cannot give pointer-to-memory for view allocation" ); + static_assert(!return_type::has_pointer, + "Cannot give pointer-to-memory for view allocation"); - return return_type( args... ); + return return_type(args...); } -template< class ... Args > +template KOKKOS_INLINE_FUNCTION -Impl::ViewCtorProp< typename Impl::ViewCtorProp< void , Args >::type ... > -view_wrap( Args const & ... args ) -{ - typedef - Impl::ViewCtorProp< typename Impl::ViewCtorProp< void , Args >::type ... > - return_type ; + Impl::ViewCtorProp::type...> + view_wrap(Args const&... args) { + typedef Impl::ViewCtorProp::type...> + return_type; - static_assert( ! return_type::has_memory_space && - ! return_type::has_execution_space && - ! return_type::has_label && - return_type::has_pointer - , "Must only give pointer-to-memory for view wrapping" ); + static_assert(!return_type::has_memory_space && + !return_type::has_execution_space && + !return_type::has_label && return_type::has_pointer, + "Must only give pointer-to-memory for view wrapping"); - return return_type( args... ); + return return_type(args...); } } /* namespace Kokkos */ @@ -557,113 +519,120 @@ view_wrap( Args const & ... args ) namespace Kokkos { -template< class DataType , class ... Properties > -class View ; - -template< class > struct is_view : public std::false_type {}; - -template< class D, class ... P > -struct is_view< View > : public std::true_type {}; - -template< class D, class ... P > -struct is_view< const View > : public std::true_type {}; +template +class View; -template< class DataType , class ... Properties > -class View : public ViewTraits< DataType , Properties ... > { -private: +template +struct is_view : public std::false_type {}; - template< class , class ... > friend class View ; - template< class , class ... > friend class Kokkos::Impl::ViewMapping ; +template +struct is_view> : public std::true_type {}; -public: +template +struct is_view> : public std::true_type {}; - typedef ViewTraits< DataType , Properties ... > traits ; +template +class View : public ViewTraits { + private: + template + friend class View; + template + friend class Kokkos::Impl::ViewMapping; -private: + public: + typedef ViewTraits traits; - typedef Kokkos::Impl::ViewMapping< traits , typename traits::specialize > map_type ; - typedef Kokkos::Impl::SharedAllocationTracker track_type ; + private: + typedef Kokkos::Impl::ViewMapping + map_type; + typedef Kokkos::Impl::SharedAllocationTracker track_type; - track_type m_track ; - map_type m_map ; - -public: + track_type m_track; + map_type m_map; + public: //---------------------------------------- /** \brief Compatible view of array of scalar types */ - typedef View< typename traits::scalar_array_type , - typename traits::array_layout , - typename traits::device_type , - typename traits::memory_traits > - array_type ; + typedef View + array_type; /** \brief Compatible view of const data type */ - typedef View< typename traits::const_data_type , - typename traits::array_layout , - typename traits::device_type , - typename traits::memory_traits > - const_type ; + typedef View + const_type; /** \brief Compatible view of non-const data type */ - typedef View< typename traits::non_const_data_type , - typename traits::array_layout , - typename traits::device_type , - typename traits::memory_traits > - non_const_type ; + typedef View + non_const_type; /** \brief Compatible HostMirror view */ - typedef View< typename traits::non_const_data_type , - typename traits::array_layout , - typename traits::host_mirror_space > - HostMirror ; + typedef View> + HostMirror; /** \brief Compatible HostMirror view */ - typedef View< typename traits::non_const_data_type , - typename traits::array_layout , - typename traits::host_mirror_space > - host_mirror_type ; + typedef View + host_mirror_type; /** \brief Unified types */ - typedef typename Impl::ViewUniformType::type uniform_type; - typedef typename Impl::ViewUniformType::const_type uniform_const_type; - typedef typename Impl::ViewUniformType::runtime_type uniform_runtime_type; - typedef typename Impl::ViewUniformType::runtime_const_type uniform_runtime_const_type; - typedef typename Impl::ViewUniformType::nomemspace_type uniform_nomemspace_type; - typedef typename Impl::ViewUniformType::const_nomemspace_type uniform_const_nomemspace_type; - typedef typename Impl::ViewUniformType::runtime_nomemspace_type uniform_runtime_nomemspace_type; - typedef typename Impl::ViewUniformType::runtime_const_nomemspace_type uniform_runtime_const_nomemspace_type; + typedef typename Impl::ViewUniformType::type uniform_type; + typedef + typename Impl::ViewUniformType::const_type uniform_const_type; + typedef typename Impl::ViewUniformType::runtime_type + uniform_runtime_type; + typedef typename Impl::ViewUniformType::runtime_const_type + uniform_runtime_const_type; + typedef typename Impl::ViewUniformType::nomemspace_type + uniform_nomemspace_type; + typedef typename Impl::ViewUniformType::const_nomemspace_type + uniform_const_nomemspace_type; + typedef typename Impl::ViewUniformType::runtime_nomemspace_type + uniform_runtime_nomemspace_type; + typedef typename Impl::ViewUniformType::runtime_const_nomemspace_type + uniform_runtime_const_nomemspace_type; //---------------------------------------- // Domain rank and extents enum { Rank = map_type::Rank }; - /** \brief rank() to be implemented - */ - //KOKKOS_INLINE_FUNCTION - //static - //constexpr unsigned rank() { return map_type::Rank; } + /** \brief rank() to be implemented + */ + // KOKKOS_INLINE_FUNCTION + // static + // constexpr unsigned rank() { return map_type::Rank; } - template< typename iType > + template KOKKOS_INLINE_FUNCTION constexpr - typename std::enable_if< std::is_integral::value , size_t >::type - extent( const iType & r ) const noexcept - { return m_map.extent(r); } + typename std::enable_if::value, size_t>::type + extent(const iType& r) const noexcept { + return m_map.extent(r); + } - static KOKKOS_INLINE_FUNCTION constexpr - size_t - static_extent( const unsigned r ) noexcept - { return map_type::static_extent(r); } + static KOKKOS_INLINE_FUNCTION constexpr size_t static_extent( + const unsigned r) noexcept { + return map_type::static_extent(r); + } - template< typename iType > + template KOKKOS_INLINE_FUNCTION constexpr - typename std::enable_if< std::is_integral::value , int >::type - extent_int( const iType & r ) const noexcept - { return static_cast(m_map.extent(r)); } + typename std::enable_if::value, int>::type + extent_int(const iType& r) const noexcept { + return static_cast(m_map.extent(r)); + } - KOKKOS_INLINE_FUNCTION constexpr - typename traits::array_layout layout() const - { return m_map.layout(); } + KOKKOS_INLINE_FUNCTION constexpr typename traits::array_layout layout() + const { + return m_map.layout(); + } //---------------------------------------- /* Deprecate all 'dimension' functions in favor of @@ -672,80 +641,134 @@ public: #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - template< typename iType > + template KOKKOS_INLINE_FUNCTION constexpr - typename std::enable_if< std::is_integral::value , size_t >::type - dimension( const iType & r ) const { return extent( r ); } - - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_0() const { return m_map.dimension_0(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_1() const { return m_map.dimension_1(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_2() const { return m_map.dimension_2(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_3() const { return m_map.dimension_3(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_4() const { return m_map.dimension_4(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_5() const { return m_map.dimension_5(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_6() const { return m_map.dimension_6(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_7() const { return m_map.dimension_7(); } + typename std::enable_if::value, size_t>::type + dimension(const iType& r) const { + return extent(r); + } + + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_0() const { + return m_map.dimension_0(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_1() const { + return m_map.dimension_1(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_2() const { + return m_map.dimension_2(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_3() const { + return m_map.dimension_3(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_4() const { + return m_map.dimension_4(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_5() const { + return m_map.dimension_5(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_6() const { + return m_map.dimension_6(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_7() const { + return m_map.dimension_7(); + } #endif //---------------------------------------- - KOKKOS_INLINE_FUNCTION constexpr size_t size() const { return m_map.dimension_0() * - m_map.dimension_1() * - m_map.dimension_2() * - m_map.dimension_3() * - m_map.dimension_4() * - m_map.dimension_5() * - m_map.dimension_6() * - m_map.dimension_7(); } - - KOKKOS_INLINE_FUNCTION constexpr size_t stride_0() const { return m_map.stride_0(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_1() const { return m_map.stride_1(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_2() const { return m_map.stride_2(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_3() const { return m_map.stride_3(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_4() const { return m_map.stride_4(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_5() const { return m_map.stride_5(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_6() const { return m_map.stride_6(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_7() const { return m_map.stride_7(); } - - template< typename iType > + KOKKOS_INLINE_FUNCTION constexpr size_t size() const { + return m_map.dimension_0() * m_map.dimension_1() * m_map.dimension_2() * + m_map.dimension_3() * m_map.dimension_4() * m_map.dimension_5() * + m_map.dimension_6() * m_map.dimension_7(); + } + + KOKKOS_INLINE_FUNCTION constexpr size_t stride_0() const { + return m_map.stride_0(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_1() const { + return m_map.stride_1(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_2() const { + return m_map.stride_2(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_3() const { + return m_map.stride_3(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_4() const { + return m_map.stride_4(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_5() const { + return m_map.stride_5(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_6() const { + return m_map.stride_6(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_7() const { + return m_map.stride_7(); + } + + template KOKKOS_INLINE_FUNCTION constexpr - typename std::enable_if< std::is_integral::value , size_t >::type - stride(iType r) const { - return (r == 0 ? m_map.stride_0() : - (r == 1 ? m_map.stride_1() : - (r == 2 ? m_map.stride_2() : - (r == 3 ? m_map.stride_3() : - (r == 4 ? m_map.stride_4() : - (r == 5 ? m_map.stride_5() : - (r == 6 ? m_map.stride_6() : - m_map.stride_7()))))))); + typename std::enable_if::value, size_t>::type + stride(iType r) const { + return ( + r == 0 + ? m_map.stride_0() + : (r == 1 + ? m_map.stride_1() + : (r == 2 + ? m_map.stride_2() + : (r == 3 + ? m_map.stride_3() + : (r == 4 + ? m_map.stride_4() + : (r == 5 + ? m_map.stride_5() + : (r == 6 + ? m_map.stride_6() + : m_map.stride_7()))))))); } - template< typename iType > - KOKKOS_INLINE_FUNCTION void stride( iType * const s ) const { m_map.stride(s); } + template + KOKKOS_INLINE_FUNCTION void stride(iType* const s) const { + m_map.stride(s); + } //---------------------------------------- // Range span is the span which contains all members. - typedef typename map_type::reference_type reference_type ; - typedef typename map_type::pointer_type pointer_type ; + typedef typename map_type::reference_type reference_type; + typedef typename map_type::pointer_type pointer_type; - enum { reference_type_is_lvalue_reference = std::is_lvalue_reference< reference_type >::value }; + enum { + reference_type_is_lvalue_reference = + std::is_lvalue_reference::value + }; KOKKOS_INLINE_FUNCTION constexpr size_t span() const { return m_map.span(); } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE // Deprecated, use 'span()' instead - KOKKOS_INLINE_FUNCTION constexpr size_t capacity() const { return m_map.span(); } + KOKKOS_INLINE_FUNCTION constexpr size_t capacity() const { + return m_map.span(); + } #endif - KOKKOS_INLINE_FUNCTION bool span_is_contiguous() const { return m_map.span_is_contiguous(); } - KOKKOS_INLINE_FUNCTION constexpr pointer_type data() const { return m_map.data(); } + KOKKOS_INLINE_FUNCTION bool span_is_contiguous() const { + return m_map.span_is_contiguous(); + } + KOKKOS_INLINE_FUNCTION constexpr pointer_type data() const { + return m_map.data(); + } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE // Deprecated, use 'span_is_contigous()' instead - KOKKOS_INLINE_FUNCTION constexpr bool is_contiguous() const { return m_map.span_is_contiguous(); } + KOKKOS_INLINE_FUNCTION constexpr bool is_contiguous() const { + return m_map.span_is_contiguous(); + } // Deprecated, use 'data()' instead - KOKKOS_INLINE_FUNCTION constexpr pointer_type ptr_on_device() const { return m_map.data(); } + KOKKOS_INLINE_FUNCTION constexpr pointer_type ptr_on_device() const { + return m_map.data(); + } #endif //---------------------------------------- @@ -753,1215 +776,946 @@ public: #ifdef KOKKOS_ENABLE_DEPRECATED_CODE KOKKOS_INLINE_FUNCTION - const Kokkos::Impl::ViewMapping< traits , typename traits::specialize > & - implementation_map() const { return m_map ; } + const Kokkos::Impl::ViewMapping& + implementation_map() const { + return m_map; + } #endif KOKKOS_INLINE_FUNCTION - const Kokkos::Impl::ViewMapping< traits , typename traits::specialize > & - impl_map() const { return m_map ; } + const Kokkos::Impl::ViewMapping& + impl_map() const { + return m_map; + } KOKKOS_INLINE_FUNCTION - const Kokkos::Impl::SharedAllocationTracker & - impl_track() const { return m_track ; } + const Kokkos::Impl::SharedAllocationTracker& impl_track() const { + return m_track; + } //---------------------------------------- -private: - + private: enum { - is_layout_left = std::is_same< typename traits::array_layout - , Kokkos::LayoutLeft >::value , + is_layout_left = + std::is_same::value, - is_layout_right = std::is_same< typename traits::array_layout - , Kokkos::LayoutRight >::value , + is_layout_right = + std::is_same::value, - is_layout_stride = std::is_same< typename traits::array_layout - , Kokkos::LayoutStride >::value , + is_layout_stride = std::is_same::value, - is_default_map = - std::is_same< typename traits::specialize , void >::value && - ( is_layout_left || is_layout_right || is_layout_stride ) + is_default_map = std::is_same::value && + (is_layout_left || is_layout_right || is_layout_stride) }; - template< class Space , bool = Kokkos::Impl::MemorySpaceAccess< Space , typename traits::memory_space >::accessible > struct verify_space - { KOKKOS_FORCEINLINE_FUNCTION static void check() {} }; + template ::accessible> + struct verify_space { + KOKKOS_FORCEINLINE_FUNCTION static void check() {} + }; - template< class Space > struct verify_space - { KOKKOS_FORCEINLINE_FUNCTION static void check() - { Kokkos::abort("Kokkos::View ERROR: attempt to access inaccessible memory space"); }; + template + struct verify_space { + KOKKOS_FORCEINLINE_FUNCTION static void check() { + Kokkos::abort( + "Kokkos::View ERROR: attempt to access inaccessible memory space"); }; + }; -#if defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK ) +#if defined(KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK) -#define KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( ARG ) \ - View::template verify_space< Kokkos::Impl::ActiveExecutionMemorySpace >::check(); \ - Kokkos::Impl::view_verify_operator_bounds< typename traits::memory_space > ARG ; +#define KOKKOS_IMPL_VIEW_OPERATOR_VERIFY(ARG) \ + View::template verify_space< \ + Kokkos::Impl::ActiveExecutionMemorySpace>::check(); \ + Kokkos::Impl::view_verify_operator_bounds ARG; #else -#define KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( ARG ) \ - View::template verify_space< Kokkos::Impl::ActiveExecutionMemorySpace >::check(); +#define KOKKOS_IMPL_VIEW_OPERATOR_VERIFY(ARG) \ + View::template verify_space< \ + Kokkos::Impl::ActiveExecutionMemorySpace>::check(); #endif -public: + public: #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - template< class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if<( Kokkos::Impl::are_integral::value - && ( 0 == Rank ) - ), reference_type >::type - operator()( Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,args...) ) - return m_map.reference(); - } - - template< typename I0 - , class ... Args> - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0, - Args ... args) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,args...) ) - return m_map.reference(i0); - } - - template< typename I0 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && is_default_map - && ! is_layout_stride - ), reference_type >::type - operator()( const I0 & i0 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,args...) ) - return m_map.m_impl_handle[ i0 ]; - } - - template< typename I0 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && is_default_map - && is_layout_stride - ), reference_type >::type - operator()( const I0 & i0 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset.m_stride.S0 * i0 ]; - } - - //------------------------------ - // Rank 1 operator[] - - template< typename I0 > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && ! is_default_map - ), reference_type >::type - operator[]( const I0 & i0 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0) ) - return m_map.reference(i0); - } - - template< typename I0 > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && is_default_map - && ! is_layout_stride - ), reference_type >::type - operator[]( const I0 & i0 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0) ) - return m_map.m_impl_handle[ i0 ]; - } - - template< typename I0 > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && is_default_map - && is_layout_stride - ), reference_type >::type - operator[]( const I0 & i0 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0) ) - return m_map.m_impl_handle[ m_map.m_impl_offset.m_stride.S0 * i0 ]; - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.reference(i0,i1); - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_left && ( traits::rank_dynamic == 0 ) - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.m_impl_handle[ i0 + m_map.m_impl_offset.m_dim.N0 * i1 ]; - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_left && ( traits::rank_dynamic != 0 ) - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.m_impl_handle[ i0 + m_map.m_impl_offset.m_stride * i1 ]; - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_right && ( traits::rank_dynamic == 0 ) - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.m_impl_handle[ i1 + m_map.m_impl_offset.m_dim.N1 * i0 ]; - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_right && ( traits::rank_dynamic != 0 ) - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.m_impl_handle[ i1 + m_map.m_impl_offset.m_stride * i0 ]; - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_stride - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.m_impl_handle[ i0 * m_map.m_impl_offset.m_stride.S0 + - i1 * m_map.m_impl_offset.m_stride.S1 ]; - } - - //------------------------------ - // Rank 3 - - template< typename I0 , typename I1 , typename I2 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 3 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2) ]; - } - - template< typename I0 , typename I1 , typename I2 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 3 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,args...) ) - return m_map.reference(i0,i1,i2); - } - - //------------------------------ - // Rank 4 - - template< typename I0 , typename I1 , typename I2 , typename I3 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 4 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3) ]; - } - - template< typename I0 , typename I1 , typename I2 , typename I3 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 4 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,args...) ) - return m_map.reference(i0,i1,i2,i3); - } - - //------------------------------ - // Rank 5 - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 5 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4) ]; - } - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 5 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,args...) ) - return m_map.reference(i0,i1,i2,i3,i4); - } - - //------------------------------ - // Rank 6 - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 6 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4,i5) ]; - } - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 6 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,args...) ) - return m_map.reference(i0,i1,i2,i3,i4,i5); - } - - //------------------------------ - // Rank 7 - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 7 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4,i5,i6) ]; - } - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 7 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6,args...) ) - return m_map.reference(i0,i1,i2,i3,i4,i5,i6); - } - - //------------------------------ - // Rank 8 - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6 , typename I7 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 8 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6 , const I7 & i7 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6,i7,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4,i5,i6,i7) ]; - } - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6 , typename I7 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 8 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6 , const I7 & i7 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6,i7,args...) ) - return m_map.reference(i0,i1,i2,i3,i4,i5,i6,i7); - } - - - #else + template + KOKKOS_FORCEINLINE_FUNCTION + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (0 == Rank)), + reference_type>::type + operator()(Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, args...)) + return m_map.reference(); + } + + template + KOKKOS_FORCEINLINE_FUNCTION + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, args...)) + return m_map.reference(i0); + } + + template + KOKKOS_FORCEINLINE_FUNCTION + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && is_default_map && + !is_layout_stride), + reference_type>::type + operator()(const I0& i0, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, args...)) + return m_map.m_impl_handle[i0]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && is_default_map && + is_layout_stride), + reference_type>::type + operator()(const I0& i0, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset.m_stride.S0 * i0]; + } + + //------------------------------ + // Rank 1 operator[] + + template + KOKKOS_FORCEINLINE_FUNCTION + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && !is_default_map), + reference_type>::type + operator[](const I0& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0)) + return m_map.reference(i0); + } + + template + KOKKOS_FORCEINLINE_FUNCTION + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && is_default_map && + !is_layout_stride), + reference_type>::type + operator[](const I0& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0)) + return m_map.m_impl_handle[i0]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && is_default_map && + is_layout_stride), + reference_type>::type + operator[](const I0& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0)) + return m_map.m_impl_handle[m_map.m_impl_offset.m_stride.S0 * i0]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.reference(i0, i1); + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + is_default_map && is_layout_left && (traits::rank_dynamic == 0)), + reference_type>::type + operator()(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.m_impl_handle[i0 + m_map.m_impl_offset.m_dim.N0 * i1]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + is_default_map && is_layout_left && (traits::rank_dynamic != 0)), + reference_type>::type + operator()(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.m_impl_handle[i0 + m_map.m_impl_offset.m_stride * i1]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + is_default_map && is_layout_right && (traits::rank_dynamic == 0)), + reference_type>::type + operator()(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.m_impl_handle[i1 + m_map.m_impl_offset.m_dim.N1 * i0]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + is_default_map && is_layout_right && (traits::rank_dynamic != 0)), + reference_type>::type + operator()(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.m_impl_handle[i1 + m_map.m_impl_offset.m_stride * i0]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + is_default_map && is_layout_stride), + reference_type>::type + operator()(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.m_impl_handle[i0 * m_map.m_impl_offset.m_stride.S0 + + i1 * m_map.m_impl_offset.m_stride.S1]; + } + + //------------------------------ + // Rank 3 + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (3 == Rank) && + is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (3 == Rank) && + !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, args...)) + return m_map.reference(i0, i1, i2); + } + + //------------------------------ + // Rank 4 + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (4 == Rank) && is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, i3, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (4 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, i3, args...)) + return m_map.reference(i0, i1, i2, i3); + } + + //------------------------------ + // Rank 5 + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (5 == Rank) && is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (5 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, args...)) + return m_map.reference(i0, i1, i2, i3, i4); + } + + //------------------------------ + // Rank 6 + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (6 == Rank) && is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4, i5)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (6 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, args...)) + return m_map.reference(i0, i1, i2, i3, i4, i5); + } + + //------------------------------ + // Rank 7 + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (7 == Rank) && is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5, const I6& i6, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4, i5, i6)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (7 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5, const I6& i6, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6, args...)) + return m_map.reference(i0, i1, i2, i3, i4, i5, i6); + } + + //------------------------------ + // Rank 8 + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (8 == Rank) && is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5, const I6& i6, const I7& i7, + Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6, i7, args...)) + return m_map + .m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4, i5, i6, i7)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (8 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5, const I6& i6, const I7& i7, + Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6, i7, args...)) + return m_map.reference(i0, i1, i2, i3, i4, i5, i6, i7); + } + +#else //------------------------------ // Rank 0 operator() - KOKKOS_FORCEINLINE_FUNCTION - reference_type - operator()() const - { - return m_map.reference(); - } + KOKKOS_FORCEINLINE_FUNCTION + reference_type operator()() const { return m_map.reference(); } //------------------------------ // Rank 1 operator() + template + KOKKOS_FORCEINLINE_FUNCTION + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0)) + return m_map.reference(i0); + } - template< typename I0> + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0) ) - return m_map.reference(i0); - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && is_default_map && + !is_layout_stride), + reference_type>::type + operator()(const I0& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0)) + return m_map.m_impl_handle[i0]; + } - template< typename I0> + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && is_default_map - && ! is_layout_stride - ), reference_type >::type - operator()( const I0 & i0 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0) ) - return m_map.m_impl_handle[ i0 ]; - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && is_default_map && + is_layout_stride), + reference_type>::type + operator()(const I0& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0)) + return m_map.m_impl_handle[m_map.m_impl_offset.m_stride.S0 * i0]; + } + //------------------------------ + // Rank 1 operator[] - template< typename I0 > + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && is_default_map - && is_layout_stride - ), reference_type >::type - operator()( const I0 & i0) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0) ) - return m_map.m_impl_handle[ m_map.m_impl_offset.m_stride.S0 * i0 ]; - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && !is_default_map), + reference_type>::type + operator[](const I0& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0)) + return m_map.reference(i0); + } + + template + KOKKOS_FORCEINLINE_FUNCTION + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && is_default_map && + !is_layout_stride), + reference_type>::type + operator[](const I0& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0)) + return m_map.m_impl_handle[i0]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && is_default_map && + is_layout_stride), + reference_type>::type + operator[](const I0& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0)) + return m_map.m_impl_handle[m_map.m_impl_offset.m_stride.S0 * i0]; + } + //------------------------------ - // Rank 1 operator[] - - template< typename I0 > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && ! is_default_map - ), reference_type >::type - operator[]( const I0 & i0 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0) ) - return m_map.reference(i0); - } - - template< typename I0 > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && is_default_map - && ! is_layout_stride - ), reference_type >::type - operator[]( const I0 & i0 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0) ) - return m_map.m_impl_handle[ i0 ]; - } - - template< typename I0 > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && is_default_map - && is_layout_stride - ), reference_type >::type - operator[]( const I0 & i0 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0) ) - return m_map.m_impl_handle[ m_map.m_impl_offset.m_stride.S0 * i0 ]; - } - - - //------------------------------ // Rank 2 - template< typename I0 , typename I1 > + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1) ) - return m_map.reference(i0,i1); - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (2 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1)) + return m_map.reference(i0, i1); + } - template< typename I0 , typename I1 > + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_left && ( traits::rank_dynamic == 0 ) - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1) ) - return m_map.m_impl_handle[ i0 + m_map.m_impl_offset.m_dim.N0 * i1 ]; - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (2 == Rank) && is_default_map && + is_layout_left && (traits::rank_dynamic == 0)), + reference_type>::type + operator()(const I0& i0, const I1& i1) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1)) + return m_map.m_impl_handle[i0 + m_map.m_impl_offset.m_dim.N0 * i1]; + } - template< typename I0 , typename I1> + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_left && ( traits::rank_dynamic != 0 ) - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1) ) - return m_map.m_impl_handle[ i0 + m_map.m_impl_offset.m_stride * i1 ]; - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (2 == Rank) && is_default_map && + is_layout_left && (traits::rank_dynamic != 0)), + reference_type>::type + operator()(const I0& i0, const I1& i1) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1)) + return m_map.m_impl_handle[i0 + m_map.m_impl_offset.m_stride * i1]; + } - template< typename I0 , typename I1 > + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_right && ( traits::rank_dynamic == 0 ) - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1) ) - return m_map.m_impl_handle[ i1 + m_map.m_impl_offset.m_dim.N1 * i0 ]; - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (2 == Rank) && is_default_map && + is_layout_right && (traits::rank_dynamic == 0)), + reference_type>::type + operator()(const I0& i0, const I1& i1) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1)) + return m_map.m_impl_handle[i1 + m_map.m_impl_offset.m_dim.N1 * i0]; + } - template< typename I0 , typename I1 > + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_right && ( traits::rank_dynamic != 0 ) - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1) ) - return m_map.m_impl_handle[ i1 + m_map.m_impl_offset.m_stride * i0 ]; - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (2 == Rank) && is_default_map && + is_layout_right && (traits::rank_dynamic != 0)), + reference_type>::type + operator()(const I0& i0, const I1& i1) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1)) + return m_map.m_impl_handle[i1 + m_map.m_impl_offset.m_stride * i0]; + } - template< typename I0 , typename I1> + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_stride - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1) ) - return m_map.m_impl_handle[ i0 * m_map.m_impl_offset.m_stride.S0 + - i1 * m_map.m_impl_offset.m_stride.S1 ]; - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (2 == Rank) && is_default_map && + is_layout_stride), + reference_type>::type + operator()(const I0& i0, const I1& i1) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1)) + return m_map.m_impl_handle[i0 * m_map.m_impl_offset.m_stride.S0 + + i1 * m_map.m_impl_offset.m_stride.S1]; + } //------------------------------ // Rank 3 - template< typename I0 , typename I1 , typename I2 > + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 3 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2) ]; - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (3 == Rank) && is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2)]; + } - template< typename I0 , typename I1 , typename I2> + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 3 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2) ) - return m_map.reference(i0,i1,i2); - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (3 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2)) + return m_map.reference(i0, i1, i2); + } //------------------------------ // Rank 4 - template< typename I0 , typename I1 , typename I2 , typename I3> - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 4 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3) ]; - } + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (4 == Rank) && + is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, i3)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3)]; + } - template< typename I0 , typename I1 , typename I2 , typename I3 > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 4 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3) ) - return m_map.reference(i0,i1,i2,i3); - } + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (4 == Rank) && + !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, i3)) + return m_map.reference(i0, i1, i2, i3); + } //------------------------------ // Rank 5 - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4> - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 5 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4) ]; - } + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (5 == Rank) && + is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, i3, i4)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4)]; + } - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4> - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 5 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4) ) - return m_map.reference(i0,i1,i2,i3,i4); - } + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (5 == Rank) && + !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, i3, i4)) + return m_map.reference(i0, i1, i2, i3, i4); + } //------------------------------ // Rank 6 - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 6 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4,i5) ]; - } + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (6 == Rank) && is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, i3, i4, i5)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4, i5)]; + } - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5> - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 6 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5) ) - return m_map.reference(i0,i1,i2,i3,i4,i5); - } + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (6 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, i3, i4, i5)) + return m_map.reference(i0, i1, i2, i3, i4, i5); + } //------------------------------ // Rank 7 - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6> - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 7 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4,i5,i6) ]; - } + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (7 == Rank) && is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5, const I6& i6) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4, i5, i6)]; + } - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6 > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 7 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6) ) - return m_map.reference(i0,i1,i2,i3,i4,i5,i6); - } + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (7 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5, const I6& i6) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6)) + return m_map.reference(i0, i1, i2, i3, i4, i5, i6); + } //------------------------------ // Rank 8 - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6 , typename I7 > + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (8 == Rank) && is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5, const I6& i6, const I7& i7) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6, i7)) + return m_map + .m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4, i5, i6, i7)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (8 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5, const I6& i6, const I7& i7) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6, i7)) + return m_map.reference(i0, i1, i2, i3, i4, i5, i6, i7); + } + +#endif + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 8 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6 , const I7 & i7) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6,i7) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4,i5,i6,i7) ]; - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (0 == Rank)), + reference_type>::type + access(Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, args...)) + return m_map.reference(); + } - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6 , typename I7> + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 8 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6 , const I7 & i7 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6,i7) ) - return m_map.reference(i0,i1,i2,i3,i4,i5,i6,i7); - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && !is_default_map), + reference_type>::type + access(const I0& i0, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, args...)) + return m_map.reference(i0); + } -#endif - template< class ... Args > + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if<( Kokkos::Impl::are_integral::value - && ( 0 == Rank ) - ), reference_type >::type - access( Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,args...) ) - return m_map.reference(); - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && is_default_map && + !is_layout_stride), + reference_type>::type + access(const I0& i0, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, args...)) + return m_map.m_impl_handle[i0]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && is_default_map && + is_layout_stride), + reference_type>::type + access(const I0& i0, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset.m_stride.S0 * i0]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + !is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.reference(i0, i1); + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + is_default_map && is_layout_left && (traits::rank_dynamic == 0)), + reference_type>::type + access(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.m_impl_handle[i0 + m_map.m_impl_offset.m_dim.N0 * i1]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + is_default_map && is_layout_left && (traits::rank_dynamic != 0)), + reference_type>::type + access(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.m_impl_handle[i0 + m_map.m_impl_offset.m_stride * i1]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + is_default_map && is_layout_right && (traits::rank_dynamic == 0)), + reference_type>::type + access(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.m_impl_handle[i1 + m_map.m_impl_offset.m_dim.N1 * i0]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + is_default_map && is_layout_right && (traits::rank_dynamic != 0)), + reference_type>::type + access(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.m_impl_handle[i1 + m_map.m_impl_offset.m_stride * i0]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + is_default_map && is_layout_stride), + reference_type>::type + access(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.m_impl_handle[i0 * m_map.m_impl_offset.m_stride.S0 + + i1 * m_map.m_impl_offset.m_stride.S1]; + } + + //------------------------------ + // Rank 3 + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (3 == Rank) && + is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (3 == Rank) && + !is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, args...)) + return m_map.reference(i0, i1, i2); + } + + //------------------------------ + // Rank 4 + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (4 == Rank) && is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, i3, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (4 == Rank) && !is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, i3, args...)) + return m_map.reference(i0, i1, i2, i3); + } + + //------------------------------ + // Rank 5 + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (5 == Rank) && is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, const I3& i3, const I4& i4, + Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (5 == Rank) && !is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, const I3& i3, const I4& i4, + Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, args...)) + return m_map.reference(i0, i1, i2, i3, i4); + } + + //------------------------------ + // Rank 6 + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (6 == Rank) && is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, const I3& i3, const I4& i4, + const I5& i5, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4, i5)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (6 == Rank) && !is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, const I3& i3, const I4& i4, + const I5& i5, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, args...)) + return m_map.reference(i0, i1, i2, i3, i4, i5); + } + + //------------------------------ + // Rank 7 + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (7 == Rank) && is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, const I3& i3, const I4& i4, + const I5& i5, const I6& i6, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4, i5, i6)]; + } - template< typename I0 - , class ... Args> - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && ! is_default_map - ), reference_type >::type - access( const I0 & i0, - Args ... args) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,args...) ) - return m_map.reference(i0); - } - - template< typename I0 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && is_default_map - && ! is_layout_stride - ), reference_type >::type - access( const I0 & i0 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,args...) ) - return m_map.m_impl_handle[ i0 ]; - } - - template< typename I0 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && is_default_map - && is_layout_stride - ), reference_type >::type - access( const I0 & i0 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset.m_stride.S0 * i0 ]; - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && ! is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.reference(i0,i1); - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_left && ( traits::rank_dynamic == 0 ) - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.m_impl_handle[ i0 + m_map.m_impl_offset.m_dim.N0 * i1 ]; - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_left && ( traits::rank_dynamic != 0 ) - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.m_impl_handle[ i0 + m_map.m_impl_offset.m_stride * i1 ]; - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_right && ( traits::rank_dynamic == 0 ) - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.m_impl_handle[ i1 + m_map.m_impl_offset.m_dim.N1 * i0 ]; - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_right && ( traits::rank_dynamic != 0 ) - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.m_impl_handle[ i1 + m_map.m_impl_offset.m_stride * i0 ]; - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_stride - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.m_impl_handle[ i0 * m_map.m_impl_offset.m_stride.S0 + - i1 * m_map.m_impl_offset.m_stride.S1 ]; - } - - //------------------------------ - // Rank 3 - - template< typename I0 , typename I1 , typename I2 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 3 == Rank ) - && is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2) ]; - } - - template< typename I0 , typename I1 , typename I2 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 3 == Rank ) - && ! is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,args...) ) - return m_map.reference(i0,i1,i2); - } - - //------------------------------ - // Rank 4 - - template< typename I0 , typename I1 , typename I2 , typename I3 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 4 == Rank ) - && is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3) ]; - } - - template< typename I0 , typename I1 , typename I2 , typename I3 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 4 == Rank ) - && ! is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,args...) ) - return m_map.reference(i0,i1,i2,i3); - } - - //------------------------------ - // Rank 5 - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 5 == Rank ) - && is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4) ]; - } - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 5 == Rank ) - && ! is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,args...) ) - return m_map.reference(i0,i1,i2,i3,i4); - } - - //------------------------------ - // Rank 6 - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 6 == Rank ) - && is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4,i5) ]; - } - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 6 == Rank ) - && ! is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,args...) ) - return m_map.reference(i0,i1,i2,i3,i4,i5); - } - - //------------------------------ - // Rank 7 - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 7 == Rank ) - && is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4,i5,i6) ]; - } - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 7 == Rank ) - && ! is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6,args...) ) - return m_map.reference(i0,i1,i2,i3,i4,i5,i6); - } - - //------------------------------ - // Rank 8 - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6 , typename I7 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 8 == Rank ) - && is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6 , const I7 & i7 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6,i7,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4,i5,i6,i7) ]; - } - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6 , typename I7 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 8 == Rank ) - && ! is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6 , const I7 & i7 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6,i7,args...) ) - return m_map.reference(i0,i1,i2,i3,i4,i5,i6,i7); - } + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (7 == Rank) && !is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, const I3& i3, const I4& i4, + const I5& i5, const I6& i6, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6, args...)) + return m_map.reference(i0, i1, i2, i3, i4, i5, i6); + } + + //------------------------------ + // Rank 8 + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (8 == Rank) && is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, const I3& i3, const I4& i4, + const I5& i5, const I6& i6, const I7& i7, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6, i7, args...)) + return m_map + .m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4, i5, i6, i7)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (8 == Rank) && !is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, const I3& i3, const I4& i4, + const I5& i5, const I6& i6, const I7& i7, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6, i7, args...)) + return m_map.reference(i0, i1, i2, i3, i4, i5, i6, i7); + } #undef KOKKOS_IMPL_VIEW_OPERATOR_VERIFY @@ -1975,546 +1729,522 @@ public: View() : m_track(), m_map() {} KOKKOS_INLINE_FUNCTION - View( const View & rhs ) : m_track( rhs.m_track, traits::is_managed ), m_map( rhs.m_map ) {} + View(const View& rhs) + : m_track(rhs.m_track, traits::is_managed), m_map(rhs.m_map) {} KOKKOS_INLINE_FUNCTION - View( View && rhs ) : m_track( std::move(rhs.m_track) ), m_map( std::move(rhs.m_map) ) {} + View(View&& rhs) + : m_track(std::move(rhs.m_track)), m_map(std::move(rhs.m_map)) {} KOKKOS_INLINE_FUNCTION - View & operator = ( const View & rhs ) { m_track = rhs.m_track ; m_map = rhs.m_map ; return *this ; } + View& operator=(const View& rhs) { + m_track = rhs.m_track; + m_map = rhs.m_map; + return *this; + } KOKKOS_INLINE_FUNCTION - View & operator = ( View && rhs ) { m_track = std::move(rhs.m_track) ; m_map = std::move(rhs.m_map) ; return *this ; } - - + View& operator=(View&& rhs) { + m_track = std::move(rhs.m_track); + m_map = std::move(rhs.m_map); + return *this; + } //---------------------------------------- // Compatible view copy constructor and assignment // may assign unmanaged from managed. - template< class RT , class ... RP > - KOKKOS_INLINE_FUNCTION - View( const View & rhs, - typename std::enable_if::traits , typename traits::specialize >::is_assignable_data_type>::type* = 0 - ) - : m_track( rhs.m_track , traits::is_managed ) - , m_map() - { - typedef typename View::traits SrcTraits ; - typedef Kokkos::Impl::ViewMapping< traits , SrcTraits , typename traits::specialize > Mapping ; - static_assert( Mapping::is_assignable , "Incompatible View copy construction" ); - Mapping::assign( m_map , rhs.m_map , rhs.m_track ); - } + template + KOKKOS_INLINE_FUNCTION View( + const View& rhs, + typename std::enable_if::traits, + typename traits::specialize>::is_assignable_data_type>::type* = 0) + : m_track(rhs.m_track, traits::is_managed), m_map() { + typedef typename View::traits SrcTraits; + typedef Kokkos::Impl::ViewMapping + Mapping; + static_assert(Mapping::is_assignable, + "Incompatible View copy construction"); + Mapping::assign(m_map, rhs.m_map, rhs.m_track); + } - template< class RT , class ... RP > - KOKKOS_INLINE_FUNCTION - typename std::enable_if::traits , typename traits::specialize >::is_assignable_data_type, - View>::type & operator = ( const View & rhs ) - { - typedef typename View::traits SrcTraits ; - typedef Kokkos::Impl::ViewMapping< traits , SrcTraits , typename traits::specialize > Mapping ; - static_assert( Mapping::is_assignable , "Incompatible View copy assignment" ); - Mapping::assign( m_map , rhs.m_map , rhs.m_track ); - m_track.assign( rhs.m_track , traits::is_managed ); - return *this ; - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + Kokkos::Impl::ViewMapping< + traits, typename View::traits, + typename traits::specialize>::is_assignable_data_type, + View>::type& + operator=(const View& rhs) { + typedef typename View::traits SrcTraits; + typedef Kokkos::Impl::ViewMapping + Mapping; + static_assert(Mapping::is_assignable, "Incompatible View copy assignment"); + Mapping::assign(m_map, rhs.m_map, rhs.m_track); + m_track.assign(rhs.m_track, traits::is_managed); + return *this; + } //---------------------------------------- // Compatible subview constructor // may assign unmanaged from managed. - template< class RT , class ... RP , class Arg0 , class ... Args > - KOKKOS_INLINE_FUNCTION - View( const View< RT , RP... > & src_view - , const Arg0 arg0 , Args ... args ) - : m_track( src_view.m_track , traits::is_managed ) - , m_map() - { - typedef View< RT , RP... > SrcType ; + template + KOKKOS_INLINE_FUNCTION View(const View& src_view, const Arg0 arg0, + Args... args) + : m_track(src_view.m_track, traits::is_managed), m_map() { + typedef View SrcType; - typedef Kokkos::Impl::ViewMapping - < void /* deduce destination view type from source view traits */ - , typename SrcType::traits - , Arg0 , Args... > Mapping ; + typedef Kokkos::Impl::ViewMapping + Mapping; - typedef typename Mapping::type DstType ; + typedef typename Mapping::type DstType; - static_assert( Kokkos::Impl::ViewMapping< traits , typename DstType::traits , typename traits::specialize >::is_assignable - , "Subview construction requires compatible view and subview arguments" ); + static_assert( + Kokkos::Impl::ViewMapping::is_assignable, + "Subview construction requires compatible view and subview arguments"); - Mapping::assign( m_map, src_view.m_map, arg0 , args... ); - } + Mapping::assign(m_map, src_view.m_map, arg0, args...); + } //---------------------------------------- // Allocation tracking properties KOKKOS_INLINE_FUNCTION - int use_count() const - { return m_track.use_count(); } + int use_count() const { return m_track.use_count(); } - inline - const std::string label() const - { return m_track.template get_label< typename traits::memory_space >(); } + inline const std::string label() const { + return m_track.template get_label(); + } //---------------------------------------- // Allocation according to allocation properties and array layout - template< class ... P > - explicit inline - View( const Impl::ViewCtorProp< P ... > & arg_prop - , typename std::enable_if< ! Impl::ViewCtorProp< P... >::has_pointer - , typename traits::array_layout - >::type const & arg_layout - ) - : m_track() - , m_map() - { - // Append layout and spaces if not input - typedef Impl::ViewCtorProp< P ... > alloc_prop_input ; - - // use 'std::integral_constant' for non-types - // to avoid duplicate class error. - typedef Impl::ViewCtorProp - < P ... - , typename std::conditional - < alloc_prop_input::has_label - , std::integral_constant - , typename std::string - >::type - , typename std::conditional - < alloc_prop_input::has_memory_space - , std::integral_constant - , typename traits::device_type::memory_space - >::type - , typename std::conditional - < alloc_prop_input::has_execution_space - , std::integral_constant - , typename traits::device_type::execution_space - >::type - > alloc_prop ; - - static_assert( traits::is_managed - , "View allocation constructor requires managed memory" ); - - if ( alloc_prop::initialize && + template + explicit inline View( + const Impl::ViewCtorProp& arg_prop, + typename std::enable_if::has_pointer, + typename traits::array_layout>::type const& + arg_layout) + : m_track(), m_map() { + // Append layout and spaces if not input + typedef Impl::ViewCtorProp alloc_prop_input; + + // use 'std::integral_constant' for non-types + // to avoid duplicate class error. + typedef Impl::ViewCtorProp< + P..., + typename std::conditional, + typename std::string>::type, + typename std::conditional< + alloc_prop_input::has_memory_space, + std::integral_constant, + typename traits::device_type::memory_space>::type, + typename std::conditional< + alloc_prop_input::has_execution_space, + std::integral_constant, + typename traits::device_type::execution_space>::type> + alloc_prop; + + static_assert(traits::is_managed, + "View allocation constructor requires managed memory"); + + if (alloc_prop::initialize && #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - ! alloc_prop::execution_space::is_initialized() + !alloc_prop::execution_space::is_initialized() #else - ! alloc_prop::execution_space::impl_is_initialized() + !alloc_prop::execution_space::impl_is_initialized() #endif - ) { - // If initializing view data then - // the execution space must be initialized. - Kokkos::Impl::throw_runtime_exception("Constructing View and initializing data with uninitialized execution space"); - } + ) { + // If initializing view data then + // the execution space must be initialized. + Kokkos::Impl::throw_runtime_exception( + "Constructing View and initializing data with uninitialized " + "execution space"); + } - // Copy the input allocation properties with possibly defaulted properties - alloc_prop prop_copy( arg_prop ); + // Copy the input allocation properties with possibly defaulted properties + alloc_prop prop_copy(arg_prop); //------------------------------------------------------------ -#if defined( KOKKOS_ENABLE_CUDA ) - // If allocating in CudaUVMSpace must fence before and after - // the allocation to protect against possible concurrent access - // on the CPU and the GPU. - // Fence using the trait's executon space (which will be Kokkos::Cuda) - // to avoid incomplete type errors from usng Kokkos::Cuda directly. - if ( std::is_same< Kokkos::CudaUVMSpace , typename traits::device_type::memory_space >::value ) { - typename traits::device_type::memory_space::execution_space().fence(); - } +#if defined(KOKKOS_ENABLE_CUDA) + // If allocating in CudaUVMSpace must fence before and after + // the allocation to protect against possible concurrent access + // on the CPU and the GPU. + // Fence using the trait's executon space (which will be Kokkos::Cuda) + // to avoid incomplete type errors from usng Kokkos::Cuda directly. + if (std::is_same::value) { + typename traits::device_type::memory_space::execution_space().fence(); + } #endif -//------------------------------------------------------------ + //------------------------------------------------------------ - Kokkos::Impl::SharedAllocationRecord<> * - record = m_map.allocate_shared( prop_copy , arg_layout ); + Kokkos::Impl::SharedAllocationRecord<>* record = + m_map.allocate_shared(prop_copy, arg_layout); //------------------------------------------------------------ -#if defined( KOKKOS_ENABLE_CUDA ) - if ( std::is_same< Kokkos::CudaUVMSpace , typename traits::device_type::memory_space >::value ) { - typename traits::device_type::memory_space::execution_space().fence(); - } +#if defined(KOKKOS_ENABLE_CUDA) + if (std::is_same::value) { + typename traits::device_type::memory_space::execution_space().fence(); + } #endif -//------------------------------------------------------------ + //------------------------------------------------------------ - // Setup and initialization complete, start tracking - m_track.assign_allocated_record_to_uninitialized( record ); - } + // Setup and initialization complete, start tracking + m_track.assign_allocated_record_to_uninitialized(record); + } KOKKOS_INLINE_FUNCTION - void assign_data( pointer_type arg_data ) - { - m_track.clear(); - m_map.assign_data( arg_data ); - } + void assign_data(pointer_type arg_data) { + m_track.clear(); + m_map.assign_data(arg_data); + } // Wrap memory according to properties and array layout - template< class ... P > - explicit KOKKOS_INLINE_FUNCTION - View( const Impl::ViewCtorProp< P ... > & arg_prop - , typename std::enable_if< Impl::ViewCtorProp< P... >::has_pointer - , typename traits::array_layout - >::type const & arg_layout - ) - : m_track() // No memory tracking - , m_map( arg_prop , arg_layout ) - { - static_assert( - std::is_same< pointer_type - , typename Impl::ViewCtorProp< P... >::pointer_type - >::value , - "Constructing View to wrap user memory must supply matching pointer type" ); - } + template + explicit KOKKOS_INLINE_FUNCTION View( + const Impl::ViewCtorProp& arg_prop, + typename std::enable_if::has_pointer, + typename traits::array_layout>::type const& + arg_layout) + : m_track() // No memory tracking + , + m_map(arg_prop, arg_layout) { + static_assert( + std::is_same::pointer_type>::value, + "Constructing View to wrap user memory must supply matching pointer " + "type"); + } // Simple dimension-only layout - template< class ... P > - explicit inline - View( const Impl::ViewCtorProp< P ... > & arg_prop - , typename std::enable_if< ! Impl::ViewCtorProp< P... >::has_pointer - , size_t - >::type const arg_N0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - ) - : View( arg_prop - , typename traits::array_layout - ( arg_N0 , arg_N1 , arg_N2 , arg_N3 - , arg_N4 , arg_N5 , arg_N6 , arg_N7 ) - ) - { + template + explicit inline View( + const Impl::ViewCtorProp& arg_prop, + typename std::enable_if::has_pointer, + size_t>::type const arg_N0 = + KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) + : View(arg_prop, + typename traits::array_layout(arg_N0, arg_N1, arg_N2, arg_N3, + arg_N4, arg_N5, arg_N6, arg_N7)) { #ifdef KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST - Impl::runtime_check_rank_host(traits::rank_dynamic, std::is_same::value, arg_N0, arg_N1, arg_N2, arg_N3, - arg_N4, arg_N5, arg_N6, arg_N7, label()); + Impl::runtime_check_rank_host( + traits::rank_dynamic, + std::is_same::value, arg_N0, arg_N1, + arg_N2, arg_N3, arg_N4, arg_N5, arg_N6, arg_N7, label()); #else - Impl::runtime_check_rank_device(traits::rank_dynamic, std::is_same::value, arg_N0, arg_N1, arg_N2, arg_N3, - arg_N4, arg_N5, arg_N6, arg_N7); + Impl::runtime_check_rank_device( + traits::rank_dynamic, + std::is_same::value, arg_N0, arg_N1, + arg_N2, arg_N3, arg_N4, arg_N5, arg_N6, arg_N7); #endif + } - } - - template< class ... P > - explicit KOKKOS_INLINE_FUNCTION - View( const Impl::ViewCtorProp< P ... > & arg_prop - , typename std::enable_if< Impl::ViewCtorProp< P... >::has_pointer - , size_t - >::type const arg_N0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - ) - : View( arg_prop - , typename traits::array_layout - ( arg_N0 , arg_N1 , arg_N2 , arg_N3 - , arg_N4 , arg_N5 , arg_N6 , arg_N7 ) - ) - { + template + explicit KOKKOS_INLINE_FUNCTION View( + const Impl::ViewCtorProp& arg_prop, + typename std::enable_if::has_pointer, + size_t>::type const arg_N0 = + KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) + : View(arg_prop, + typename traits::array_layout(arg_N0, arg_N1, arg_N2, arg_N3, + arg_N4, arg_N5, arg_N6, arg_N7)) { #ifdef KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST - Impl::runtime_check_rank_host(traits::rank_dynamic, std::is_same::value, arg_N0, arg_N1, arg_N2, arg_N3, - arg_N4, arg_N5, arg_N6, arg_N7, label()); + Impl::runtime_check_rank_host( + traits::rank_dynamic, + std::is_same::value, arg_N0, arg_N1, + arg_N2, arg_N3, arg_N4, arg_N5, arg_N6, arg_N7, label()); #else - Impl::runtime_check_rank_device(traits::rank_dynamic, std::is_same::value, arg_N0, arg_N1, arg_N2, arg_N3, - arg_N4, arg_N5, arg_N6, arg_N7); + Impl::runtime_check_rank_device( + traits::rank_dynamic, + std::is_same::value, arg_N0, arg_N1, + arg_N2, arg_N3, arg_N4, arg_N5, arg_N6, arg_N7); #endif - - } + } // Allocate with label and layout - template< typename Label > - explicit inline - View( const Label & arg_label - , typename std::enable_if< - Kokkos::Impl::is_view_label