"platforms/cuda/vscode:/vscode.git/clone" did not exist on "5b017677e1add9ac33b318c73fad21c04ff93287"
Commit 2f553a66 authored by Peter Eastman's avatar Peter Eastman
Browse files

Continuing to refactor tests

parent 4ed151e1
positions[0] = Vec3(0.230000,0.628000,0.113000);
positions[1] = Vec3(0.137000,0.626000,0.150000);
positions[2] = Vec3(0.231000,0.589000,0.021000);
positions[3] = Vec3(0.225000,0.275000,-0.866000);
positions[4] = Vec3(0.260000,0.258000,-0.774000);
positions[5] = Vec3(0.137000,0.230000,-0.878000);
positions[6] = Vec3(0.019000,0.368000,0.647000);
positions[7] = Vec3(-0.063000,0.411000,0.686000);
positions[8] = Vec3(-0.009000,0.295000,0.584000);
positions[9] = Vec3(0.569000,-0.587000,-0.697000);
positions[10] = Vec3(0.476000,-0.594000,-0.734000);
positions[11] = Vec3(0.580000,-0.498000,-0.653000);
positions[12] = Vec3(-0.307000,-0.351000,0.703000);
positions[13] = Vec3(-0.364000,-0.367000,0.784000);
positions[14] = Vec3(-0.366000,-0.341000,0.623000);
positions[15] = Vec3(-0.119000,0.618000,0.856000);
positions[16] = Vec3(-0.086000,0.712000,0.856000);
positions[17] = Vec3(-0.068000,0.564000,0.922000);
positions[18] = Vec3(-0.727000,0.703000,0.717000);
positions[19] = Vec3(-0.670000,0.781000,0.692000);
positions[20] = Vec3(-0.787000,0.729000,0.793000);
positions[21] = Vec3(-0.107000,0.607000,0.231000);
positions[22] = Vec3(-0.119000,0.594000,0.132000);
positions[23] = Vec3(-0.137000,0.526000,0.280000);
positions[24] = Vec3(0.768000,-0.718000,-0.839000);
positions[25] = Vec3(0.690000,-0.701000,-0.779000);
positions[26] = Vec3(0.802000,-0.631000,-0.875000);
positions[27] = Vec3(0.850000,0.798000,-0.039000);
positions[28] = Vec3(0.846000,0.874000,0.026000);
positions[29] = Vec3(0.872000,0.834000,-0.130000);
positions[30] = Vec3(0.685000,-0.850000,0.665000);
positions[31] = Vec3(0.754000,-0.866000,0.735000);
positions[32] = Vec3(0.612000,-0.793000,0.703000);
positions[33] = Vec3(0.686000,-0.701000,-0.059000);
positions[34] = Vec3(0.746000,-0.622000,-0.045000);
positions[35] = Vec3(0.600000,-0.670000,-0.100000);
positions[36] = Vec3(0.335000,-0.427000,-0.801000);
positions[37] = Vec3(0.257000,-0.458000,-0.854000);
positions[38] = Vec3(0.393000,-0.369000,-0.858000);
positions[39] = Vec3(-0.402000,-0.357000,-0.523000);
positions[40] = Vec3(-0.378000,-0.263000,-0.497000);
positions[41] = Vec3(-0.418000,-0.411000,-0.441000);
positions[42] = Vec3(0.438000,0.392000,-0.363000);
positions[43] = Vec3(0.520000,0.336000,-0.354000);
positions[44] = Vec3(0.357000,0.334000,-0.359000);
positions[45] = Vec3(-0.259000,0.447000,0.737000);
positions[46] = Vec3(-0.333000,0.493000,0.687000);
positions[47] = Vec3(-0.208000,0.515000,0.790000);
positions[48] = Vec3(0.231000,-0.149000,0.483000);
positions[49] = Vec3(0.265000,-0.072000,0.537000);
positions[50] = Vec3(0.275000,-0.149000,0.393000);
positions[51] = Vec3(-0.735000,-0.521000,-0.172000);
positions[52] = Vec3(-0.688000,-0.521000,-0.084000);
positions[53] = Vec3(-0.783000,-0.608000,-0.183000);
positions[54] = Vec3(0.230000,-0.428000,0.538000);
positions[55] = Vec3(0.204000,-0.332000,0.538000);
positions[56] = Vec3(0.159000,-0.482000,0.583000);
positions[57] = Vec3(0.240000,-0.771000,0.886000);
positions[58] = Vec3(0.254000,-0.855000,0.938000);
positions[59] = Vec3(0.185000,-0.707000,0.941000);
positions[60] = Vec3(0.620000,-0.076000,-0.423000);
positions[61] = Vec3(0.528000,-0.093000,-0.388000);
positions[62] = Vec3(0.648000,0.016000,-0.397000);
positions[63] = Vec3(0.606000,-0.898000,0.123000);
positions[64] = Vec3(0.613000,-0.814000,0.069000);
positions[65] = Vec3(0.652000,-0.885000,0.211000);
positions[66] = Vec3(-0.268000,0.114000,-0.382000);
positions[67] = Vec3(-0.286000,0.181000,-0.454000);
positions[68] = Vec3(-0.271000,0.160000,-0.293000);
positions[69] = Vec3(0.122000,0.643000,0.563000);
positions[70] = Vec3(0.077000,0.555000,0.580000);
positions[71] = Vec3(0.121000,0.697000,0.647000);
positions[72] = Vec3(-0.020000,-0.095000,0.359000);
positions[73] = Vec3(0.034000,-0.124000,0.439000);
positions[74] = Vec3(0.010000,-0.005000,0.330000);
positions[75] = Vec3(0.027000,-0.266000,0.117000);
positions[76] = Vec3(0.008000,-0.362000,0.138000);
positions[77] = Vec3(-0.006000,-0.208000,0.192000);
positions[78] = Vec3(-0.173000,0.922000,0.612000);
positions[79] = Vec3(-0.078000,0.893000,0.620000);
positions[80] = Vec3(-0.181000,0.987000,0.537000);
positions[81] = Vec3(-0.221000,-0.754000,0.432000);
positions[82] = Vec3(-0.135000,-0.752000,0.380000);
positions[83] = Vec3(-0.207000,-0.707000,0.520000);
positions[84] = Vec3(0.113000,0.737000,-0.265000);
positions[85] = Vec3(0.201000,0.724000,-0.220000);
positions[86] = Vec3(0.100000,0.834000,-0.287000);
positions[87] = Vec3(0.613000,-0.497000,0.726000);
positions[88] = Vec3(0.564000,-0.584000,0.735000);
positions[89] = Vec3(0.590000,-0.454000,0.639000);
positions[90] = Vec3(-0.569000,-0.634000,-0.439000);
positions[91] = Vec3(-0.532000,-0.707000,-0.497000);
positions[92] = Vec3(-0.517000,-0.629000,-0.354000);
positions[93] = Vec3(0.809000,0.004000,0.502000);
positions[94] = Vec3(0.849000,0.095000,0.493000);
positions[95] = Vec3(0.709000,0.012000,0.508000);
positions[96] = Vec3(0.197000,-0.886000,-0.598000);
positions[97] = Vec3(0.286000,-0.931000,-0.612000);
positions[98] = Vec3(0.124000,-0.951000,-0.617000);
positions[99] = Vec3(-0.337000,-0.863000,0.190000);
positions[100] = Vec3(-0.400000,-0.939000,0.203000);
positions[101] = Vec3(-0.289000,-0.845000,0.276000);
positions[102] = Vec3(-0.675000,-0.070000,-0.246000);
positions[103] = Vec3(-0.651000,-0.010000,-0.322000);
positions[104] = Vec3(-0.668000,-0.165000,-0.276000);
positions[105] = Vec3(0.317000,0.251000,-0.061000);
positions[106] = Vec3(0.388000,0.322000,-0.055000);
positions[107] = Vec3(0.229000,0.290000,-0.033000);
positions[108] = Vec3(-0.396000,-0.445000,-0.909000);
positions[109] = Vec3(-0.455000,-0.439000,-0.829000);
positions[110] = Vec3(-0.411000,-0.533000,-0.955000);
positions[111] = Vec3(-0.195000,-0.148000,0.572000);
positions[112] = Vec3(-0.236000,-0.171000,0.484000);
positions[113] = Vec3(-0.213000,-0.222000,0.637000);
positions[114] = Vec3(0.598000,0.729000,0.270000);
positions[115] = Vec3(0.622000,0.798000,0.202000);
positions[116] = Vec3(0.520000,0.762000,0.324000);
positions[117] = Vec3(-0.581000,0.345000,-0.918000);
positions[118] = Vec3(-0.667000,0.295000,-0.931000);
positions[119] = Vec3(-0.519000,0.291000,-0.862000);
positions[120] = Vec3(-0.286000,-0.200000,0.307000);
positions[121] = Vec3(-0.197000,-0.154000,0.310000);
positions[122] = Vec3(-0.307000,-0.224000,0.212000);
positions[123] = Vec3(0.807000,0.605000,-0.397000);
positions[124] = Vec3(0.760000,0.602000,-0.308000);
positions[125] = Vec3(0.756000,0.550000,-0.463000);
positions[126] = Vec3(-0.468000,0.469000,-0.188000);
positions[127] = Vec3(-0.488000,0.512000,-0.100000);
positions[128] = Vec3(-0.390000,0.407000,-0.179000);
positions[129] = Vec3(-0.889000,0.890000,-0.290000);
positions[130] = Vec3(-0.843000,0.806000,-0.319000);
positions[131] = Vec3(-0.945000,0.924000,-0.365000);
positions[132] = Vec3(-0.871000,0.410000,-0.620000);
positions[133] = Vec3(-0.948000,0.444000,-0.566000);
positions[134] = Vec3(-0.905000,0.359000,-0.699000);
positions[135] = Vec3(-0.821000,0.701000,0.429000);
positions[136] = Vec3(-0.795000,0.697000,0.525000);
positions[137] = Vec3(-0.906000,0.650000,0.415000);
positions[138] = Vec3(0.076000,0.811000,0.789000);
positions[139] = Vec3(0.175000,0.799000,0.798000);
positions[140] = Vec3(0.052000,0.906000,0.810000);
positions[141] = Vec3(0.130000,-0.041000,-0.291000);
positions[142] = Vec3(0.120000,-0.056000,-0.192000);
positions[143] = Vec3(0.044000,-0.005000,-0.327000);
positions[144] = Vec3(0.865000,0.348000,0.195000);
positions[145] = Vec3(0.924000,0.411000,0.146000);
positions[146] = Vec3(0.884000,0.254000,0.166000);
positions[147] = Vec3(-0.143000,0.585000,-0.031000);
positions[148] = Vec3(-0.169000,0.674000,-0.067000);
positions[149] = Vec3(-0.145000,0.517000,-0.104000);
positions[150] = Vec3(-0.500000,-0.718000,0.545000);
positions[151] = Vec3(-0.417000,-0.747000,0.497000);
positions[152] = Vec3(-0.549000,-0.651000,0.489000);
positions[153] = Vec3(0.550000,0.196000,0.885000);
positions[154] = Vec3(0.545000,0.191000,0.985000);
positions[155] = Vec3(0.552000,0.292000,0.856000);
positions[156] = Vec3(-0.854000,-0.406000,0.477000);
positions[157] = Vec3(-0.900000,-0.334000,0.425000);
positions[158] = Vec3(-0.858000,-0.386000,0.575000);
positions[159] = Vec3(0.351000,-0.061000,0.853000);
positions[160] = Vec3(0.401000,-0.147000,0.859000);
positions[161] = Vec3(0.416000,0.016000,0.850000);
positions[162] = Vec3(-0.067000,-0.796000,0.873000);
positions[163] = Vec3(-0.129000,-0.811000,0.797000);
positions[164] = Vec3(-0.119000,-0.785000,0.958000);
positions[165] = Vec3(-0.635000,-0.312000,-0.356000);
positions[166] = Vec3(-0.629000,-0.389000,-0.292000);
positions[167] = Vec3(-0.687000,-0.338000,-0.436000);
positions[168] = Vec3(0.321000,-0.919000,0.242000);
positions[169] = Vec3(0.403000,-0.880000,0.200000);
positions[170] = Vec3(0.294000,-1.001000,0.193000);
positions[171] = Vec3(-0.404000,0.735000,0.728000);
positions[172] = Vec3(-0.409000,0.670000,0.803000);
positions[173] = Vec3(-0.324000,0.794000,0.741000);
positions[174] = Vec3(0.461000,-0.596000,-0.135000);
positions[175] = Vec3(0.411000,-0.595000,-0.221000);
positions[176] = Vec3(0.398000,-0.614000,-0.059000);
positions[177] = Vec3(-0.751000,-0.086000,0.237000);
positions[178] = Vec3(-0.811000,-0.148000,0.287000);
positions[179] = Vec3(-0.720000,-0.130000,0.152000);
positions[180] = Vec3(0.202000,0.285000,-0.364000);
positions[181] = Vec3(0.122000,0.345000,-0.377000);
positions[182] = Vec3(0.192000,0.236000,-0.278000);
positions[183] = Vec3(-0.230000,-0.485000,0.081000);
positions[184] = Vec3(-0.262000,-0.391000,0.071000);
positions[185] = Vec3(-0.306000,-0.548000,0.069000);
positions[186] = Vec3(0.464000,-0.119000,0.323000);
positions[187] = Vec3(0.497000,-0.080000,0.409000);
positions[188] = Vec3(0.540000,-0.126000,0.258000);
positions[189] = Vec3(-0.462000,0.107000,0.426000);
positions[190] = Vec3(-0.486000,0.070000,0.336000);
positions[191] = Vec3(-0.363000,0.123000,0.430000);
positions[192] = Vec3(0.249000,-0.077000,-0.621000);
positions[193] = Vec3(0.306000,-0.142000,-0.571000);
positions[194] = Vec3(0.233000,-0.110000,-0.714000);
positions[195] = Vec3(-0.922000,-0.164000,0.904000);
positions[196] = Vec3(-0.842000,-0.221000,0.925000);
positions[197] = Vec3(-0.971000,-0.204000,0.827000);
positions[198] = Vec3(0.382000,0.700000,0.480000);
positions[199] = Vec3(0.427000,0.610000,0.477000);
positions[200] = Vec3(0.288000,0.689000,0.513000);
positions[201] = Vec3(-0.315000,0.222000,-0.133000);
positions[202] = Vec3(-0.320000,0.259000,-0.041000);
positions[203] = Vec3(-0.387000,0.153000,-0.145000);
positions[204] = Vec3(0.614000,0.122000,0.117000);
positions[205] = Vec3(0.712000,0.100000,0.124000);
positions[206] = Vec3(0.583000,0.105000,0.024000);
positions[207] = Vec3(0.781000,0.264000,-0.113000);
positions[208] = Vec3(0.848000,0.203000,-0.070000);
positions[209] = Vec3(0.708000,0.283000,-0.048000);
positions[210] = Vec3(0.888000,-0.348000,-0.667000);
positions[211] = Vec3(0.865000,-0.373000,-0.761000);
positions[212] = Vec3(0.949000,-0.417000,-0.628000);
positions[213] = Vec3(-0.511000,0.590000,-0.429000);
positions[214] = Vec3(-0.483000,0.547000,-0.344000);
positions[215] = Vec3(-0.486000,0.686000,-0.428000);
positions[216] = Vec3(0.803000,-0.460000,0.924000);
positions[217] = Vec3(0.893000,-0.446000,0.882000);
positions[218] = Vec3(0.732000,-0.458000,0.853000);
positions[219] = Vec3(0.922000,0.503000,0.899000);
positions[220] = Vec3(0.897000,0.494000,0.803000);
positions[221] = Vec3(0.970000,0.421000,0.930000);
positions[222] = Vec3(0.539000,0.064000,0.512000);
positions[223] = Vec3(0.458000,0.065000,0.570000);
positions[224] = Vec3(0.542000,0.147000,0.457000);
positions[225] = Vec3(-0.428000,-0.674000,0.041000);
positions[226] = Vec3(-0.396000,-0.750000,0.098000);
positions[227] = Vec3(-0.520000,-0.647000,0.071000);
positions[228] = Vec3(0.297000,0.035000,0.171000);
positions[229] = Vec3(0.346000,0.119000,0.150000);
positions[230] = Vec3(0.359000,-0.030000,0.216000);
positions[231] = Vec3(-0.927000,0.236000,0.480000);
positions[232] = Vec3(-0.975000,0.277000,0.402000);
positions[233] = Vec3(-0.828000,0.234000,0.461000);
positions[234] = Vec3(-0.786000,0.683000,-0.398000);
positions[235] = Vec3(-0.866000,0.622000,-0.395000);
positions[236] = Vec3(-0.705000,0.630000,-0.422000);
positions[237] = Vec3(-0.635000,-0.292000,0.793000);
positions[238] = Vec3(-0.614000,-0.218000,0.728000);
positions[239] = Vec3(-0.567000,-0.292000,0.866000);
positions[240] = Vec3(0.459000,-0.710000,0.741000);
positions[241] = Vec3(0.388000,-0.737000,0.806000);
positions[242] = Vec3(0.433000,-0.738000,0.648000);
positions[243] = Vec3(-0.591000,-0.065000,0.591000);
positions[244] = Vec3(-0.547000,-0.001000,0.527000);
positions[245] = Vec3(-0.641000,-0.013000,0.661000);
positions[246] = Vec3(-0.830000,0.549000,0.016000);
positions[247] = Vec3(-0.871000,0.631000,-0.023000);
positions[248] = Vec3(-0.766000,0.575000,0.089000);
positions[249] = Vec3(0.078000,0.556000,-0.476000);
positions[250] = Vec3(0.170000,0.555000,-0.517000);
positions[251] = Vec3(0.072000,0.630000,-0.409000);
positions[252] = Vec3(0.561000,0.222000,-0.715000);
positions[253] = Vec3(0.599000,0.138000,-0.678000);
positions[254] = Vec3(0.473000,0.241000,-0.671000);
positions[255] = Vec3(0.866000,0.454000,0.642000);
positions[256] = Vec3(0.834000,0.526000,0.580000);
positions[257] = Vec3(0.890000,0.373000,0.589000);
positions[258] = Vec3(-0.845000,0.039000,0.753000);
positions[259] = Vec3(-0.917000,0.044000,0.684000);
positions[260] = Vec3(-0.869000,-0.030000,0.822000);
positions[261] = Vec3(-0.433000,-0.689000,0.867000);
positions[262] = Vec3(-0.488000,-0.773000,0.860000);
positions[263] = Vec3(-0.407000,-0.660000,0.775000);
positions[264] = Vec3(-0.396000,0.590000,-0.870000);
positions[265] = Vec3(-0.426000,0.495000,-0.863000);
positions[266] = Vec3(-0.323000,0.606000,-0.804000);
positions[267] = Vec3(-0.005000,0.833000,0.377000);
positions[268] = Vec3(0.037000,0.769000,0.441000);
positions[269] = Vec3(-0.043000,0.782000,0.299000);
positions[270] = Vec3(0.488000,-0.477000,0.174000);
positions[271] = Vec3(0.401000,-0.492000,0.221000);
positions[272] = Vec3(0.471000,-0.451000,0.079000);
positions[273] = Vec3(-0.198000,-0.582000,0.657000);
positions[274] = Vec3(-0.099000,-0.574000,0.671000);
positions[275] = Vec3(-0.243000,-0.498000,0.688000);
positions[276] = Vec3(-0.472000,0.575000,0.078000);
positions[277] = Vec3(-0.526000,0.554000,0.159000);
positions[278] = Vec3(-0.381000,0.534000,0.087000);
positions[279] = Vec3(0.527000,0.256000,0.328000);
positions[280] = Vec3(0.554000,0.197000,0.253000);
positions[281] = Vec3(0.527000,0.351000,0.297000);
positions[282] = Vec3(-0.108000,-0.639000,-0.274000);
positions[283] = Vec3(-0.017000,-0.678000,-0.287000);
positions[284] = Vec3(-0.100000,-0.543000,-0.250000);
positions[285] = Vec3(-0.798000,-0.515000,-0.522000);
positions[286] = Vec3(-0.878000,-0.538000,-0.467000);
positions[287] = Vec3(-0.715000,-0.541000,-0.473000);
positions[288] = Vec3(-0.270000,-0.233000,-0.237000);
positions[289] = Vec3(-0.243000,-0.199000,-0.327000);
positions[290] = Vec3(-0.191000,-0.271000,-0.191000);
positions[291] = Vec3(-0.751000,-0.667000,-0.762000);
positions[292] = Vec3(-0.791000,-0.623000,-0.681000);
positions[293] = Vec3(-0.792000,-0.630000,-0.845000);
positions[294] = Vec3(-0.224000,-0.763000,-0.783000);
positions[295] = Vec3(-0.219000,-0.682000,-0.724000);
positions[296] = Vec3(-0.310000,-0.761000,-0.834000);
positions[297] = Vec3(0.915000,0.089000,-0.460000);
positions[298] = Vec3(0.940000,0.069000,-0.555000);
positions[299] = Vec3(0.987000,0.145000,-0.418000);
positions[300] = Vec3(-0.882000,-0.746000,-0.143000);
positions[301] = Vec3(-0.981000,-0.740000,-0.133000);
positions[302] = Vec3(-0.859000,-0.826000,-0.199000);
positions[303] = Vec3(0.705000,-0.812000,0.368000);
positions[304] = Vec3(0.691000,-0.805000,0.467000);
positions[305] = Vec3(0.789000,-0.863000,0.350000);
positions[306] = Vec3(0.410000,0.813000,-0.611000);
positions[307] = Vec3(0.496000,0.825000,-0.561000);
positions[308] = Vec3(0.368000,0.726000,-0.584000);
positions[309] = Vec3(-0.588000,0.386000,-0.600000);
positions[310] = Vec3(-0.567000,0.460000,-0.536000);
positions[311] = Vec3(-0.677000,0.403000,-0.643000);
positions[312] = Vec3(0.064000,-0.298000,-0.531000);
positions[313] = Vec3(0.018000,-0.216000,-0.565000);
positions[314] = Vec3(0.162000,-0.279000,-0.522000);
positions[315] = Vec3(0.367000,-0.762000,0.501000);
positions[316] = Vec3(0.360000,-0.679000,0.445000);
positions[317] = Vec3(0.371000,-0.842000,0.441000);
positions[318] = Vec3(0.566000,0.537000,0.865000);
positions[319] = Vec3(0.578000,0.603000,0.791000);
positions[320] = Vec3(0.612000,0.571000,0.948000);
positions[321] = Vec3(-0.610000,-0.514000,0.388000);
positions[322] = Vec3(-0.560000,-0.437000,0.428000);
positions[323] = Vec3(-0.705000,-0.512000,0.420000);
positions[324] = Vec3(-0.590000,-0.417000,-0.720000);
positions[325] = Vec3(-0.543000,-0.404000,-0.633000);
positions[326] = Vec3(-0.656000,-0.491000,-0.711000);
positions[327] = Vec3(-0.280000,0.639000,0.472000);
positions[328] = Vec3(-0.311000,0.700000,0.545000);
positions[329] = Vec3(-0.230000,0.691000,0.403000);
positions[330] = Vec3(0.354000,-0.352000,-0.533000);
positions[331] = Vec3(0.333000,-0.396000,-0.620000);
positions[332] = Vec3(0.451000,-0.326000,-0.530000);
positions[333] = Vec3(0.402000,0.751000,-0.264000);
positions[334] = Vec3(0.470000,0.806000,-0.311000);
positions[335] = Vec3(0.442000,0.663000,-0.237000);
positions[336] = Vec3(-0.275000,0.779000,-0.192000);
positions[337] = Vec3(-0.367000,0.817000,-0.197000);
positions[338] = Vec3(-0.215000,0.826000,-0.257000);
positions[339] = Vec3(-0.849000,0.105000,-0.092000);
positions[340] = Vec3(-0.843000,0.190000,-0.144000);
positions[341] = Vec3(-0.817000,0.029000,-0.149000);
positions[342] = Vec3(0.504000,0.050000,-0.122000);
positions[343] = Vec3(0.462000,-0.007000,-0.192000);
positions[344] = Vec3(0.438000,0.119000,-0.090000);
positions[345] = Vec3(0.573000,0.870000,-0.833000);
positions[346] = Vec3(0.617000,0.959000,-0.842000);
positions[347] = Vec3(0.510000,0.870000,-0.756000);
positions[348] = Vec3(-0.502000,0.862000,-0.817000);
positions[349] = Vec3(-0.577000,0.862000,-0.883000);
positions[350] = Vec3(-0.465000,0.770000,-0.808000);
positions[351] = Vec3(-0.653000,0.525000,0.275000);
positions[352] = Vec3(-0.640000,0.441000,0.329000);
positions[353] = Vec3(-0.682000,0.599000,0.335000);
positions[354] = Vec3(0.307000,0.213000,-0.631000);
positions[355] = Vec3(0.284000,0.250000,-0.541000);
positions[356] = Vec3(0.277000,0.118000,-0.637000);
positions[357] = Vec3(0.037000,-0.552000,-0.580000);
positions[358] = Vec3(0.090000,-0.601000,-0.512000);
positions[359] = Vec3(0.059000,-0.454000,-0.575000);
positions[360] = Vec3(0.732000,0.634000,-0.798000);
positions[361] = Vec3(0.791000,0.608000,-0.874000);
positions[362] = Vec3(0.704000,0.730000,-0.809000);
positions[363] = Vec3(-0.134000,-0.927000,-0.008000);
positions[364] = Vec3(-0.180000,-0.934000,-0.097000);
positions[365] = Vec3(-0.196000,-0.883000,0.058000);
positions[366] = Vec3(0.307000,0.063000,0.618000);
positions[367] = Vec3(0.296000,0.157000,0.651000);
positions[368] = Vec3(0.302000,-0.000000,0.695000);
positions[369] = Vec3(-0.240000,0.367000,0.374000);
positions[370] = Vec3(-0.238000,0.291000,0.438000);
positions[371] = Vec3(-0.288000,0.444000,0.414000);
positions[372] = Vec3(-0.839000,0.766000,-0.896000);
positions[373] = Vec3(-0.824000,0.787000,-0.800000);
positions[374] = Vec3(-0.869000,0.671000,-0.905000);
positions[375] = Vec3(-0.882000,-0.289000,-0.162000);
positions[376] = Vec3(-0.902000,-0.245000,-0.250000);
positions[377] = Vec3(-0.843000,-0.380000,-0.178000);
positions[378] = Vec3(-0.003000,-0.344000,-0.257000);
positions[379] = Vec3(0.011000,-0.317000,-0.352000);
positions[380] = Vec3(0.080000,-0.322000,-0.204000);
positions[381] = Vec3(0.350000,0.898000,-0.058000);
positions[382] = Vec3(0.426000,0.942000,-0.010000);
positions[383] = Vec3(0.385000,0.851000,-0.140000);
positions[384] = Vec3(-0.322000,0.274000,0.125000);
positions[385] = Vec3(-0.383000,0.199000,0.148000);
positions[386] = Vec3(-0.300000,0.326000,0.208000);
positions[387] = Vec3(-0.559000,0.838000,0.042000);
positions[388] = Vec3(-0.525000,0.745000,0.057000);
positions[389] = Vec3(-0.541000,0.865000,-0.053000);
positions[390] = Vec3(-0.794000,-0.529000,0.849000);
positions[391] = Vec3(-0.787000,-0.613000,0.794000);
positions[392] = Vec3(-0.732000,-0.460000,0.813000);
positions[393] = Vec3(0.319000,0.810000,-0.913000);
positions[394] = Vec3(0.412000,0.846000,-0.908000);
positions[395] = Vec3(0.313000,0.725000,-0.861000);
positions[396] = Vec3(0.339000,0.509000,-0.856000);
positions[397] = Vec3(0.287000,0.426000,-0.873000);
positions[398] = Vec3(0.416000,0.514000,-0.920000);
positions[399] = Vec3(0.511000,0.415000,-0.054000);
positions[400] = Vec3(0.493000,0.460000,0.034000);
positions[401] = Vec3(0.553000,0.480000,-0.117000);
positions[402] = Vec3(-0.724000,0.380000,-0.184000);
positions[403] = Vec3(-0.769000,0.443000,-0.120000);
positions[404] = Vec3(-0.631000,0.411000,-0.201000);
positions[405] = Vec3(-0.702000,0.207000,-0.385000);
positions[406] = Vec3(-0.702000,0.271000,-0.308000);
positions[407] = Vec3(-0.674000,0.255000,-0.468000);
positions[408] = Vec3(0.008000,-0.536000,0.200000);
positions[409] = Vec3(-0.085000,-0.515000,0.169000);
positions[410] = Vec3(0.018000,-0.635000,0.213000);
positions[411] = Vec3(0.088000,-0.061000,0.927000);
positions[412] = Vec3(0.046000,-0.147000,0.900000);
positions[413] = Vec3(0.182000,-0.058000,0.893000);
positions[414] = Vec3(0.504000,-0.294000,0.910000);
positions[415] = Vec3(0.570000,-0.220000,0.919000);
positions[416] = Vec3(0.548000,-0.373000,0.868000);
positions[417] = Vec3(-0.860000,0.796000,-0.624000);
positions[418] = Vec3(-0.819000,0.764000,-0.538000);
positions[419] = Vec3(-0.956000,0.769000,-0.627000);
positions[420] = Vec3(0.040000,0.544000,-0.748000);
positions[421] = Vec3(0.125000,0.511000,-0.789000);
positions[422] = Vec3(0.053000,0.559000,-0.650000);
positions[423] = Vec3(0.189000,0.520000,-0.140000);
positions[424] = Vec3(0.248000,0.480000,-0.210000);
positions[425] = Vec3(0.131000,0.591000,-0.181000);
positions[426] = Vec3(-0.493000,-0.912000,-0.202000);
positions[427] = Vec3(-0.454000,-0.823000,-0.182000);
positions[428] = Vec3(-0.483000,-0.932000,-0.299000);
positions[429] = Vec3(0.815000,0.572000,0.325000);
positions[430] = Vec3(0.822000,0.483000,0.279000);
positions[431] = Vec3(0.721000,0.606000,0.317000);
positions[432] = Vec3(-0.205000,0.604000,-0.656000);
positions[433] = Vec3(-0.243000,0.535000,-0.594000);
positions[434] = Vec3(-0.123000,0.568000,-0.700000);
positions[435] = Vec3(0.252000,-0.298000,-0.118000);
positions[436] = Vec3(0.222000,-0.241000,-0.042000);
positions[437] = Vec3(0.245000,-0.395000,-0.092000);
positions[438] = Vec3(0.671000,0.464000,-0.593000);
positions[439] = Vec3(0.637000,0.375000,-0.623000);
positions[440] = Vec3(0.697000,0.518000,-0.673000);
positions[441] = Vec3(0.930000,-0.184000,-0.397000);
positions[442] = Vec3(0.906000,-0.202000,-0.492000);
positions[443] = Vec3(0.960000,-0.090000,-0.387000);
positions[444] = Vec3(0.473000,0.500000,0.191000);
positions[445] = Vec3(0.534000,0.580000,0.195000);
positions[446] = Vec3(0.378000,0.531000,0.198000);
positions[447] = Vec3(0.159000,-0.725000,-0.396000);
positions[448] = Vec3(0.181000,-0.786000,-0.320000);
positions[449] = Vec3(0.169000,-0.774000,-0.482000);
positions[450] = Vec3(-0.515000,-0.803000,-0.628000);
positions[451] = Vec3(-0.491000,-0.866000,-0.702000);
positions[452] = Vec3(-0.605000,-0.763000,-0.646000);
positions[453] = Vec3(-0.560000,0.855000,0.309000);
positions[454] = Vec3(-0.646000,0.824000,0.351000);
positions[455] = Vec3(-0.564000,0.841000,0.210000);
positions[456] = Vec3(-0.103000,-0.115000,-0.708000);
positions[457] = Vec3(-0.042000,-0.085000,-0.781000);
positions[458] = Vec3(-0.141000,-0.204000,-0.730000);
positions[459] = Vec3(-0.610000,-0.131000,-0.734000);
positions[460] = Vec3(-0.526000,-0.126000,-0.788000);
positions[461] = Vec3(-0.633000,-0.227000,-0.716000);
positions[462] = Vec3(0.083000,-0.604000,-0.840000);
positions[463] = Vec3(0.078000,-0.605000,-0.740000);
positions[464] = Vec3(0.000000,-0.645000,-0.878000);
positions[465] = Vec3(0.688000,-0.200000,-0.146000);
positions[466] = Vec3(0.632000,-0.119000,-0.137000);
positions[467] = Vec3(0.740000,-0.196000,-0.232000);
positions[468] = Vec3(0.903000,0.086000,0.133000);
positions[469] = Vec3(0.954000,0.087000,0.047000);
positions[470] = Vec3(0.959000,0.044000,0.204000);
positions[471] = Vec3(-0.136000,0.135000,0.523000);
positions[472] = Vec3(-0.063000,0.118000,0.456000);
positions[473] = Vec3(-0.167000,0.048000,0.561000);
positions[474] = Vec3(-0.474000,-0.289000,0.477000);
positions[475] = Vec3(-0.407000,-0.277000,0.403000);
positions[476] = Vec3(-0.514000,-0.200000,0.500000);
positions[477] = Vec3(0.130000,-0.068000,-0.011000);
positions[478] = Vec3(0.089000,-0.142000,0.042000);
positions[479] = Vec3(0.194000,-0.017000,0.047000);
positions[480] = Vec3(-0.582000,0.927000,0.672000);
positions[481] = Vec3(-0.522000,0.846000,0.674000);
positions[482] = Vec3(-0.542000,0.996000,0.612000);
positions[483] = Vec3(0.830000,-0.589000,-0.440000);
positions[484] = Vec3(0.825000,-0.556000,-0.345000);
positions[485] = Vec3(0.744000,-0.570000,-0.486000);
positions[486] = Vec3(0.672000,-0.246000,0.154000);
positions[487] = Vec3(0.681000,-0.236000,0.055000);
positions[488] = Vec3(0.632000,-0.335000,0.175000);
positions[489] = Vec3(-0.212000,-0.142000,-0.468000);
positions[490] = Vec3(-0.159000,-0.132000,-0.552000);
positions[491] = Vec3(-0.239000,-0.052000,-0.434000);
positions[492] = Vec3(-0.021000,0.175000,-0.899000);
positions[493] = Vec3(0.018000,0.090000,-0.935000);
positions[494] = Vec3(-0.119000,0.177000,-0.918000);
positions[495] = Vec3(0.263000,0.326000,0.720000);
positions[496] = Vec3(0.184000,0.377000,0.686000);
positions[497] = Vec3(0.254000,0.311000,0.818000);
positions[498] = Vec3(-0.668000,-0.250000,0.031000);
positions[499] = Vec3(-0.662000,-0.343000,0.068000);
positions[500] = Vec3(-0.727000,-0.250000,-0.049000);
positions[501] = Vec3(0.822000,-0.860000,-0.490000);
positions[502] = Vec3(0.862000,-0.861000,-0.582000);
positions[503] = Vec3(0.832000,-0.768000,-0.450000);
positions[504] = Vec3(0.916000,0.910000,0.291000);
positions[505] = Vec3(0.979000,0.948000,0.223000);
positions[506] = Vec3(0.956000,0.827000,0.330000);
positions[507] = Vec3(-0.358000,-0.255000,0.044000);
positions[508] = Vec3(-0.450000,-0.218000,0.051000);
positions[509] = Vec3(-0.320000,-0.235000,-0.046000);
positions[510] = Vec3(0.372000,-0.574000,-0.372000);
positions[511] = Vec3(0.359000,-0.481000,-0.406000);
positions[512] = Vec3(0.288000,-0.626000,-0.385000);
positions[513] = Vec3(-0.248000,-0.570000,-0.573000);
positions[514] = Vec3(-0.188000,-0.567000,-0.493000);
positions[515] = Vec3(-0.323000,-0.506000,-0.560000);
positions[516] = Vec3(-0.823000,-0.764000,0.696000);
positions[517] = Vec3(-0.893000,-0.811000,0.750000);
positions[518] = Vec3(-0.764000,-0.832000,0.653000);
positions[519] = Vec3(-0.848000,0.236000,-0.891000);
positions[520] = Vec3(-0.856000,0.200000,-0.984000);
positions[521] = Vec3(-0.850000,0.160000,-0.826000);
positions[522] = Vec3(0.590000,-0.375000,0.491000);
positions[523] = Vec3(0.632000,-0.433000,0.421000);
positions[524] = Vec3(0.546000,-0.296000,0.447000);
positions[525] = Vec3(-0.153000,0.385000,-0.481000);
positions[526] = Vec3(-0.080000,0.454000,-0.477000);
positions[527] = Vec3(-0.125000,0.310000,-0.540000);
positions[528] = Vec3(0.255000,-0.514000,0.290000);
positions[529] = Vec3(0.159000,-0.513000,0.263000);
positions[530] = Vec3(0.267000,-0.461000,0.374000);
positions[531] = Vec3(0.105000,-0.849000,-0.136000);
positions[532] = Vec3(0.028000,-0.882000,-0.082000);
positions[533] = Vec3(0.190000,-0.879000,-0.094000);
positions[534] = Vec3(0.672000,0.203000,-0.373000);
positions[535] = Vec3(0.762000,0.187000,-0.413000);
positions[536] = Vec3(0.680000,0.208000,-0.274000);
positions[537] = Vec3(0.075000,0.345000,0.033000);
positions[538] = Vec3(-0.017000,0.317000,0.004000);
positions[539] = Vec3(0.106000,0.422000,-0.023000);
positions[540] = Vec3(-0.422000,0.856000,-0.464000);
positions[541] = Vec3(-0.479000,0.908000,-0.527000);
positions[542] = Vec3(-0.326000,0.868000,-0.488000);
positions[543] = Vec3(0.072000,0.166000,0.318000);
positions[544] = Vec3(0.055000,0.249000,0.264000);
positions[545] = Vec3(0.162000,0.129000,0.296000);
positions[546] = Vec3(-0.679000,-0.527000,0.119000);
positions[547] = Vec3(-0.778000,-0.538000,0.121000);
positions[548] = Vec3(-0.645000,-0.512000,0.212000);
positions[549] = Vec3(0.613000,0.842000,-0.431000);
positions[550] = Vec3(0.669000,0.923000,-0.448000);
positions[551] = Vec3(0.672000,0.762000,-0.428000);
positions[552] = Vec3(-0.369000,-0.095000,-0.903000);
positions[553] = Vec3(-0.336000,-0.031000,-0.972000);
positions[554] = Vec3(-0.303000,-0.101000,-0.828000);
positions[555] = Vec3(0.716000,0.565000,-0.154000);
positions[556] = Vec3(0.735000,0.630000,-0.080000);
positions[557] = Vec3(0.776000,0.485000,-0.145000);
positions[558] = Vec3(-0.412000,-0.642000,-0.229000);
positions[559] = Vec3(-0.421000,-0.652000,-0.130000);
positions[560] = Vec3(-0.316000,-0.649000,-0.255000);
positions[561] = Vec3(0.390000,-0.121000,-0.302000);
positions[562] = Vec3(0.299000,-0.080000,-0.304000);
positions[563] = Vec3(0.383000,-0.215000,-0.270000);
positions[564] = Vec3(-0.188000,0.883000,-0.608000);
positions[565] = Vec3(-0.215000,0.794000,-0.645000);
positions[566] = Vec3(-0.187000,0.951000,-0.681000);
positions[567] = Vec3(-0.637000,0.325000,0.449000);
positions[568] = Vec3(-0.572000,0.251000,0.438000);
positions[569] = Vec3(-0.617000,0.375000,0.533000);
positions[570] = Vec3(0.594000,0.745000,0.652000);
positions[571] = Vec3(0.644000,0.830000,0.633000);
positions[572] = Vec3(0.506000,0.747000,0.604000);
positions[573] = Vec3(-0.085000,0.342000,-0.220000);
positions[574] = Vec3(-0.102000,0.373000,-0.314000);
positions[575] = Vec3(-0.169000,0.305000,-0.182000);
positions[576] = Vec3(-0.132000,-0.928000,-0.345000);
positions[577] = Vec3(-0.094000,-0.837000,-0.330000);
positions[578] = Vec3(-0.140000,-0.945000,-0.444000);
positions[579] = Vec3(0.859000,-0.488000,0.016000);
positions[580] = Vec3(0.813000,-0.473000,0.104000);
positions[581] = Vec3(0.903000,-0.403000,-0.014000);
positions[582] = Vec3(0.661000,-0.072000,-0.909000);
positions[583] = Vec3(0.615000,0.016000,-0.922000);
positions[584] = Vec3(0.760000,-0.060000,-0.916000);
positions[585] = Vec3(-0.454000,-0.011000,-0.142000);
positions[586] = Vec3(-0.550000,-0.022000,-0.169000);
positions[587] = Vec3(-0.398000,-0.078000,-0.190000);
positions[588] = Vec3(0.859000,-0.906000,0.861000);
positions[589] = Vec3(0.913000,-0.975000,0.909000);
positions[590] = Vec3(0.827000,-0.837000,0.927000);
positions[591] = Vec3(-0.779000,-0.878000,0.087000);
positions[592] = Vec3(-0.802000,-0.825000,0.005000);
positions[593] = Vec3(-0.698000,-0.934000,0.068000);
positions[594] = Vec3(-0.001000,-0.293000,0.851000);
positions[595] = Vec3(-0.072000,-0.305000,0.781000);
positions[596] = Vec3(0.000000,-0.372000,0.911000);
positions[597] = Vec3(0.221000,-0.548000,-0.018000);
positions[598] = Vec3(0.156000,-0.621000,-0.039000);
positions[599] = Vec3(0.225000,-0.534000,0.080000);
positions[600] = Vec3(0.079000,-0.622000,0.653000);
positions[601] = Vec3(0.078000,-0.669000,0.741000);
positions[602] = Vec3(0.161000,-0.650000,0.602000);
positions[603] = Vec3(0.672000,-0.471000,-0.238000);
positions[604] = Vec3(0.594000,-0.521000,-0.200000);
positions[605] = Vec3(0.669000,-0.376000,-0.207000);
positions[606] = Vec3(-0.038000,0.192000,-0.635000);
positions[607] = Vec3(-0.042000,0.102000,-0.591000);
positions[608] = Vec3(-0.035000,0.181000,-0.734000);
positions[609] = Vec3(0.428000,0.424000,0.520000);
positions[610] = Vec3(0.458000,0.352000,0.458000);
positions[611] = Vec3(0.389000,0.384000,0.603000);
positions[612] = Vec3(-0.157000,-0.375000,-0.758000);
positions[613] = Vec3(-0.250000,-0.400000,-0.785000);
positions[614] = Vec3(-0.131000,-0.425000,-0.676000);
positions[615] = Vec3(0.317000,0.547000,-0.582000);
positions[616] = Vec3(0.355000,0.488000,-0.510000);
positions[617] = Vec3(0.357000,0.521000,-0.670000);
positions[618] = Vec3(0.812000,-0.276000,0.687000);
positions[619] = Vec3(0.844000,-0.266000,0.593000);
positions[620] = Vec3(0.733000,-0.338000,0.689000);
positions[621] = Vec3(-0.438000,0.214000,-0.750000);
positions[622] = Vec3(-0.386000,0.149000,-0.695000);
positions[623] = Vec3(-0.487000,0.277000,-0.689000);
positions[624] = Vec3(-0.861000,0.034000,-0.708000);
positions[625] = Vec3(-0.924000,-0.038000,-0.739000);
positions[626] = Vec3(-0.768000,-0.002000,-0.708000);
positions[627] = Vec3(0.770000,-0.532000,0.301000);
positions[628] = Vec3(0.724000,-0.619000,0.318000);
positions[629] = Vec3(0.861000,-0.535000,0.342000);
positions[630] = Vec3(0.618000,-0.295000,-0.578000);
positions[631] = Vec3(0.613000,-0.213000,-0.521000);
positions[632] = Vec3(0.707000,-0.298000,-0.623000);
positions[633] = Vec3(-0.510000,0.052000,0.168000);
positions[634] = Vec3(-0.475000,0.011000,0.084000);
positions[635] = Vec3(-0.600000,0.014000,0.188000);
positions[636] = Vec3(-0.562000,0.453000,0.691000);
positions[637] = Vec3(-0.621000,0.533000,0.695000);
positions[638] = Vec3(-0.547000,0.418000,0.784000);
positions[639] = Vec3(-0.269000,0.221000,0.882000);
positions[640] = Vec3(-0.353000,0.220000,0.936000);
positions[641] = Vec3(-0.267000,0.304000,0.826000);
positions[642] = Vec3(0.039000,-0.785000,0.300000);
positions[643] = Vec3(0.138000,-0.796000,0.291000);
positions[644] = Vec3(-0.001000,-0.871000,0.332000);
positions[645] = Vec3(0.875000,-0.216000,0.337000);
positions[646] = Vec3(0.798000,-0.251000,0.283000);
positions[647] = Vec3(0.843000,-0.145000,0.399000);
ASSERT_EQUAL_VEC(Vec3( 1.53862e+01, -9.40085e+01, 8.09974e+01), forces1[0], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.16025e+01, 3.42647e+01, 7.90920e+01), forces1[1], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-6.96273e+01, 7.80017e+01, 7.38545e+00), forces1[2], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-9.28843e+01, -1.89277e+01, -2.54913e+02), forces1[3], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.22785e+01, -3.88301e+01, -2.81351e+02), forces1[4], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.09090e+02, 1.75451e+02, -1.29874e+02), forces1[5], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.95616e+02, 5.36132e+02, -4.55554e+02), forces1[6], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.85944e+02, -1.19523e+02, 7.88721e+01), forces1[7], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.13615e+02, -6.17221e+01, 1.57270e+02), forces1[8], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.66977e+01, -6.36326e+01, 1.65651e+02), forces1[9], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.62216e+00, 1.13905e+02, -5.46500e+01), forces1[10], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.21610e+01, 2.96483e+01, -6.34852e+01), forces1[11], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-9.01658e+01, 1.07406e+02, 2.69335e+01), forces1[12], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.14730e+01, 9.63730e+01, 1.37884e+02), forces1[13], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.45980e+02, 2.47183e+01, 1.30466e+02), forces1[14], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 5.15321e+01, 2.08457e+02, 4.15324e+02), forces1[15], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.53856e+02, 6.74890e+01, -7.69439e+01), forces1[16], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.56804e+02, 1.82869e+02, 2.35455e+02), forces1[17], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.78646e+02, 4.16416e+01, -2.55139e+02), forces1[18], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.51530e+01, 3.24295e+01, 1.87664e+01), forces1[19], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.04660e+02, -2.25016e+02, 5.95159e+01), forces1[20], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.93048e+01, 3.22523e+01, 1.06075e+02), forces1[21], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.84792e+01, 1.15745e+02, 9.08190e+01), forces1[22], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 6.22807e+01, -3.30640e+01, 2.38179e+01), forces1[23], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-8.10281e+01, 5.37699e+01, 1.70935e+02), forces1[24], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-6.55507e+01, 2.52756e+02, 1.34829e+02), forces1[25], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-6.62832e+01, -6.20729e+01, -9.53832e+01), forces1[26], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.93262e+01, -8.64360e+01, -9.20284e+01), forces1[27], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.72500e+00, -1.78213e+02, 1.54062e+01), forces1[28], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.46320e+02, 1.93997e+01, -1.06660e+01), forces1[29], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.02138e+01, 1.84585e+02, -1.96791e+02), forces1[30], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.44392e+01, -1.63547e+02, -1.34078e+02), forces1[31], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-6.64487e+01, -1.01917e+02, -2.94291e+01), forces1[32], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.62979e+02, -8.44104e+01, 4.45776e+00), forces1[33], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.37054e+02, -1.64893e+01, 1.62445e+02), forces1[34], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.79879e+02, -1.28158e+02, 1.46225e+02), forces1[35], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.18701e+02, 1.96825e+01, 1.78171e+02), forces1[36], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-6.05936e+01, -1.32890e+02, 3.44742e+01), forces1[37], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.00952e+01, -2.04575e+02, 1.62082e+02), forces1[38], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.48119e+02, -5.51581e+01, 7.61226e+01), forces1[39], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.54706e+02, -7.79318e+01, -1.19613e+02), forces1[40], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.99297e+02, 1.36546e+02, 1.92910e+02), forces1[41], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.30607e+02, 9.45022e+01, -1.15484e+02), forces1[42], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.87492e+01, 3.38234e+01, -1.13593e+02), forces1[43], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.13434e+01, 1.75865e+02, 7.10201e+01), forces1[44], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.98165e+02, -1.81350e+02, -1.38226e+02), forces1[45], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.58294e+02, -1.74709e+02, -1.91109e+02), forces1[46], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.09248e+02, -1.57551e+02, -2.54299e+02), forces1[47], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-9.75881e+01, -1.06801e+02, -8.62635e+01), forces1[48], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.96592e+02, -1.56687e+01, -9.07580e+01), forces1[49], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.07471e+02, -1.59465e+02, 1.41495e+01), forces1[50], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.97824e+02, -1.58296e+01, -3.62499e+01), forces1[51], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.93794e+01, 2.56345e+01, 5.39562e+01), forces1[52], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.00946e+02, 1.34042e+02, 8.37801e+01), forces1[53], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.44101e+01, 1.04507e+02, -7.20338e+00), forces1[54], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.36940e+02, 1.45544e+02, 7.49711e+01), forces1[55], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.50152e+00, 2.02504e+02, 1.20796e+02), forces1[56], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.94096e+02, -4.04458e+01, 5.69722e+01), forces1[57], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-8.39977e+01, -1.51534e+02, -4.73434e+01), forces1[58], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.19892e+01, -9.31361e+01, -3.38910e+01), forces1[59], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-6.17884e+01, 1.00547e+02, -1.33243e+02), forces1[60], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 5.71112e+01, 6.21495e+01, 1.61566e+02), forces1[61], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.56825e+01, 6.35038e+01, -1.08713e+02), forces1[62], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.42227e+02, 2.10144e+02, 1.68761e+02), forces1[63], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.92938e+02, -1.15636e+02, -2.42672e+02), forces1[64], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-6.46946e+01, 1.75845e+02, 2.87636e+01), forces1[65], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 5.35161e+01, -3.00661e+01, -1.51624e+02), forces1[66], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.77087e+01, 1.55190e+02, 2.57432e+01), forces1[67], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-9.98358e+00, -2.76639e+02, -2.72293e+01), forces1[68], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.05003e+02, 1.07560e+02, 3.34506e+01), forces1[69], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 9.18245e+01, -1.75537e+01, -9.57309e+01), forces1[70], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.67253e+02, 5.59922e-01, 1.01207e+02), forces1[71], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.62670e+02, -6.88248e+01, -4.21201e+02), forces1[72], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.18113e+02, -5.78800e+01, -2.27353e+02), forces1[73], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.64922e+00, 9.21166e+01, -8.93683e+01), forces1[74], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.12201e+02, -3.27194e+01, 1.34264e+02), forces1[75], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 6.44131e+01, -7.40189e+01, 1.05403e+02), forces1[76], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.25775e+01, -1.36797e+02, 2.73836e+02), forces1[77], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.10304e+01, 7.16395e+01, 4.68672e+02), forces1[78], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.93444e+01, -2.15029e+02, -6.63119e+01), forces1[79], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.55389e+02, -3.73611e+02, 1.19751e+02), forces1[80], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.45909e+02, -1.24787e+02, 3.49148e+01), forces1[81], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.32739e+01, 2.95694e+02, -5.37526e+01), forces1[82], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.54390e+02, 4.53455e+02, -2.26764e+02), forces1[83], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.41532e+02, 4.99625e+01, -2.51478e+02), forces1[84], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.44295e+02, 3.25984e+02, -1.78338e+02), forces1[85], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.41100e+02, 7.63283e+01, 1.44488e+02), forces1[86], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.38640e+00, 2.32776e+02, 7.67636e+01), forces1[87], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.02516e+01, 2.34037e+02, 1.90372e+02), forces1[88], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 6.91986e+01, 6.06007e+01, -2.82869e+01), forces1[89], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.17690e+01, 2.95809e+02, 8.76127e+01), forces1[90], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.68695e+02, 3.01744e+02, -4.89279e+01), forces1[91], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.69699e+01, -8.28133e+01, 1.45608e+02), forces1[92], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.06525e+02, -1.67708e+02, -8.84405e+01), forces1[93], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.24225e+02, -2.54622e+02, 6.45408e+01), forces1[94], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.17139e+01, 8.98704e+01, 1.46449e+02), forces1[95], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-6.77809e+01, -7.22944e+00, -1.54716e+02), forces1[96], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.09684e+01, -7.69721e+01, 4.92171e+01), forces1[97], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.39983e+01, -1.04019e+01, -1.19765e+02), forces1[98], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.69240e+02, -4.03667e+02, -1.80224e+01), forces1[99], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-9.94854e+01, 1.06162e+02, 2.06747e+02), forces1[100], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.37669e+02, 1.53252e+02, 2.04131e+02), forces1[101], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-8.32814e+02, 6.44910e+01, -3.37777e+02), forces1[102], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.66103e+02, 8.69357e+01, -1.09283e+02), forces1[103], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.18540e+01, 6.11078e+01, -1.30500e+02), forces1[104], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.89128e+02, -2.65106e+02, -1.28996e+02), forces1[105], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.45378e+01, -3.81579e+02, -1.11586e+02), forces1[106], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-5.79366e+01, -2.27092e+02, 2.32158e+02), forces1[107], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.14303e+02, 1.21953e+02, 3.08605e+01), forces1[108], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.95355e+02, 2.38433e+02, -3.78260e+01), forces1[109], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.25306e+02, -5.62806e+01, 2.93849e+02), forces1[110], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.32541e+02, 1.53253e+02, 1.18339e+02), forces1[111], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.26061e+02, 1.22366e+02, 6.31712e+00), forces1[112], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.68565e+02, 9.40491e+01, 4.12643e+01), forces1[113], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.19917e+02, -1.43527e+02, -2.21682e+02), forces1[114], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.93757e+01, 9.98556e+01, 7.38225e+01), forces1[115], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 5.87240e+01, -7.40610e+01, 1.37672e+02), forces1[116], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.90455e+01, -9.52131e+01, -4.21601e+02), forces1[117], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.97078e+02, 2.45509e+02, 9.26765e+01), forces1[118], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.98206e+02, 1.14032e+02, 8.71204e+01), forces1[119], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.19803e+02, 1.82722e+01, -3.52888e+00), forces1[120], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.30623e+02, 7.51475e-01, -4.84435e+01), forces1[121], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 5.02126e+01, 5.55326e+01, 2.67927e+00), forces1[122], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.87364e+02, 1.76214e+02, -3.09445e+02), forces1[123], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.85190e+02, -1.63720e+02, -7.15048e+01), forces1[124], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.65174e+02, -1.33924e+02, -6.94217e+01), forces1[125], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.39913e+00, 2.52232e+01, 5.05709e+01), forces1[126], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.63349e+02, 9.56277e+01, 5.30812e+01), forces1[127], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-8.92027e+01, -9.44704e+01, -7.51200e+00), forces1[128], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.24094e+02, 7.38856e+01, 1.76005e+02), forces1[129], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 6.92944e+01, 3.02317e+02, 1.39375e+02), forces1[130], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-5.66291e+01, 1.41333e+02, 6.15473e+00), forces1[131], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.36178e+01, -1.58532e+01, -8.84526e+00), forces1[132], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.48146e+01, -3.41461e+01, -5.24216e+01), forces1[133], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 6.99809e+01, 1.02879e+01, -5.01739e+01), forces1[134], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.62285e+02, -4.90274e+01, 3.03601e+01), forces1[135], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.06458e+02, -3.96124e+01, 1.03454e+02), forces1[136], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.29243e+02, 6.18585e+01, -1.77272e+02), forces1[137], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.15853e+02, 2.19635e+02, -4.11751e+02), forces1[138], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.16425e+01, 8.23178e+01, 4.42405e+02), forces1[139], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.21858e+01, 4.82821e+01, 1.93947e+02), forces1[140], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-6.03450e+00, 2.30768e+01, 4.96796e+01), forces1[141], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 5.67572e+01, 7.23375e+01, 6.32957e+01), forces1[142], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.67345e+01, 1.26459e+01, 8.78382e+01), forces1[143], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.43687e+02, 1.76648e+01, 3.89767e+01), forces1[144], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 9.77056e+01, -9.46510e+01, -1.60263e+02), forces1[145], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-6.49800e+01, -2.68488e+01, 4.35106e+01), forces1[146], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.46710e+02, -5.25895e+01, -5.40524e+01), forces1[147], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-9.33729e+01, -4.69399e+01, -7.85015e+01), forces1[148], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.78265e+02, 3.19667e+00, -1.14997e+02), forces1[149], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.93773e+02, 7.50014e+01, -6.05331e+01), forces1[150], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.41372e+02, 1.04392e+02, -1.69148e+02), forces1[151], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 5.16023e+01, -7.84331e+00, -3.50072e+01), forces1[152], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.91752e+02, -8.75055e+01, 2.06764e+01), forces1[153], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.24104e+01, 2.55823e+02, 5.03937e+01), forces1[154], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.44493e+01, -1.88359e+02, -2.96664e+02), forces1[155], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-9.95569e+01, -1.48556e+02, -3.25981e+01), forces1[156], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 9.87067e+01, -3.24463e+01, -4.72036e+01), forces1[157], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.57426e+01, -4.76206e+01, -4.60343e+01), forces1[158], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.72900e+01, 5.41697e-01, -1.00543e+02), forces1[159], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.18469e+01, -6.73531e+00, 1.21198e+02), forces1[160], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 5.22925e+01, -1.12784e+01, 1.43764e+02), forces1[161], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-9.83447e+00, -1.45820e+01, -1.70105e+02), forces1[162], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.76068e+01, -7.28345e+00, -1.56973e+02), forces1[163], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.79090e+01, -1.92976e+02, -1.29871e+02), forces1[164], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.93110e+01, -1.12724e+02, 2.45046e+01), forces1[165], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.69833e+02, -9.82967e+01, 5.93923e+01), forces1[166], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.02085e+02, 9.27636e+00, 6.98988e+01), forces1[167], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.84338e+01, 1.41909e+02, -4.11691e+01), forces1[168], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.23626e+02, -1.04296e+02, 4.77490e+01), forces1[169], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.37003e+01, 4.13719e+01, 1.29790e+02), forces1[170], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.42874e+02, -8.32344e+01, -3.05737e+01), forces1[171], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.41293e+01, 7.66533e+01, 1.00918e+02), forces1[172], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.02752e+02, -3.11320e+01, -2.04248e+01), forces1[173], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 5.71192e+01, -3.13758e+02, 2.83511e+02), forces1[174], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.43170e+02, 1.60859e+02, 6.31587e+01), forces1[175], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.26734e+02, 1.91452e+02, -1.93402e+00), forces1[176], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.10931e+02, -1.64391e+01, -6.86948e+01), forces1[177], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-9.38600e+01, 2.32825e+02, -5.25593e+00), forces1[178], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-6.54520e+01, -1.88445e+02, -4.29131e+01), forces1[179], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.24785e+02, -1.05275e+02, -2.98944e+01), forces1[180], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.05063e+02, -6.53701e+01, 3.24520e+01), forces1[181], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.53521e+01, -9.04667e+01, -1.59980e+01), forces1[182], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.53764e+01, -3.04915e+01, 1.37888e+02), forces1[183], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.08932e+02, -9.35386e+01, -1.80955e+01), forces1[184], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.64566e+02, -1.70413e+02, -1.27317e+01), forces1[185], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.22672e+02, -3.22897e+02, 3.76674e+00), forces1[186], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-5.09547e+01, 3.37045e+02, -2.28878e+02), forces1[187], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 9.33946e+01, -1.01157e+02, -5.42970e+01), forces1[188], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.88672e+01, 2.85116e+01, -8.06985e-01), forces1[189], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 9.46034e+01, 1.78114e+02, -8.00020e+01), forces1[190], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.94640e+01, -7.09864e+01, 1.32544e+02), forces1[191], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 5.87772e+01, 8.20162e+01, -9.03433e+01), forces1[192], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.88680e+00, 8.72448e+01, -2.61573e+01), forces1[193], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.28593e+01, 2.51197e+00, -5.73722e+01), forces1[194], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-5.80417e+01, -7.37577e+01, 1.00134e+02), forces1[195], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.56974e+01, 6.72072e+00, -3.81539e+01), forces1[196], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-6.19232e+01, -3.54500e+01, 8.29318e+01), forces1[197], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.04113e+01, -4.41970e+01, 1.03326e+02), forces1[198], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-6.90881e+01, -1.12057e+02, 4.49403e+01), forces1[199], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-5.92007e+01, 3.55272e+01, -2.40127e+02), forces1[200], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.43562e+02, 6.23027e+02, -2.49264e+02), forces1[201], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.76198e+02, -3.02372e+02, 1.62332e+02), forces1[202], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.20299e+02, -2.27586e+02, 5.80333e+01), forces1[203], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 9.39488e+01, -1.07027e+00, -2.95203e+01), forces1[204], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 6.73263e+01, -1.08485e+02, 5.71183e+00), forces1[205], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.00039e+01, -2.49895e+02, 3.39192e+01), forces1[206], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.29623e+01, 1.32732e+02, 2.08741e+01), forces1[207], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.25554e+02, -1.56772e+01, -1.08164e+02), forces1[208], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-8.38717e+01, 1.52424e+01, 4.36131e+01), forces1[209], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.76367e+01, 1.13676e+02, -8.52759e+01), forces1[210], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-6.96298e+01, -9.30520e+01, -2.23851e+01), forces1[211], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.75027e+01, 1.64821e+02, 6.78676e+01), forces1[212], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.64028e+02, 3.12107e+01, 8.76753e+01), forces1[213], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.72632e+01, 5.28099e+01, 1.69700e+01), forces1[214], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.40135e+02, -7.08379e+01, -1.93293e+02), forces1[215], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.76562e+01, 2.29918e+02, 1.30609e+02), forces1[216], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 9.81640e+01, -2.90103e+02, 1.36757e+00), forces1[217], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.79291e+01, -2.93974e+02, 1.15436e+02), forces1[218], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.17338e+02, 1.11581e+02, 3.46029e+01), forces1[219], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.13346e+01, 3.15582e+01, 8.34550e+01), forces1[220], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-8.57677e+01, 1.77750e+01, 1.01067e+02), forces1[221], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.49827e+02, 8.44938e+01, 1.82793e+02), forces1[222], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.35999e+02, -1.89848e+02, -2.50760e+02), forces1[223], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.41970e+02, -1.87691e+02, -2.44756e+02), forces1[224], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.37302e+02, 8.71479e+01, -2.13793e+02), forces1[225], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.45010e+01, 2.44686e+02, -1.46416e+02), forces1[226], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.31020e+02, 1.28244e+02, 7.71140e+01), forces1[227], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.53744e+01, 1.29065e+02, 2.11056e+02), forces1[228], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.21924e+01, 9.95419e+00, -1.07719e+02), forces1[229], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.85756e+01, 9.52314e+01, 8.76358e+01), forces1[230], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.93957e+00, 1.53656e+02, -1.13339e+02), forces1[231], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.02172e+02, 8.87905e+01, -2.13701e+02), forces1[232], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.68099e+01, 1.91141e+02, 4.82221e+01), forces1[233], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.92679e+02, -2.47187e+02, 6.66851e+01), forces1[234], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.09980e+02, -1.43568e+02, -3.01739e+01), forces1[235], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.33167e+02, -3.32798e+02, 5.34600e+01), forces1[236], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-5.24223e+01, 9.76875e+00, 4.47725e+01), forces1[237], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.69405e+01, -8.41132e+01, -5.38952e+01), forces1[238], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.12010e+01, 1.44242e+01, -1.42070e+01), forces1[239], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.96477e+02, -4.50656e+02, 1.11329e+02), forces1[240], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.39163e+02, 1.76905e+02, 5.32392e+00), forces1[241], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.19746e+02, 1.76406e+02, 1.08727e+01), forces1[242], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.59625e+01, 1.08166e+01, 1.58314e+02), forces1[243], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-5.06176e+00, 1.91897e+01, 1.04092e+02), forces1[244], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.25838e+02, -4.67771e+00, -5.29138e+01), forces1[245], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.85855e+01, 1.78805e+01, -1.25884e+02), forces1[246], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.10798e+02, 9.15074e+01, 1.95780e+02), forces1[247], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-8.10572e+01, -1.48442e+02, 4.74169e+01), forces1[248], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.25479e+02, 2.55010e+01, 8.47576e+01), forces1[249], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.10701e+02, -6.73355e+01, 1.19913e+02), forces1[250], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-5.70376e+01, -6.37904e+00, 1.26145e+02), forces1[251], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.37588e+02, 1.02142e+02, 3.67769e+02), forces1[252], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.52584e+01, -7.07147e+01, 1.73165e+02), forces1[253], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-9.33450e+01, -2.18105e+02, -1.55636e+02), forces1[254], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.29365e+02, 7.78338e+01, -3.82730e+01), forces1[255], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.57375e+02, -6.66875e+01, -5.81031e+01), forces1[256], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.78245e+01, -1.40991e+01, 3.12933e+01), forces1[257], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.87648e+01, 2.74231e+02, 7.27232e+01), forces1[258], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.14936e+02, 1.20339e+01, -1.48413e+02), forces1[259], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.06217e+02, -3.13647e+01, -1.68616e+02), forces1[260], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.25106e+02, -2.60277e+02, -1.61136e+02), forces1[261], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.70346e+02, -9.32224e+00, -5.51717e+01), forces1[262], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.83465e+01, -2.28314e+02, -2.29566e+02), forces1[263], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-5.96075e+01, 1.48719e+02, 9.34688e+01), forces1[264], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.71370e+02, 1.70586e+02, -9.94963e+01), forces1[265], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 5.40521e+01, -1.08310e+02, 3.14259e+01), forces1[266], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.40452e+02, -2.41911e+02, 1.64059e+02), forces1[267], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.58929e+02, -1.31148e+02, -5.32733e+01), forces1[268], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 5.63751e+01, -2.73274e+02, -8.70685e+00), forces1[269], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.31634e+02, 2.19012e+02, -9.03802e+01), forces1[270], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.18020e+02, -1.92997e+01, -5.66165e+00), forces1[271], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.73518e+01, -3.11848e+01, -1.30020e+02), forces1[272], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 5.17466e+01, -3.68264e+02, 2.52209e+02), forces1[273], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.05037e+02, -1.84548e+02, -2.29593e+02), forces1[274], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.33053e+02, -1.07748e+02, -3.35660e+02), forces1[275], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.26641e+00, -2.78635e+00, -6.24895e+01), forces1[276], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-8.89712e+01, -4.30328e+01, -1.35221e+02), forces1[277], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.08792e+01, 8.56090e+01, 7.01326e+01), forces1[278], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.41320e+01, 1.50690e+02, -3.83537e+01), forces1[279], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.77423e+01, 7.38950e+01, 4.53469e+01), forces1[280], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.26780e+02, 1.02539e+02, -1.85815e+02), forces1[281], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.00799e+01, 1.14102e+02, -1.69102e+02), forces1[282], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.76513e+01, 8.40729e+01, 4.44592e+01), forces1[283], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.26467e+01, 5.77168e+01, 6.22600e+01), forces1[284], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.50347e+02, 3.61081e+02, -9.77920e+00), forces1[285], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 6.74580e+01, -5.17134e+01, -4.47767e+02), forces1[286], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.34437e+01, -3.97370e+02, -1.13442e+02), forces1[287], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.99880e+01, 2.09852e+02, 5.14899e+02), forces1[288], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.66190e+02, -2.26561e+02, 2.12404e+02), forces1[289], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.70999e+02, -2.62349e+02, -1.29205e+01), forces1[290], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 6.14337e+01, 5.49849e+01, 1.43268e+02), forces1[291], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.68620e+02, 3.93466e+00, 5.58857e+01), forces1[292], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.80270e+02, -1.13992e+01, 5.41069e+01), forces1[293], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-5.97739e+00, 1.29408e+02, -5.46560e+01), forces1[294], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.63236e+02, -1.28719e+02, 3.12749e+02), forces1[295], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-8.22808e+01, 1.12193e+02, 7.28319e+01), forces1[296], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.99596e+01, 2.53709e+02, 4.53500e+01), forces1[297], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.27720e+01, 8.59763e+01, 6.45557e+01), forces1[298], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.27058e+02, 1.22472e+01, 1.29561e+01), forces1[299], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.06664e+01, -9.58809e+01, -3.53582e+01), forces1[300], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 5.53970e+01, 5.12101e+01, 1.16686e+02), forces1[301], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.73120e+02, -1.27943e+02, -7.31003e+01), forces1[302], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 5.71294e+01, 2.17024e+02, 9.31014e+01), forces1[303], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.68161e+01, -1.85137e+02, 1.09745e+02), forces1[304], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.01521e+02, 5.92488e+00, -4.76997e+01), forces1[305], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.65074e+02, -7.65780e+01, -1.09596e+02), forces1[306], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-9.97306e+01, 3.84936e+01, 3.18940e+02), forces1[307], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.03733e+01, -3.14806e+01, -1.59317e+02), forces1[308], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-8.43092e+01, -1.29125e+02, 1.63512e+02), forces1[309], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.96060e+02, 5.77380e+01, -1.44479e+02), forces1[310], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.06352e+01, 5.46684e+00, 1.26620e+02), forces1[311], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.68377e+01, 1.94905e+02, 2.46429e+02), forces1[312], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.30349e+02, 9.49772e+01, -1.35362e+02), forces1[313], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.38512e+01, 6.40803e+01, 8.45394e+00), forces1[314], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-9.42175e+01, -1.59403e+00, -1.30405e+02), forces1[315], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.35848e+01, -4.54779e+00, -1.44903e+02), forces1[316], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.11989e+02, -1.18639e+01, -1.17828e+02), forces1[317], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.49970e+02, 6.35046e+01, -2.88805e+01), forces1[318], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.44126e+01, -6.56825e+01, -1.14100e+02), forces1[319], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.77255e+01, -3.66261e+01, -1.19649e+02), forces1[320], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-6.97007e+01, 1.88165e+01, 4.66627e+01), forces1[321], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.11016e+01, 1.60276e+01, -8.72109e+01), forces1[322], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-5.62297e+01, 1.86600e+02, 7.68552e+01), forces1[323], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.39138e+02, 2.21671e+02, 8.47440e+01), forces1[324], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.74277e+02, -6.06765e+01, -4.23965e+01), forces1[325], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.63159e+02, -6.13787e+01, -2.54964e+01), forces1[326], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-8.00529e+01, -6.56450e+01, -3.53408e+01), forces1[327], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-6.27153e+01, -9.16080e+01, -6.10037e+00), forces1[328], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.07795e+01, -6.31786e+01, 3.97424e+01), forces1[329], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-6.69043e+01, 2.05417e+02, -1.55673e+02), forces1[330], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.55098e+01, 6.25556e+01, -9.57571e+01), forces1[331], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.75174e+00, -7.00953e+01, -1.65779e+01), forces1[332], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.48906e+02, -9.37035e+01, -1.37237e+02), forces1[333], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.05834e+02, -1.77865e+02, -2.97998e+02), forces1[334], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.28005e+02, -1.09597e+02, -1.57769e+02), forces1[335], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.72019e+01, -2.11978e+02, -5.75568e+01), forces1[336], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-6.47436e+00, -2.09055e+01, 9.54998e+01), forces1[337], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.00282e+01, -1.18118e+02, 7.20331e+01), forces1[338], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.27051e+01, 3.88512e+01, -3.37338e+02), forces1[339], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.92361e+02, 4.97166e+01, -2.72135e+02), forces1[340], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.01809e+02, 3.12384e+01, -1.44869e+02), forces1[341], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.70524e+01, 6.01604e+01, -1.29958e+01), forces1[342], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.75977e+01, -6.85964e+01, 5.29205e+01), forces1[343], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-9.82625e+01, 5.36498e+01, -1.27179e+02), forces1[344], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.48158e+02, 1.18954e+01, 1.03589e+02), forces1[345], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.76540e+01, 8.31945e+01, 6.88425e-01), forces1[346], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 9.36393e+01, 5.97150e+00, 5.92665e+01), forces1[347], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 6.35596e+01, -3.45187e+01, -8.71186e+01), forces1[348], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.14736e+01, 1.99758e+01, 3.17942e+01), forces1[349], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.15299e+01, -6.78140e+01, -1.20761e+02), forces1[350], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.48161e+02, 1.61995e+02, -2.00364e+01), forces1[351], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.91715e+02, 4.15257e+01, -1.01480e+02), forces1[352], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.53537e+02, 2.47464e+01, -9.32184e+01), forces1[353], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.26331e+02, -1.50752e+02, 3.87836e+02), forces1[354], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.80549e+02, -1.04529e+02, 2.64609e+02), forces1[355], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.33299e+00, -1.04191e+02, 2.43081e+02), forces1[356], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.49417e+02, -2.10331e+02, -2.12391e+02), forces1[357], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.64496e+01, -8.65224e+01, 2.09075e+02), forces1[358], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.26786e+02, -1.04116e+02, 2.42460e+02), forces1[359], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.67930e+01, 5.02589e+01, 7.66782e+01), forces1[360], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 9.64137e+01, -5.87259e+01, 1.21975e+02), forces1[361], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.49708e+02, -5.25609e+01, -2.18329e+02), forces1[362], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.57850e+02, 5.04311e+02, -5.05894e+01), forces1[363], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.62212e+01, -2.94583e+02, 1.54045e+02), forces1[364], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-5.61638e+01, -1.84431e+02, 1.13710e+02), forces1[365], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.06173e+02, 9.36425e+01, 2.20592e+02), forces1[366], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.52623e+02, 1.46025e+02, 8.97291e+01), forces1[367], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.54323e+01, 2.26018e+02, 3.46087e+02), forces1[368], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.27183e+02, -2.09440e+01, -1.89634e+02), forces1[369], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.73506e+02, 2.01241e+02, 5.03574e+01), forces1[370], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.14771e+02, 1.73517e+02, 2.04777e+02), forces1[371], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.08803e+02, -4.69136e+01, 3.13410e+01), forces1[372], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.70333e+01, -9.14230e+01, 2.67645e+01), forces1[373], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.42054e+01, -1.04732e+02, -1.88134e+00), forces1[374], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.41157e+02, -1.07118e+02, 1.67297e+02), forces1[375], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.48356e+01, -8.47055e+01, 2.43285e+02), forces1[376], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.80449e+01, -1.46446e+02, 1.85386e+01), forces1[377], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 6.80687e+00, -6.96210e+01, 1.25177e+01), forces1[378], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.23687e+01, -9.93136e+01, 1.45164e+00), forces1[379], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-9.95215e+00, 1.37747e+01, 4.23959e+00), forces1[380], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-8.62211e+01, 5.78277e+02, 3.68049e+01), forces1[381], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.65270e+02, -1.15374e+02, 1.18132e+02), forces1[382], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.66667e+02, -8.49100e+01, 2.96994e+02), forces1[383], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.99785e+02, 2.24069e+02, 2.30458e+01), forces1[384], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.83662e+01, 2.02857e+01, 5.16795e+01), forces1[385], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.30910e+02, -2.01579e+02, 1.48973e+02), forces1[386], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-5.48803e+01, -2.39996e+02, -6.71369e+01), forces1[387], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.45565e+02, -2.03246e+02, -2.90114e+02), forces1[388], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.28809e+01, 1.07210e+02, 5.79218e+01), forces1[389], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.33045e+01, 4.29217e+01, -2.51884e+01), forces1[390], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.01216e+02, 7.87171e+01, -8.84528e+01), forces1[391], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 6.94984e+01, -1.82575e+00, 6.60948e+01), forces1[392], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-8.01760e+01, 1.13645e+02, 1.03720e+02), forces1[393], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 5.02227e+01, -1.82477e+02, -1.93295e+02), forces1[394], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-8.88739e+01, -7.04682e+01, -1.97902e+02), forces1[395], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.08208e+02, 2.04314e+02, -9.77061e+01), forces1[396], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.97001e+02, -3.37469e+01, 1.30428e+02), forces1[397], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 5.39859e+01, 1.55789e+02, 9.33634e+01), forces1[398], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.71075e+01, 1.01907e+02, -1.62363e+02), forces1[399], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.51477e+02, -1.49509e+02, 2.38020e+01), forces1[400], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.62232e+02, 1.06486e+02, 1.02031e+02), forces1[401], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.24938e+01, 1.19921e+02, -9.62759e+01), forces1[402], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.56992e+01, -1.10020e+02, 1.49108e+02), forces1[403], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.10656e+01, 2.79604e+01, 1.91755e+02), forces1[404], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.74338e+00, -7.08051e+01, -1.05929e+02), forces1[405], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.64700e+02, -1.27130e+02, -5.91595e+01), forces1[406], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 5.30385e+01, 2.08802e+01, -3.57840e+01), forces1[407], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.08287e+02, 2.29771e+01, -2.26233e+02), forces1[408], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.58650e+02, -1.14832e+02, -1.67121e+02), forces1[409], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.19177e+02, 9.05557e+01, 3.00496e+02), forces1[410], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.59854e+01, -1.24855e+02, 1.73507e+02), forces1[411], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.01537e+02, -3.21500e+01, -1.62947e+02), forces1[412], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.68513e+01, 7.25403e+01, 1.10509e+02), forces1[413], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.74676e+01, 1.99661e+02, -3.30448e+02), forces1[414], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.89877e+02, -5.06918e+01, 2.07261e+02), forces1[415], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.05311e+01, 7.99589e+01, -9.81659e+01), forces1[416], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.19039e+02, 7.86478e+01, -1.36094e+02), forces1[417], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.39276e+01, 1.04302e+02, -1.99319e+02), forces1[418], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-8.07836e+01, -7.02154e+01, -3.20077e+01), forces1[419], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.04021e+01, -2.95668e+01, -9.62964e+01), forces1[420], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 5.13789e+01, 2.11057e+01, -7.24998e+01), forces1[421], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.89102e+01, -6.59244e+01, -8.40365e+01), forces1[422], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.19672e+02, -4.01191e+01, 6.57098e+01), forces1[423], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.87553e+01, -8.69171e+01, 2.43178e+01), forces1[424], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-5.67881e+01, -1.94017e+02, 4.85473e+01), forces1[425], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.07150e+02, -1.99734e+02, -2.09862e+01), forces1[426], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.36179e+02, 1.95193e+01, -1.32315e+02), forces1[427], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.23323e+02, -6.31094e+01, -8.32846e+01), forces1[428], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.02495e+00, -1.45980e+02, 5.02494e+02), forces1[429], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.25222e+01, 1.02561e+02, 1.77325e+01), forces1[430], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.12695e+02, 3.15051e+02, -4.46404e+01), forces1[431], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.92031e+02, -9.89024e+01, -3.74688e+02), forces1[432], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.43199e+01, 7.50213e+01, 1.10375e+02), forces1[433], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.10558e+01, 2.43859e+02, 5.47498e+01), forces1[434], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.97703e+01, -1.48364e+02, -1.17638e+02), forces1[435], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.62397e+01, 4.88941e+01, -2.71595e+02), forces1[436], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.31340e+01, -8.20624e+01, 1.16191e+02), forces1[437], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.38517e+02, -7.62394e+01, -5.88168e+00), forces1[438], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.62851e+01, 6.72427e+01, -1.80434e+01), forces1[439], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.58861e+02, 1.15957e+02, -3.78160e+01), forces1[440], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.51803e+02, -4.12446e+01, -8.91525e+01), forces1[441], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-9.61287e+01, -1.36689e+02, -9.23537e+00), forces1[442], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.82943e+02, 1.05844e+02, -1.72148e+02), forces1[443], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.55236e+01, 9.18378e+01, 1.24360e+01), forces1[444], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-5.01227e+01, 8.39026e+01, 3.96741e+02), forces1[445], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.87558e+01, 5.47395e+01, -5.73402e+00), forces1[446], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.60796e+02, -5.52985e+01, 3.17802e+01), forces1[447], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.11619e+02, 1.11090e+02, 1.51495e+02), forces1[448], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 5.78213e+01, -1.33902e+02, 1.13590e+02), forces1[449], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.74607e+02, -2.79326e+02, -1.00171e+02), forces1[450], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-6.47808e+01, -1.29366e+02, -1.92232e+02), forces1[451], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.75509e+00, 1.63688e+01, -3.24829e+02), forces1[452], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.93082e+01, -2.44679e+02, 7.91941e+01), forces1[453], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.41263e+01, 9.35389e+01, 9.69223e+01), forces1[454], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.76713e+02, 1.98982e+02, 2.68113e+01), forces1[455], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-6.79544e+01, 6.96513e+01, -1.90320e+02), forces1[456], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.34104e+02, 2.74828e+01, -3.93803e+01), forces1[457], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.28254e+02, -1.35572e+02, -4.32733e+01), forces1[458], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.28600e+01, 3.07094e+00, -3.78996e+01), forces1[459], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.03587e+02, 1.77989e+02, -6.99490e+01), forces1[460], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.08656e+02, -4.54770e+01, -6.76500e+01), forces1[461], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.71838e+01, 5.19782e+01, -2.94923e+01), forces1[462], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.40301e+02, 2.74572e+02, -3.56579e+01), forces1[463], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 9.03587e+01, -3.16257e+01, -7.72873e+01), forces1[464], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.67138e+02, -7.24846e+01, -6.24143e+01), forces1[465], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-9.03813e+00, 9.49458e+01, 3.72519e+01), forces1[466], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 6.14010e+01, 6.47582e+01, 1.42218e+02), forces1[467], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.20325e+01, 1.99039e+02, 3.65580e+02), forces1[468], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.42970e+02, -8.88587e+01, 1.72171e+02), forces1[469], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.90803e+01, -2.60758e+02, 1.15577e+02), forces1[470], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.52557e+02, -8.51485e+00, -1.82612e+02), forces1[471], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 5.19978e+00, 1.82368e+02, 4.96817e+01), forces1[472], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.60405e+02, -5.75249e+01, 4.30526e+01), forces1[473], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.05782e+01, -1.01381e+02, 5.21152e+01), forces1[474], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.98251e-01, 1.60005e+02, 2.94808e+01), forces1[475], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.38812e+02, -2.31535e+02, 1.88049e+02), forces1[476], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 6.81939e+01, 1.28753e+02, -1.67824e+02), forces1[477], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.23875e+02, 1.55757e+02, -2.79290e+02), forces1[478], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.68146e+01, 8.00636e+01, 1.82356e+00), forces1[479], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.81555e+02, -2.44338e+02, -1.67866e+02), forces1[480], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.60882e+02, 1.64545e+02, 1.24397e+02), forces1[481], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.43347e+02, 1.22527e+02, 2.15375e+02), forces1[482], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.75592e+02, -3.02264e+02, 3.12921e+02), forces1[483], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.42347e+02, 1.64524e+02, 1.46878e+02), forces1[484], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.44791e+00, 6.90323e+01, -3.86573e+01), forces1[485], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.00184e+02, -1.07891e+02, 3.14068e+01), forces1[486], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.40711e+01, 1.27511e+01, 5.66277e+01), forces1[487], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.74580e+02, -1.14306e+02, -1.37535e+02), forces1[488], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.98657e+01, 2.19658e+02, -7.96343e+01), forces1[489], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.90069e+02, 1.36943e+02, -1.78217e+02), forces1[490], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 6.64334e+01, 2.56388e+02, -8.52711e+01), forces1[491], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.38510e+01, -1.61329e+02, 2.59550e+02), forces1[492], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-8.11033e+01, -7.18533e+01, 7.75259e+00), forces1[493], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.05854e+02, 3.14397e+02, -4.61488e+02), forces1[494], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.69218e+02, 1.76533e+02, 2.08605e+02), forces1[495], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.06655e+01, -6.09886e+02, -6.99069e+01), forces1[496], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.19305e+02, -1.88157e+02, 1.20294e+02), forces1[497], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.74817e+01, -1.67738e+01, -7.85411e+00), forces1[498], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 6.56252e+00, -4.35681e+01, -6.24241e+01), forces1[499], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-5.73399e+01, 1.15493e+02, 9.92190e+01), forces1[500], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.58626e+01, 9.15080e+01, 3.20924e+00), forces1[501], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.09582e+01, -1.76054e+01, 6.71996e+00), forces1[502], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.59525e+01, 1.83369e+02, -1.70381e+02), forces1[503], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.32243e+01, 3.37044e+01, -6.27663e+01), forces1[504], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.91590e+01, -5.93696e+01, -7.26003e+01), forces1[505], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.74042e+00, 7.24544e+01, 5.83752e+01), forces1[506], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.35769e+01, 4.35961e+02, 7.54309e+01), forces1[507], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.81578e+02, -1.82955e+02, -1.36110e+02), forces1[508], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.53200e+02, -2.25646e+01, -1.26235e+02), forces1[509], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.02017e+01, 7.54878e+01, -9.98370e+01), forces1[510], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.56935e+01, 7.19882e+00, -3.07487e+02), forces1[511], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.60290e+01, 4.63810e+01, -1.39429e+02), forces1[512], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.36883e+02, -2.71943e+02, 1.90138e+01), forces1[513], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.95573e+01, -1.31976e+02, -1.48737e+02), forces1[514], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.61876e+02, 1.02997e+02, -1.00309e+02), forces1[515], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.73595e+00, 3.79678e+01, 9.45418e+01), forces1[516], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.60218e+00, -7.40917e+01, -2.21371e+01), forces1[517], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.27199e+02, 1.31094e+02, 1.12529e+02), forces1[518], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.04103e+02, 4.69682e+01, -1.18068e+02), forces1[519], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.12794e+01, -1.26833e+02, -4.04741e+01), forces1[520], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.09384e+01, 1.86161e+02, 3.95213e+01), forces1[521], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.91470e+02, 8.17955e+01, -9.25509e+01), forces1[522], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.33121e+01, 7.77548e-01, -1.48384e+02), forces1[523], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.52149e+02, -1.00219e+02, -7.57906e+01), forces1[524], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.46003e+02, -1.03331e+01, 1.17347e+01), forces1[525], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 9.09634e+00, 1.43847e+02, -1.42581e+02), forces1[526], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.68641e+02, 6.25042e+01, -7.01507e+01), forces1[527], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.49802e+01, 2.37203e+02, -2.40370e+02), forces1[528], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.85669e+01, -1.41784e+02, 4.28138e+01), forces1[529], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.75729e+01, -3.33632e+02, 1.31688e+02), forces1[530], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.04035e+02, 1.12452e+02, 7.19995e+01), forces1[531], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 9.61972e+00, 5.32166e+01, -9.89477e+01), forces1[532], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.19982e+01, -2.20164e+02, 9.06987e-01), forces1[533], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.71185e+01, -7.67379e+01, 8.12237e+01), forces1[534], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.80057e+01, -1.09793e+02, -2.04253e+01), forces1[535], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.16821e+02, 1.20240e+02, 5.96457e+01), forces1[536], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.64018e+01, 6.17819e+01, 9.91575e+01), forces1[537], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.55515e+01, -9.66187e+01, -8.19956e+00), forces1[538], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.17947e+01, -1.53378e+01, 1.27485e+00), forces1[539], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.02055e+02, 7.70776e+01, 1.14883e+02), forces1[540], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-5.43124e+01, 9.43473e+01, 8.60578e+01), forces1[541], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-9.81264e+01, -1.32125e+02, 2.56224e+01), forces1[542], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.25842e+01, -1.26725e+02, -8.30650e+01), forces1[543], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.50125e+01, -6.20165e+01, 2.58080e+01), forces1[544], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.55319e+01, -1.59769e+01, -7.15921e+01), forces1[545], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.34804e+01, 4.08590e+02, -8.70023e+01), forces1[546], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.53654e+01, -2.03185e+02, -4.39618e+01), forces1[547], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.62931e+01, -2.78936e+02, 5.62579e+00), forces1[548], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.92745e+01, -9.69829e+01, -3.54599e+01), forces1[549], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.58047e+01, -8.17034e+01, 5.89773e+01), forces1[550], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.75002e+01, -7.94191e+01, 7.55542e+01), forces1[551], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-9.53611e+01, 1.20621e+02, 1.49809e+02), forces1[552], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.63438e+01, -6.24402e+01, -1.12122e+01), forces1[553], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.11429e+02, -4.56045e+01, -4.59567e+01), forces1[554], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.28516e+02, -4.47595e+00, 1.81453e+02), forces1[555], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.33297e+02, 1.44805e+02, -4.27640e+01), forces1[556], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.16740e+02, -7.65847e+00, 7.66024e+01), forces1[557], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.77942e+02, -1.45939e+02, 8.07326e+01), forces1[558], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.68632e+02, 2.69537e+02, 1.22007e+02), forces1[559], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.12709e+02, 6.01408e+01, 1.54041e+02), forces1[560], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.27652e+02, -5.25610e+01, -9.60596e+01), forces1[561], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.14047e+02, -2.01466e+01, -4.96293e+01), forces1[562], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.09791e+02, 4.12161e+01, 1.83442e+02), forces1[563], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.49134e+02, -4.62596e+00, 2.20999e+01), forces1[564], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.30637e+02, -3.75250e+01, 4.14259e+01), forces1[565], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.75025e+02, 3.85962e+01, 5.80226e+01), forces1[566], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.98389e+00, -1.23933e+02, 1.30628e+02), forces1[567], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.05449e+01, -1.14065e+02, 9.70791e+01), forces1[568], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 6.60462e+01, -9.53328e+01, 9.89856e+01), forces1[569], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.13288e+01, -1.44056e+01, 1.39952e+02), forces1[570], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-5.42917e+01, 1.66166e+01, 1.91947e+02), forces1[571], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.13590e+02, -1.55874e+02, -1.13269e+02), forces1[572], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.42809e+02, 3.88945e+02, 1.47303e+02), forces1[573], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.29792e+02, -1.91594e+02, -4.64513e+01), forces1[574], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.06517e+02, -3.17549e+02, 9.06953e+00), forces1[575], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.35062e+02, -3.38933e+01, -9.66009e+01), forces1[576], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.67609e+02, 1.26402e+02, -4.97788e+01), forces1[577], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.05138e+00, 1.07362e+02, -1.02375e+02), forces1[578], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.22771e+02, -7.72250e+01, 1.66501e+02), forces1[579], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.95650e+01, 8.12102e+00, 1.03117e+02), forces1[580], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.75584e+02, 2.88991e+01, -1.17320e+02), forces1[581], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-6.91275e+01, 8.38319e+01, 4.97708e+01), forces1[582], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.51951e+02, 1.60368e+02, -2.06266e+02), forces1[583], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.31889e+01, -2.02781e+02, -8.72161e+01), forces1[584], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.92408e+02, -1.87100e+01, 2.05541e+02), forces1[585], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.73554e+02, -5.01580e+00, 2.66621e+02), forces1[586], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.59561e+02, 9.15584e+00, 1.28235e+02), forces1[587], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 9.11016e+01, 7.42097e+01, -4.28122e+01), forces1[588], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.03537e+02, 2.10837e+01, -1.33908e+02), forces1[589], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.16906e+01, -1.58535e+01, 4.67992e+01), forces1[590], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.44325e+02, -2.46328e+00, -1.81854e+01), forces1[591], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-5.30320e+01, 9.72891e+01, 2.06240e+01), forces1[592], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.36896e+01, 1.33852e+02, 5.19553e+01), forces1[593], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 9.50875e+00, -1.63962e+02, -7.41674e+01), forces1[594], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.07601e+02, -8.54691e+01, 3.11595e+01), forces1[595], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.65770e+02, -4.64405e+01, 8.34911e+01), forces1[596], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.44367e+01, -1.84108e+02, 1.39835e+02), forces1[597], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.24114e+02, 2.50886e+01, 2.54009e+01), forces1[598], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.16187e+02, -4.85179e+01, 1.32305e+02), forces1[599], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 6.37446e+01, -3.29674e+01, 1.16326e+02), forces1[600], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.68011e+01, -1.00073e+02, 8.04682e+01), forces1[601], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-4.83294e+01, -1.73859e+02, 1.36328e+01), forces1[602], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 6.83292e+01, 1.39303e+02, -1.01045e+02), forces1[603], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.07133e+01, 1.29633e+02, -1.90943e+02), forces1[604], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.55543e+02, 7.87557e+01, 9.29806e+01), forces1[605], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.64013e+02, -2.60759e+01, 1.75076e+02), forces1[606], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.33794e+02, -1.63774e+02, -6.37393e+01), forces1[607], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.54235e+02, 2.41512e+02, 1.60676e+02), forces1[608], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.17775e+02, 6.48107e+01, 3.84545e+01), forces1[609], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.04735e+01, 2.01260e+01, 2.39831e+01), forces1[610], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.38884e+02, 1.20777e+02, -5.46490e+01), forces1[611], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.07723e+02, 2.58444e+02, 1.48247e+02), forces1[612], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.01470e+02, -6.94941e+01, -2.70882e+02), forces1[613], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.21667e+01, -1.98769e+02, -1.54892e+02), forces1[614], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.80724e+02, 4.52486e+01, 1.40398e+02), forces1[615], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 3.86820e+02, -7.75719e+00, -1.08164e+01), forces1[616], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.42790e+02, 4.80985e+01, -6.18837e+00), forces1[617], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.76946e+02, -1.97796e+02, 2.44731e+01), forces1[618], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.47411e+02, 2.23512e+02, -4.11150e+01), forces1[619], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.04834e+01, 5.22527e+01, -2.27808e+01), forces1[620], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.52307e+02, 7.40937e+01, 1.12984e+02), forces1[621], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.32953e+01, -1.29608e+02, 1.32966e+02), forces1[622], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.23861e+01, -1.19511e+02, 1.00268e+02), forces1[623], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.50610e+01, -1.46388e+02, -7.77507e+01), forces1[624], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 8.62300e+01, -1.37666e+02, -1.20764e+02), forces1[625], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.47310e+01, -1.47118e+02, -5.18370e+01), forces1[626], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.62932e+01, 7.13690e+01, 1.43985e+02), forces1[627], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.96823e+01, -3.58054e+01, -1.45690e+02), forces1[628], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.18087e+00, 1.85480e+01, 9.50527e+01), forces1[629], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.74362e+00, 1.43052e+01, -4.25871e+01), forces1[630], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.97525e+02, -1.59562e+01, 1.90143e+01), forces1[631], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 2.57292e+01, -2.08667e+02, 2.11507e+01), forces1[632], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.01669e+01, -1.07214e+02, -2.53008e+01), forces1[633], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.18560e+02, 4.41674e+01, -1.78058e+02), forces1[634], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.93301e+00, 5.90508e+01, -3.94824e+01), forces1[635], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-7.81815e+01, 8.73784e+01, -6.35956e+01), forces1[636], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.52356e+01, 1.30136e+02, 1.52025e+01), forces1[637], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.66178e+02, -5.94385e+01, -1.04578e+02), forces1[638], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-1.19123e+02, -1.75069e+02, -2.04114e+00), forces1[639], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-3.92283e+01, 5.61702e+01, 1.27395e+02), forces1[640], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 4.74836e-01, -2.04058e+02, -4.01525e+01), forces1[641], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 6.92669e+01, 6.04519e+00, 4.03163e+01), forces1[642], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.08236e+01, 1.26554e+02, -8.63729e+01), forces1[643], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.88180e+02, -1.08833e+02, -1.18964e+02), forces1[644], 10*TOL);
ASSERT_EQUAL_VEC(Vec3(-2.76077e+01, -2.97113e+02, 5.08198e+02), forces1[645], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 1.84023e+02, 3.56521e+02, -2.17616e+02), forces1[646], 10*TOL);
ASSERT_EQUAL_VEC(Vec3( 7.81607e+01, 3.17356e+02, -1.40920e+02), forces1[647], 10*TOL);
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2012-2015 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/AndersenThermostat.h"
#include "openmm/Context.h"
#include "openmm/NonbondedForce.h"
#include "openmm/System.h"
#include "openmm/VerletIntegrator.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <sstream>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-5;
void compareStates(State& s1, State& s2) {
ASSERT_EQUAL_TOL(s1.getTime(), s2.getTime(), TOL);
int numParticles = s1.getPositions().size();
for (int i = 0; i < numParticles; i++) {
ASSERT_EQUAL_VEC(s1.getPositions()[i], s2.getPositions()[i], TOL);
ASSERT_EQUAL_VEC(s1.getVelocities()[i], s2.getVelocities()[i], TOL);
Vec3 a1, b1, c1, a2, b2, c2;
s1.getPeriodicBoxVectors(a1, b1, c1);
s2.getPeriodicBoxVectors(a2, b2, c2);
ASSERT_EQUAL_VEC(a1, a2, TOL);
ASSERT_EQUAL_VEC(b1, b2, TOL);
ASSERT_EQUAL_VEC(c1, c2, TOL);
for (map<string, double>::const_iterator iter = s1.getParameters().begin(); iter != s1.getParameters().end(); ++iter)
ASSERT_EQUAL(iter->second, (*s2.getParameters().find(iter->first)).second);
}
}
void testSetState() {
const int numParticles = 10;
const double boxSize = 3.0;
const double temperature = 200.0;
System system;
system.addForce(new AndersenThermostat(0.0, 100.0));
NonbondedForce* nonbonded = new NonbondedForce();
system.addForce(nonbonded);
nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
vector<Vec3> positions(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numParticles; i++) {
system.addParticle(1.0);
nonbonded->addParticle(i%2 == 0 ? 0.1 : -0.1, 0.2, 0.1);
positions[i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt));
}
VerletIntegrator integrator(0.001);
Context context(system, integrator, platform);
context.setPositions(positions);
context.setPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
context.setParameter(AndersenThermostat::Temperature(), temperature);
// Run for a little while.
integrator.step(100);
// Record the current state.
State s1 = context.getState(State::Positions | State::Velocities | State::Parameters);
// Continue the simulation for a few more steps and record a partial state.
integrator.step(10);
State s2 = context.getState(State::Positions);
// Restore the original state and see if everything gets restored correctly.
context.setPeriodicBoxVectors(Vec3(2*boxSize, 0, 0), Vec3(0, 2*boxSize, 0), Vec3(0, 0, 2*boxSize));
context.setParameter(AndersenThermostat::Temperature(), temperature+10);
context.setState(s1);
State s3 = context.getState(State::Positions | State::Velocities | State::Parameters);
compareStates(s1, s3);
// Set the partial state and see if the correct things were set.
context.setState(s2);
State s4 = context.getState(State::Positions | State::Velocities | State::Parameters);
for (int i = 0; i < numParticles; i++) {
ASSERT_EQUAL_VEC(s2.getPositions()[i], s4.getPositions()[i], TOL);
ASSERT_EQUAL_VEC(s1.getVelocities()[i], s4.getVelocities()[i], TOL);
}
}
void runPlatformTests();
int main(int argc, char* argv[]) {
try {
initializeTests(argc, argv);
testSetState();
runPlatformTests();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2008-2015 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "ReferencePlatform.h"
#include "openmm/NonbondedForce.h"
#include "openmm/System.h"
#include "openmm/LangevinIntegrator.h"
#include "openmm/VerletIntegrator.h"
#include "openmm/internal/ContextImpl.h"
#include "openmm/internal/NonbondedForceImpl.h"
#include "SimTKOpenMMRealType.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
void testEwaldExact() {
// Use a NaCl crystal to compare the calculated and Madelung energies
const int numParticles = 1000;
const double cutoff = 1.0;
const double boxSize = 2.82;
const double ewaldTol = 1e-5;
System system;
for (int i = 0; i < numParticles/2; i++)
system.addParticle(22.99);
for (int i = 0; i < numParticles/2; i++)
system.addParticle(35.45);
VerletIntegrator integrator(0.01);
NonbondedForce* nonbonded = new NonbondedForce();
for (int i = 0; i < numParticles/2; i++)
nonbonded->addParticle(1.0, 1.0,0.0);
for (int i = 0; i < numParticles/2; i++)
nonbonded->addParticle(-1.0, 1.0,0.0);
nonbonded->setNonbondedMethod(NonbondedForce::Ewald);
nonbonded->setCutoffDistance(cutoff);
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
nonbonded->setEwaldErrorTolerance(ewaldTol);
system.addForce(nonbonded);
Context context(system, integrator, platform);
vector<Vec3> positions(numParticles);
#include "nacl_crystal.dat"
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
// The potential energy of an ion in a crystal is
// E = - (M*e^2/ 4*pi*epsilon0*a0),
// where
// M : Madelung constant (dimensionless, for FCC cells such as NaCl it is 1.7476)
// e : 1.6022 × 10−19 C
// 4*pi*epsilon0: 1.112 × 10−10 C²/(J m)
// a0 : 0.282 x 10-9 m (perfect cell)
//
// E is then the energy per pair of ions, so for our case
// E has to be divided by 2 (per ion), multiplied by N(avogadro), multiplied by number of particles, and divided by 1000 for kJ
double exactEnergy = - (1.7476 * 1.6022e-19 * 1.6022e-19 * 6.02214e+23 * numParticles) / (1.112e-10 * 0.282e-9 * 2 * 1000);
//cout << "exact\t\t: " << exactEnergy << endl;
//cout << "calc\t\t: " << state.getPotentialEnergy() << endl;
ASSERT_EQUAL_TOL(exactEnergy, state.getPotentialEnergy(), 100*ewaldTol);
}
void testEwaldPME(bool includeExceptions) {
// Use amorphous NaCl system for the tests
const int numParticles = 894;
const double cutoff = 1.2;
const double boxSize = 3.00646;
double tol = 1e-5;
ReferencePlatform reference;
System system;
NonbondedForce* nonbonded = new NonbondedForce();
nonbonded->setNonbondedMethod(NonbondedForce::Ewald);
nonbonded->setCutoffDistance(cutoff);
nonbonded->setEwaldErrorTolerance(tol);
for (int i = 0; i < numParticles/2; i++)
system.addParticle(22.99);
for (int i = 0; i < numParticles/2; i++)
system.addParticle(35.45);
for (int i = 0; i < numParticles/2; i++)
nonbonded->addParticle(1.0, 1.0,0.0);
for (int i = 0; i < numParticles/2; i++)
nonbonded->addParticle(-1.0, 1.0,0.0);
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
system.addForce(nonbonded);
vector<Vec3> positions(numParticles);
#include "nacl_amorph.dat"
if (includeExceptions) {
// Add some exclusions.
for (int i = 0; i < numParticles-1; i++) {
Vec3 delta = positions[i]-positions[i+1];
if (sqrt(delta.dot(delta)) < 0.5*cutoff)
nonbonded->addException(i, i+1, i%2 == 0 ? 0.0 : 0.5, 1.0, 0.0);
}
}
// (1) Check whether this matches the Reference platform when using Ewald Method
VerletIntegrator integrator1(0.01);
VerletIntegrator integrator2(0.01);
Context context(system, integrator1, platform);
Context referenceContext(system, integrator2, reference);
context.setPositions(positions);
referenceContext.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
State referenceState = referenceContext.getState(State::Forces | State::Energy);
tol = 1e-2;
for (int i = 0; i < numParticles; i++) {
ASSERT_EQUAL_VEC(referenceState.getForces()[i], state.getForces()[i], tol);
}
tol = 1e-5;
ASSERT_EQUAL_TOL(referenceState.getPotentialEnergy(), state.getPotentialEnergy(), tol);
if (!includeExceptions)
ASSERT_EQUAL_TOL(-3.82047e+05, state.getPotentialEnergy(), 1e-5); // Value from Gromacs
// (2) Check whether Ewald method is self-consistent
double norm = 0.0;
for (int i = 0; i < numParticles; ++i) {
Vec3 f = state.getForces()[i];
norm += f[0]*f[0] + f[1]*f[1] + f[2]*f[2];
}
norm = std::sqrt(norm);
const double delta = 5e-3;
double step = delta/norm;
for (int i = 0; i < numParticles; ++i) {
Vec3 p = positions[i];
Vec3 f = state.getForces()[i];
positions[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step);
}
VerletIntegrator integrator3(0.01);
Context context2(system, integrator3, platform);
context2.setPositions(positions);
tol = 1e-2;
State state2 = context2.getState(State::Energy);
ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state.getPotentialEnergy())/delta, tol)
// (3) Check whether this matches the Reference platform when using PME
nonbonded->setNonbondedMethod(NonbondedForce::PME);
context.reinitialize();
referenceContext.reinitialize();
context.setPositions(positions);
referenceContext.setPositions(positions);
state = context.getState(State::Forces | State::Energy);
referenceState = referenceContext.getState(State::Forces | State::Energy);
tol = 1e-2;
for (int i = 0; i < numParticles; i++) {
ASSERT_EQUAL_VEC(referenceState.getForces()[i], state.getForces()[i], tol);
}
tol = 1e-5;
ASSERT_EQUAL_TOL(referenceState.getPotentialEnergy(), state.getPotentialEnergy(), tol);
if (!includeExceptions)
ASSERT_EQUAL_TOL(-3.82047e+05, state.getPotentialEnergy(), 1e-3); // Value from Gromacs
// (4) Check whether PME method is self-consistent
norm = 0.0;
for (int i = 0; i < numParticles; ++i) {
Vec3 f = state.getForces()[i];
norm += f[0]*f[0] + f[1]*f[1] + f[2]*f[2];
}
norm = std::sqrt(norm);
step = delta/norm;
for (int i = 0; i < numParticles; ++i) {
Vec3 p = positions[i];
Vec3 f = state.getForces()[i];
positions[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step);
}
VerletIntegrator integrator4(0.01);
Context context3(system, integrator4, platform);
context3.setPositions(positions);
tol = 1e-2;
State state3 = context3.getState(State::Energy);
ASSERT_EQUAL_TOL(norm, (state3.getPotentialEnergy()-state.getPotentialEnergy())/delta, tol)
}
void testTriclinic() {
// Create a triclinic box containing eight particles.
System system;
system.setDefaultPeriodicBoxVectors(Vec3(2.5, 0, 0), Vec3(0.5, 3.0, 0), Vec3(0.7, 0.9, 3.5));
for (int i = 0; i < 8; i++)
system.addParticle(1.0);
NonbondedForce* force = new NonbondedForce();
system.addForce(force);
force->setNonbondedMethod(NonbondedForce::PME);
force->setCutoffDistance(1.0);
force->setPMEParameters(3.45891, 32, 40, 48);
for (int i = 0; i < 4; i++)
force->addParticle(-1, 0.440104, 0.4184); // Cl parameters
for (int i = 0; i < 4; i++)
force->addParticle(1, 0.332840, 0.0115897); // Na parameters
vector<Vec3> positions(8);
positions[0] = Vec3(1.744, 2.788, 3.162);
positions[1] = Vec3(1.048, 0.762, 2.340);
positions[2] = Vec3(2.489, 1.570, 2.817);
positions[3] = Vec3(1.027, 1.893, 3.271);
positions[4] = Vec3(0.937, 0.825, 0.009);
positions[5] = Vec3(2.290, 1.887, 3.352);
positions[6] = Vec3(1.266, 1.111, 2.894);
positions[7] = Vec3(0.933, 1.862, 3.490);
// Compute the forces and energy.
VerletIntegrator integ(0.001);
Context context(system, integ, platform);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
// Compare them to values computed by Gromacs.
double expectedEnergy = -963.370;
vector<Vec3> expectedForce(8);
expectedForce[0] = Vec3(4.25253e+01, -1.23503e+02, 1.22139e+02);
expectedForce[1] = Vec3(9.74752e+01, 1.68213e+02, 1.93169e+02);
expectedForce[2] = Vec3(-1.50348e+02, 1.29165e+02, 3.70435e+02);
expectedForce[3] = Vec3(9.18644e+02, -3.52571e+00, -1.34772e+03);
expectedForce[4] = Vec3(-1.61193e+02, 9.01528e+01, -7.12904e+01);
expectedForce[5] = Vec3(2.82630e+02, 2.78029e+01, -3.72864e+02);
expectedForce[6] = Vec3(-1.47454e+02, -2.14448e+02, -3.55789e+02);
expectedForce[7] = Vec3(-8.82195e+02, -7.39132e+01, 1.46202e+03);
for (int i = 0; i < 8; i++) {
ASSERT_EQUAL_VEC(expectedForce[i], state.getForces()[i], 1e-4);
}
ASSERT_EQUAL_TOL(expectedEnergy, state.getPotentialEnergy(), 1e-4);
}
void testErrorTolerance(NonbondedForce::NonbondedMethod method) {
// Create a cloud of random point charges.
const int numParticles = 51;
const double boxWidth = 5.0;
System system;
system.setDefaultPeriodicBoxVectors(Vec3(boxWidth, 0, 0), Vec3(0, boxWidth, 0), Vec3(0, 0, boxWidth));
NonbondedForce* force = new NonbondedForce();
system.addForce(force);
vector<Vec3> positions(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numParticles; i++) {
system.addParticle(1.0);
force->addParticle(-1.0+i*2.0/(numParticles-1), 1.0, 0.0);
positions[i] = Vec3(boxWidth*genrand_real2(sfmt), boxWidth*genrand_real2(sfmt), boxWidth*genrand_real2(sfmt));
}
force->setNonbondedMethod(method);
// For various values of the cutoff and error tolerance, see if the actual error is reasonable.
for (double cutoff = 1.0; cutoff < boxWidth/2; cutoff *= 1.2) {
force->setCutoffDistance(cutoff);
vector<Vec3> refForces;
double norm = 0.0;
for (double tol = 5e-5; tol < 1e-3; tol *= 2.0) {
force->setEwaldErrorTolerance(tol);
VerletIntegrator integrator(0.01);
Context context(system, integrator, platform);
context.setPositions(positions);
State state = context.getState(State::Forces);
if (refForces.size() == 0) {
refForces = state.getForces();
for (int i = 0; i < numParticles; i++)
norm += refForces[i].dot(refForces[i]);
norm = sqrt(norm);
}
else {
double diff = 0.0;
for (int i = 0; i < numParticles; i++) {
Vec3 delta = refForces[i]-state.getForces()[i];
diff += delta.dot(delta);
}
diff = sqrt(diff)/norm;
ASSERT(diff < 2*tol);
}
if (method == NonbondedForce::PME) {
// See if the PME parameters were calculated correctly.
double expectedAlpha, actualAlpha;
int expectedSize[3], actualSize[3];
NonbondedForceImpl::calcPMEParameters(system, *force, expectedAlpha, expectedSize[0], expectedSize[1], expectedSize[2]);
force->getPMEParametersInContext(context, actualAlpha, actualSize[0], actualSize[1], actualSize[2]);
ASSERT_EQUAL_TOL(expectedAlpha, actualAlpha, 1e-5);
for (int i = 0; i < 3; i++) {
ASSERT(actualSize[i] >= expectedSize[i]);
ASSERT(actualSize[i] < expectedSize[i]+10);
}
}
}
}
}
void testPMEParameters() {
// Create a cloud of random point charges.
const int numParticles = 51;
const double boxWidth = 4.7;
System system;
system.setDefaultPeriodicBoxVectors(Vec3(boxWidth, 0, 0), Vec3(0, boxWidth, 0), Vec3(0, 0, boxWidth));
NonbondedForce* force = new NonbondedForce();
system.addForce(force);
vector<Vec3> positions(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numParticles; i++) {
system.addParticle(1.0);
force->addParticle(-1.0+i*2.0/(numParticles-1), 1.0, 0.0);
positions[i] = Vec3(boxWidth*genrand_real2(sfmt), boxWidth*genrand_real2(sfmt), boxWidth*genrand_real2(sfmt));
}
force->setNonbondedMethod(NonbondedForce::PME);
// Compute the energy with an error tolerance of 1e-3.
force->setEwaldErrorTolerance(1e-3);
VerletIntegrator integrator1(0.01);
Context context1(system, integrator1, platform);
context1.setPositions(positions);
double energy1 = context1.getState(State::Energy).getPotentialEnergy();
// Try again with an error tolerance of 1e-4.
force->setEwaldErrorTolerance(1e-4);
VerletIntegrator integrator2(0.01);
Context context2(system, integrator2, platform);
context2.setPositions(positions);
double energy2 = context2.getState(State::Energy).getPotentialEnergy();
// Now explicitly set the parameters. These should match the values that were
// used for tolerance 1e-3.
force->setPMEParameters(2.49291157051793, 32, 32, 32);
VerletIntegrator integrator3(0.01);
Context context3(system, integrator3, platform);
context3.setPositions(positions);
double energy3 = context3.getState(State::Energy).getPotentialEnergy();
ASSERT_EQUAL_TOL(energy1, energy3, 1e-6);
ASSERT(fabs((energy1-energy2)/energy1) > 1e-5);
}
void runPlatformTests();
int main(int argc, char* argv[]) {
try {
initializeTests(argc, argv);
testEwaldExact();
testEwaldPME(false);
testEwaldPME(true);
testTriclinic();
testErrorTolerance(NonbondedForce::Ewald);
testErrorTolerance(NonbondedForce::PME);
testPMEParameters();
runPlatformTests();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2008-2015 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "ReferencePlatform.h"
#include "openmm/GBSAOBCForce.h"
#include "openmm/System.h"
#include "openmm/LangevinIntegrator.h"
#include "openmm/NonbondedForce.h"
#include "SimTKOpenMMRealType.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-5;
void testSingleParticle() {
System system;
system.addParticle(2.0);
LangevinIntegrator integrator(0, 0.1, 0.01);
GBSAOBCForce* gbsa = new GBSAOBCForce();
NonbondedForce* nonbonded = new NonbondedForce();
gbsa->addParticle(0.5, 0.15, 1);
nonbonded->addParticle(0.5, 1, 0);
system.addForce(gbsa);
system.addForce(nonbonded);
ASSERT(!gbsa->usesPeriodicBoundaryConditions());
ASSERT(!system.usesPeriodicBoundaryConditions());
Context context(system, integrator, platform);
vector<Vec3> positions(1);
positions[0] = Vec3(0, 0, 0);
context.setPositions(positions);
State state = context.getState(State::Energy);
double bornRadius = 0.15-0.009; // dielectric offset
double eps0 = EPSILON0;
double bornEnergy = (-0.5*0.5/(8*PI_M*eps0))*(1.0/gbsa->getSoluteDielectric()-1.0/gbsa->getSolventDielectric())/bornRadius;
double extendedRadius = 0.15+0.14; // probe radius
double nonpolarEnergy = 4*PI_M*2.25936*extendedRadius*extendedRadius*std::pow(0.15/bornRadius, 6.0);
ASSERT_EQUAL_TOL((bornEnergy+nonpolarEnergy), state.getPotentialEnergy(), 0.01);
// Change the parameters and see if it is still correct.
gbsa->setParticleParameters(0, 0.4, 0.25, 1);
gbsa->updateParametersInContext(context);
state = context.getState(State::Energy);
bornRadius = 0.25-0.009; // dielectric offset
bornEnergy = (-0.4*0.4/(8*PI_M*eps0))*(1.0/gbsa->getSoluteDielectric()-1.0/gbsa->getSolventDielectric())/bornRadius;
extendedRadius = 0.25+0.14;
nonpolarEnergy = 4*PI_M*2.25936*extendedRadius*extendedRadius*std::pow(0.25/bornRadius, 6.0);
ASSERT_EQUAL_TOL((bornEnergy+nonpolarEnergy), state.getPotentialEnergy(), 0.01);
}
void testGlobalSettings() {
System system;
system.addParticle(2.0);
LangevinIntegrator integrator(0, 0.1, 0.01);
GBSAOBCForce* gbsa = new GBSAOBCForce();
gbsa->addParticle(0.5, 0.15, 1);
const double soluteDielectric = 2.1;
const double solventDielectric = 35.0;
const double surfaceAreaEnergy = 0.75;
gbsa->setSoluteDielectric(soluteDielectric);
gbsa->setSolventDielectric(solventDielectric);
gbsa->setSurfaceAreaEnergy(surfaceAreaEnergy);
system.addForce(gbsa);
ASSERT(!gbsa->usesPeriodicBoundaryConditions());
ASSERT(!system.usesPeriodicBoundaryConditions());
Context context(system, integrator, platform);
vector<Vec3> positions(1);
positions[0] = Vec3(0, 0, 0);
context.setPositions(positions);
State state = context.getState(State::Energy);
double bornRadius = 0.15-0.009; // dielectric offset
double eps0 = EPSILON0;
double bornEnergy = (-0.5*0.5/(8*PI_M*eps0))*(1.0/soluteDielectric-1.0/solventDielectric)/bornRadius;
double extendedRadius = 0.15+0.14; // probe radius
double nonpolarEnergy = 4*PI_M*surfaceAreaEnergy*extendedRadius*extendedRadius*std::pow(0.15/bornRadius, 6.0);
ASSERT_EQUAL_TOL((bornEnergy+nonpolarEnergy), state.getPotentialEnergy(), 0.01);
}
void testCutoffAndPeriodic() {
System system;
system.addParticle(1.0);
system.addParticle(1.0);
LangevinIntegrator integrator(0, 0.1, 0.01);
GBSAOBCForce* gbsa = new GBSAOBCForce();
NonbondedForce* nonbonded = new NonbondedForce();
gbsa->addParticle(-1, 0.15, 1);
nonbonded->addParticle(-1, 1, 0);
gbsa->addParticle(1, 0.15, 1);
nonbonded->addParticle(1, 1, 0);
const double cutoffDistance = 3.0;
const double boxSize = 10.0;
nonbonded->setCutoffDistance(cutoffDistance);
gbsa->setCutoffDistance(cutoffDistance);
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
system.addForce(gbsa);
system.addForce(nonbonded);
vector<Vec3> positions(2);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(2, 0, 0);
// Calculate the forces for both cutoff and periodic with two different atom positions.
nonbonded->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic);
gbsa->setNonbondedMethod(GBSAOBCForce::CutoffNonPeriodic);
ASSERT(!nonbonded->usesPeriodicBoundaryConditions());
ASSERT(!gbsa->usesPeriodicBoundaryConditions());
ASSERT(!system.usesPeriodicBoundaryConditions());
Context context(system, integrator, platform);
context.setPositions(positions);
State state1 = context.getState(State::Forces);
nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
gbsa->setNonbondedMethod(GBSAOBCForce::CutoffPeriodic);
ASSERT(nonbonded->usesPeriodicBoundaryConditions());
ASSERT(gbsa->usesPeriodicBoundaryConditions());
ASSERT(system.usesPeriodicBoundaryConditions());
context.reinitialize();
context.setPositions(positions);
State state2 = context.getState(State::Forces);
positions[1][0]+= boxSize;
nonbonded->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic);
gbsa->setNonbondedMethod(GBSAOBCForce::CutoffNonPeriodic);
ASSERT(!nonbonded->usesPeriodicBoundaryConditions());
ASSERT(!gbsa->usesPeriodicBoundaryConditions());
ASSERT(!system.usesPeriodicBoundaryConditions());
context.reinitialize();
context.setPositions(positions);
State state3 = context.getState(State::Forces);
nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
gbsa->setNonbondedMethod(GBSAOBCForce::CutoffPeriodic);
ASSERT(nonbonded->usesPeriodicBoundaryConditions());
ASSERT(gbsa->usesPeriodicBoundaryConditions());
ASSERT(system.usesPeriodicBoundaryConditions());
context.reinitialize();
context.setPositions(positions);
State state4 = context.getState(State::Forces);
// All forces should be identical, exception state3 which should be zero.
ASSERT_EQUAL_VEC(state1.getForces()[0], state2.getForces()[0], 0.01);
ASSERT_EQUAL_VEC(state1.getForces()[1], state2.getForces()[1], 0.01);
ASSERT_EQUAL_VEC(state1.getForces()[0], state4.getForces()[0], 0.01);
ASSERT_EQUAL_VEC(state1.getForces()[1], state4.getForces()[1], 0.01);
ASSERT_EQUAL_VEC(state3.getForces()[0], Vec3(0, 0, 0), 0.01);
ASSERT_EQUAL_VEC(state3.getForces()[1], Vec3(0, 0, 0), 0.01);
}
void testForce(int numParticles, NonbondedForce::NonbondedMethod method, GBSAOBCForce::NonbondedMethod method2) {
ReferencePlatform reference;
System system;
GBSAOBCForce* gbsa = new GBSAOBCForce();
NonbondedForce* nonbonded = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) {
system.addParticle(1.0);
double charge = i%2 == 0 ? -1 : 1;
gbsa->addParticle(charge, 0.15, 1);
nonbonded->addParticle(charge, 1, 0);
}
nonbonded->setNonbondedMethod(method);
gbsa->setNonbondedMethod(method2);
nonbonded->setCutoffDistance(3.0);
gbsa->setCutoffDistance(3.0);
int grid = (int) floor(0.5+pow(numParticles, 1.0/3.0));
if (method == NonbondedForce::CutoffPeriodic) {
double boxSize = (grid+1)*1.1;
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
}
system.addForce(gbsa);
system.addForce(nonbonded);
LangevinIntegrator integrator1(0, 0.1, 0.01);
LangevinIntegrator integrator2(0, 0.1, 0.01);
Context context(system, integrator1, platform);
Context refContext(system, integrator2, reference);
// Set random (but uniformly distributed) positions for all the particles.
vector<Vec3> positions(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < grid; i++)
for (int j = 0; j < grid; j++)
for (int k = 0; k < grid; k++)
positions[i*grid*grid+j*grid+k] = Vec3(i*1.1, j*1.1, k*1.1);
for (int i = 0; i < numParticles; ++i)
positions[i] = positions[i] + Vec3(0.5*genrand_real2(sfmt), 0.5*genrand_real2(sfmt), 0.5*genrand_real2(sfmt));
context.setPositions(positions);
refContext.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
State refState = refContext.getState(State::Forces | State::Energy);
// Make sure this agrees with the Reference platform.
double norm = 0.0;
double diff = 0.0;
for (int i = 0; i < numParticles; ++i) {
Vec3 f = state.getForces()[i];
norm += f[0]*f[0] + f[1]*f[1] + f[2]*f[2];
Vec3 delta = f-refState.getForces()[i];
diff += delta[0]*delta[0] + delta[1]*delta[1] + delta[2]*delta[2];
}
norm = std::sqrt(norm);
diff = std::sqrt(diff);
ASSERT_EQUAL_TOL(0.0, diff, 0.001*norm);
ASSERT_EQUAL_TOL(state.getPotentialEnergy(), refState.getPotentialEnergy(), 1e-3);
// Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount.
// (This doesn't work with cutoffs, since the energy changes discontinuously at the cutoff distance.)
if (method == NonbondedForce::NoCutoff)
{
const double delta = 0.3;
double step = 0.5*delta/norm;
vector<Vec3> positions2(numParticles), positions3(numParticles);
for (int i = 0; i < numParticles; ++i) {
Vec3 p = positions[i];
Vec3 f = state.getForces()[i];
positions2[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step);
positions3[i] = Vec3(p[0]+f[0]*step, p[1]+f[1]*step, p[2]+f[2]*step);
}
context.setPositions(positions2);
State state2 = context.getState(State::Energy);
context.setPositions(positions3);
State state3 = context.getState(State::Energy);
ASSERT_EQUAL_TOL(norm, (state2.getPotentialEnergy()-state3.getPotentialEnergy())/delta, 1e-2)
}
}
void runPlatformTests();
int main(int argc, char* argv[]) {
try {
initializeTests(argc, argv);
testSingleParticle();
testGlobalSettings();
testCutoffAndPeriodic();
for (int i = 5; i < 11; i++) {
testForce(i*i*i, NonbondedForce::NoCutoff, GBSAOBCForce::NoCutoff);
testForce(i*i*i, NonbondedForce::CutoffNonPeriodic, GBSAOBCForce::CutoffNonPeriodic);
testForce(i*i*i, NonbondedForce::CutoffPeriodic, GBSAOBCForce::CutoffPeriodic);
}
runPlatformTests();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2008-2015 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "openmm/HarmonicBondForce.h"
#include "openmm/NonbondedForce.h"
#include "openmm/System.h"
#include "openmm/LangevinIntegrator.h"
#include "SimTKOpenMMRealType.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-5;
void testSingleBond() {
System system;
system.addParticle(2.0);
system.addParticle(2.0);
LangevinIntegrator integrator(0, 0.1, 0.01);
HarmonicBondForce* forceField = new HarmonicBondForce();
forceField->addBond(0, 1, 1.5, 1);
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(2);
positions[0] = Vec3(-1, 0, 0);
positions[1] = Vec3(1, 0, 0);
context.setPositions(positions);
// This is simply a damped harmonic oscillator, so compare it to the analytical solution.
double freq = std::sqrt(1-0.05*0.05);
for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions | State::Velocities);
double time = state.getTime();
double expectedDist = 1.5+0.5*std::exp(-0.05*time)*std::cos(freq*time);
ASSERT_EQUAL_VEC(Vec3(-0.5*expectedDist, 0, 0), state.getPositions()[0], 0.02);
ASSERT_EQUAL_VEC(Vec3(0.5*expectedDist, 0, 0), state.getPositions()[1], 0.02);
double expectedSpeed = -0.5*std::exp(-0.05*time)*(0.05*std::cos(freq*time)+freq*std::sin(freq*time));
ASSERT_EQUAL_VEC(Vec3(-0.5*expectedSpeed, 0, 0), state.getVelocities()[0], 0.02);
ASSERT_EQUAL_VEC(Vec3(0.5*expectedSpeed, 0, 0), state.getVelocities()[1], 0.02);
integrator.step(1);
}
// Not set the friction to a tiny value and see if it conserves energy.
integrator.setFriction(5e-5);
context.setPositions(positions);
State state = context.getState(State::Energy);
double initialEnergy = state.getKineticEnergy()+state.getPotentialEnergy();
for (int i = 0; i < 1000; ++i) {
state = context.getState(State::Energy);
double energy = state.getKineticEnergy()+state.getPotentialEnergy();
ASSERT_EQUAL_TOL(initialEnergy, energy, 0.01);
integrator.step(1);
}
}
void testTemperature() {
const int numParticles = 8;
const double temp = 100.0;
System system;
LangevinIntegrator integrator(temp, 2.0, 0.01);
NonbondedForce* forceField = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) {
system.addParticle(2.0);
forceField->addParticle((i%2 == 0 ? 1.0 : -1.0), 1.0, 5.0);
}
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(numParticles);
for (int i = 0; i < numParticles; ++i)
positions[i] = Vec3((i%2 == 0 ? 2 : -2), (i%4 < 2 ? 2 : -2), (i < 4 ? 2 : -2));
context.setPositions(positions);
// Let it equilibrate.
integrator.step(10000);
// Now run it for a while and see if the temperature is correct.
double ke = 0.0;
for (int i = 0; i < 10000; ++i) {
State state = context.getState(State::Energy);
ke += state.getKineticEnergy();
integrator.step(1);
}
ke /= 10000;
double expected = 0.5*numParticles*3*BOLTZ*temp;
ASSERT_USUALLY_EQUAL_TOL(expected, ke, 6/std::sqrt(10000.0));
}
void testConstraints() {
const int numParticles = 8;
const int numConstraints = 5;
const double temp = 100.0;
System system;
LangevinIntegrator integrator(temp, 2.0, 0.01);
integrator.setConstraintTolerance(1e-5);
NonbondedForce* forceField = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) {
system.addParticle(10.0);
forceField->addParticle((i%2 == 0 ? 0.2 : -0.2), 0.5, 5.0);
}
system.addConstraint(0, 1, 1.0);
system.addConstraint(1, 2, 1.0);
system.addConstraint(2, 3, 1.0);
system.addConstraint(4, 5, 1.0);
system.addConstraint(6, 7, 1.0);
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numParticles; ++i) {
positions[i] = Vec3(i/2, (i+1)/2, 0);
velocities[i] = Vec3(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5);
}
context.setPositions(positions);
context.setVelocities(velocities);
// Simulate it and see whether the constraints remain satisfied.
for (int i = 0; i < 1000; ++i) {
State state = context.getState(State::Positions);
for (int j = 0; j < numConstraints; ++j) {
int particle1, particle2;
double distance;
system.getConstraintParameters(j, particle1, particle2, distance);
Vec3 p1 = state.getPositions()[particle1];
Vec3 p2 = state.getPositions()[particle2];
double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2]));
ASSERT_EQUAL_TOL(distance, dist, 1e-4);
}
integrator.step(1);
}
}
void testConstrainedMasslessParticles() {
System system;
system.addParticle(0.0);
system.addParticle(1.0);
system.addConstraint(0, 1, 1.5);
vector<Vec3> positions(2);
positions[0] = Vec3(-1, 0, 0);
positions[1] = Vec3(1, 0, 0);
LangevinIntegrator integrator(300.0, 2.0, 0.01);
bool failed = false;
try {
// This should throw an exception.
Context context(system, integrator, platform);
}
catch (exception& ex) {
failed = true;
}
ASSERT(failed);
// Now make both particles massless, which should work.
system.setParticleMass(1, 0.0);
Context context(system, integrator, platform);
context.setPositions(positions);
context.setVelocitiesToTemperature(300.0);
integrator.step(1);
State state = context.getState(State::Velocities);
ASSERT_EQUAL(0.0, state.getVelocities()[0][0]);
}
void testRandomSeed() {
const int numParticles = 8;
const double temp = 100.0;
System system;
LangevinIntegrator integrator(temp, 2.0, 0.01);
NonbondedForce* forceField = new NonbondedForce();
for (int i = 0; i < numParticles; ++i) {
system.addParticle(2.0);
forceField->addParticle((i%2 == 0 ? 1.0 : -1.0), 1.0, 5.0);
}
system.addForce(forceField);
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
for (int i = 0; i < numParticles; ++i) {
positions[i] = Vec3((i%2 == 0 ? 2 : -2), (i%4 < 2 ? 2 : -2), (i < 4 ? 2 : -2));
velocities[i] = Vec3(0, 0, 0);
}
// Try twice with the same random seed.
integrator.setRandomNumberSeed(5);
Context context(system, integrator, platform);
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state1 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state2 = context.getState(State::Positions);
// Try twice with a different random seed.
integrator.setRandomNumberSeed(10);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state3 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state4 = context.getState(State::Positions);
// Compare the results.
for (int i = 0; i < numParticles; i++) {
for (int j = 0; j < 3; j++) {
ASSERT(state1.getPositions()[i][j] == state2.getPositions()[i][j]);
ASSERT(state3.getPositions()[i][j] == state4.getPositions()[i][j]);
ASSERT(state1.getPositions()[i][j] != state3.getPositions()[i][j]);
}
}
}
void runPlatformTests();
int main(int argc, char* argv[]) {
try {
initializeTests(argc, argv);
testSingleBond();
testTemperature();
testConstraints();
testConstrainedMasslessParticles();
testRandomSeed();
runPlatformTests();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2010-2015 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "openmm/HarmonicBondForce.h"
#include "openmm/LocalEnergyMinimizer.h"
#include "openmm/NonbondedForce.h"
#include "openmm/VerletIntegrator.h"
#include "openmm/VirtualSite.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
void testHarmonicBonds() {
const int numParticles = 10;
System system;
HarmonicBondForce* bonds = new HarmonicBondForce();
system.addForce(bonds);
// Create a chain of particles connected by harmonic bonds.
vector<Vec3> positions(numParticles);
for (int i = 0; i < numParticles; i++) {
system.addParticle(1.0);
positions[i] = Vec3(i, 0, 0);
if (i > 0)
bonds->addBond(i-1, i, 1+0.1*i, 1);
}
// Minimize it and check that all bonds are at their equilibrium distances.
VerletIntegrator integrator(0.01);
Context context(system, integrator, platform);
context.setPositions(positions);
LocalEnergyMinimizer::minimize(context, 1e-5);
State state = context.getState(State::Positions);
for (int i = 1; i < numParticles; i++) {
Vec3 delta = state.getPositions()[i]-state.getPositions()[i-1];
ASSERT_EQUAL_TOL(1+0.1*i, sqrt(delta.dot(delta)), 1e-4);
}
}
void testLargeSystem() {
const int numMolecules = 25;
const int numParticles = numMolecules*2;
const double cutoff = 2.0;
const double boxSize = 4.0;
const double tolerance = 10;
System system;
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
NonbondedForce* nonbonded = new NonbondedForce();
nonbonded->setCutoffDistance(cutoff);
nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
system.addForce(nonbonded);
// Create a cloud of molecules.
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
vector<Vec3> positions(numParticles);
for (int i = 0; i < numMolecules; i++) {
system.addParticle(1.0);
system.addParticle(1.0);
nonbonded->addParticle(-1.0, 0.2, 0.2);
nonbonded->addParticle(1.0, 0.2, 0.2);
positions[2*i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt));
positions[2*i+1] = Vec3(positions[2*i][0]+1.0, positions[2*i][1], positions[2*i][2]);
system.addConstraint(2*i, 2*i+1, 1.0);
}
// Minimize it and verify that the energy has decreased.
VerletIntegrator integrator(0.01);
Context context(system, integrator, platform);
context.setPositions(positions);
State initialState = context.getState(State::Forces | State::Energy);
LocalEnergyMinimizer::minimize(context, tolerance);
State finalState = context.getState(State::Forces | State::Energy | State::Positions);
ASSERT(finalState.getPotentialEnergy() < initialState.getPotentialEnergy());
// Compute the force magnitude, subtracting off any component parallel to a constraint, and
// check that it satisfies the requested tolerance.
double forceNorm = 0.0;
for (int i = 0; i < numParticles; i += 2) {
Vec3 dir = finalState.getPositions()[i+1]-finalState.getPositions()[i];
double distance = sqrt(dir.dot(dir));
dir *= 1.0/distance;
Vec3 f = finalState.getForces()[i];
f -= dir*dir.dot(f);
forceNorm += f.dot(f);
f = finalState.getForces()[i+1];
f -= dir*dir.dot(f);
forceNorm += f.dot(f);
}
forceNorm = sqrt(forceNorm/(5*numMolecules));
ASSERT(forceNorm < 2*tolerance);
}
void testVirtualSites() {
const int numMolecules = 25;
const int numParticles = numMolecules*3;
const double cutoff = 2.0;
const double boxSize = 4.0;
const double tolerance = 10;
System system;
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
NonbondedForce* nonbonded = new NonbondedForce();
nonbonded->setCutoffDistance(cutoff);
nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
system.addForce(nonbonded);
// Create a cloud of molecules.
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
vector<Vec3> positions(numParticles);
for (int i = 0; i < numMolecules; i++) {
system.addParticle(1.0);
system.addParticle(1.0);
system.addParticle(0.0);
nonbonded->addParticle(-1.0, 0.2, 0.2);
nonbonded->addParticle(0.5, 0.2, 0.2);
nonbonded->addParticle(0.5, 0.2, 0.2);
positions[3*i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt));
positions[3*i+1] = Vec3(positions[3*i][0]+1.0, positions[3*i][1], positions[3*i][2]);
positions[3*i+2] = Vec3();
system.addConstraint(3*i, 3*i+1, 1.0);
system.setVirtualSite(3*i+2, new TwoParticleAverageSite(3*i, 3*i+1, 0.5, 0.5));
}
// Minimize it and verify that the energy has decreased.
VerletIntegrator integrator(0.01);
Context context(system, integrator, platform);
context.setPositions(positions);
context.applyConstraints(1e-5);
State initialState = context.getState(State::Forces | State::Energy);
LocalEnergyMinimizer::minimize(context, tolerance);
State finalState = context.getState(State::Forces | State::Energy | State::Positions);
ASSERT(finalState.getPotentialEnergy() < initialState.getPotentialEnergy());
// Compute the force magnitude, subtracting off any component parallel to a constraint, and
// check that it satisfies the requested tolerance.
double forceNorm = 0.0;
for (int i = 0; i < numParticles; i += 3) {
Vec3 dir = finalState.getPositions()[i+1]-finalState.getPositions()[i];
double distance = sqrt(dir.dot(dir));
dir *= 1.0/distance;
Vec3 f = finalState.getForces()[i];
f -= dir*dir.dot(f);
forceNorm += f.dot(f);
f = finalState.getForces()[i+1];
f -= dir*dir.dot(f);
forceNorm += f.dot(f);
// Check the virtual site location.
ASSERT_EQUAL_VEC((finalState.getPositions()[i+1]+finalState.getPositions()[i])*0.5, finalState.getPositions()[i+2], 1e-5);
}
forceNorm = sqrt(forceNorm/(5*numMolecules));
ASSERT(forceNorm < 2*tolerance);
}
void runPlatformTests();
int main(int argc, char* argv[]) {
try {
initializeTests(argc, argv);
testHarmonicBonds();
testLargeSystem();
testVirtualSites();
runPlatformTests();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2008-2015 Stanford University and the Authors. *
* Authors: Peter Eastman, Lee-Ping Wang *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/CustomExternalForce.h"
#include "openmm/MonteCarloBarostat.h"
#include "openmm/MonteCarloAnisotropicBarostat.h"
#include "openmm/Context.h"
#include "openmm/NonbondedForce.h"
#include "openmm/System.h"
#include "openmm/LangevinIntegrator.h"
#include "openmm/VerletIntegrator.h"
#include "sfmt/SFMT.h"
#include "SimTKOpenMMRealType.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
void testIdealGas() {
const int numParticles = 64;
const int frequency = 10;
const int steps = 1000;
const double pressure = 1.5;
const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3
const double temp[] = {300.0, 600.0, 1000.0};
const double initialVolume = numParticles*BOLTZ*temp[1]/pressureInMD;
const double initialLength = std::pow(initialVolume, 1.0/3.0);
// Create a gas of noninteracting particles.
System system;
system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, 0.5*initialLength, 0), Vec3(0, 0, 2*initialLength));
vector<Vec3> positions(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numParticles; ++i) {
system.addParticle(1.0);
positions[i] = Vec3(initialLength*genrand_real2(sfmt), 0.5*initialLength*genrand_real2(sfmt), 2*initialLength*genrand_real2(sfmt));
}
MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pressure, pressure, pressure), temp[0], true, true, true, frequency);
system.addForce(barostat);
ASSERT(barostat->usesPeriodicBoundaryConditions());
ASSERT(system.usesPeriodicBoundaryConditions());
// Test it for three different temperatures.
for (int i = 0; i < 3; i++) {
barostat->setTemperature(temp[i]);
LangevinIntegrator integrator(temp[i], 0.1, 0.01);
Context context(system, integrator, platform);
context.setPositions(positions);
// Let it equilibrate.
integrator.step(10000);
// Now run it for a while and see if the volume is correct.
double volume = 0.0;
for (int j = 0; j < steps; ++j) {
Vec3 box[3];
context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]);
volume += box[0][0]*box[1][1]*box[2][2];
integrator.step(frequency);
}
volume /= steps;
double expected = (numParticles+1)*BOLTZ*temp[i]/pressureInMD;
ASSERT_USUALLY_EQUAL_TOL(expected, volume, 3/std::sqrt((double) steps));
}
}
void testIdealGasAxis(int axis) {
// Test scaling just one axis.
const int numParticles = 64;
const int frequency = 10;
const int steps = 1000;
const double pressure = 1.5;
const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3
const double temp[] = {300.0, 600.0, 1000.0};
const double initialVolume = numParticles*BOLTZ*temp[1]/pressureInMD;
const double initialLength = std::pow(initialVolume, 1.0/3.0);
const bool scaleX = (axis == 0);
const bool scaleY = (axis == 1);
const bool scaleZ = (axis == 2);
double boxX;
double boxY;
double boxZ;
// Create a gas of noninteracting particles.
System system;
system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, 0.5*initialLength, 0), Vec3(0, 0, 2*initialLength));
vector<Vec3> positions(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numParticles; ++i) {
system.addParticle(1.0);
positions[i] = Vec3(initialLength*genrand_real2(sfmt), 0.5*initialLength*genrand_real2(sfmt), 2*initialLength*genrand_real2(sfmt));
}
MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pressure, pressure, pressure), temp[0], scaleX, scaleY, scaleZ, frequency);
system.addForce(barostat);
ASSERT(barostat->usesPeriodicBoundaryConditions());
ASSERT(system.usesPeriodicBoundaryConditions());
// Test it for three different temperatures.
for (int i = 0; i < 3; i++) {
barostat->setTemperature(temp[i]);
LangevinIntegrator integrator(temp[i], 0.1, 0.01);
Context context(system, integrator, platform);
context.setPositions(positions);
// Let it equilibrate.
integrator.step(10000);
// Now run it for a while and see if the volume is correct.
double volume = 0.0;
for (int j = 0; j < steps; ++j) {
Vec3 box[3];
context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]);
boxX = box[0][0];
boxY = box[1][1];
boxZ = box[2][2];
volume += box[0][0]*box[1][1]*box[2][2];
integrator.step(frequency);
}
volume /= steps;
double expected = (numParticles+1)*BOLTZ*temp[i]/pressureInMD;
ASSERT_USUALLY_EQUAL_TOL(expected, volume, 3/std::sqrt((double) steps));
if (!scaleX) {
ASSERT(boxX == initialLength);
}
if (!scaleY) {
ASSERT(boxY == 0.5*initialLength);
}
if (!scaleZ) {
ASSERT(boxZ == 2*initialLength);
}
}
}
void testRandomSeed() {
const int numParticles = 8;
const double temp = 100.0;
const double pressure = 1.5;
System system;
system.setDefaultPeriodicBoxVectors(Vec3(8, 0, 0), Vec3(0, 8, 0), Vec3(0, 0, 8));
VerletIntegrator integrator(0.01);
NonbondedForce* forceField = new NonbondedForce();
forceField->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
for (int i = 0; i < numParticles; ++i) {
system.addParticle(2.0);
forceField->addParticle((i%2 == 0 ? 1.0 : -1.0), 1.0, 5.0);
}
system.addForce(forceField);
MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pressure, pressure, pressure), temp, true, true, true, 1);
system.addForce(barostat);
ASSERT(barostat->usesPeriodicBoundaryConditions());
ASSERT(system.usesPeriodicBoundaryConditions());
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
for (int i = 0; i < numParticles; ++i) {
positions[i] = Vec3((i%2 == 0 ? 2 : -2), (i%4 < 2 ? 2 : -2), (i < 4 ? 2 : -2));
velocities[i] = Vec3(0, 0, 0);
}
// Try twice with the same random seed.
barostat->setRandomNumberSeed(5);
Context context(system, integrator, platform);
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state1 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state2 = context.getState(State::Positions);
// Try twice with a different random seed.
barostat->setRandomNumberSeed(10);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state3 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state4 = context.getState(State::Positions);
// Compare the results.
for (int i = 0; i < numParticles; i++) {
for (int j = 0; j < 3; j++) {
ASSERT(state1.getPositions()[i][j] == state2.getPositions()[i][j]);
ASSERT(state3.getPositions()[i][j] == state4.getPositions()[i][j]);
ASSERT(state1.getPositions()[i][j] != state3.getPositions()[i][j]);
}
}
}
void testTriclinic() {
const int numParticles = 64;
const int frequency = 10;
const int steps = 1000;
const double pressure = 1.5;
const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3
const double temperature = 300.0;
const double initialVolume = numParticles*BOLTZ*temperature/pressureInMD;
const double initialLength = std::pow(initialVolume, 1.0/3.0);
// Create a gas of noninteracting particles.
System system;
Vec3 initialBox[3];
initialBox[0] = Vec3(initialLength, 0, 0);
initialBox[1] = Vec3(0.2*initialLength, initialLength, 0);
initialBox[2] = Vec3(0.1*initialLength, 0.3*initialLength, initialLength);
system.setDefaultPeriodicBoxVectors(initialBox[0], initialBox[1], initialBox[2]);
vector<Vec3> positions(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numParticles; ++i) {
system.addParticle(1.0);
positions[i] = Vec3(initialLength*genrand_real2(sfmt), initialLength*genrand_real2(sfmt), initialLength*genrand_real2(sfmt));
}
MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pressure, pressure, pressure), temperature, true, true, true, frequency);
system.addForce(barostat);
// Run a simulation
LangevinIntegrator integrator(temperature, 0.1, 0.01);
Context context(system, integrator, platform);
context.setPositions(positions);
// Let it equilibrate.
integrator.step(10000);
// Now run it for a while and see if the volume is correct.
double volume = 0.0;
for (int j = 0; j < steps; ++j) {
Vec3 box[3];
context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]);
volume += box[0][0]*box[1][1]*box[2][2];
integrator.step(frequency);
}
volume /= steps;
double expected = (numParticles+1)*BOLTZ*temperature/pressureInMD;
ASSERT_USUALLY_EQUAL_TOL(expected, volume, 3/std::sqrt((double) steps));
// Make sure the box vectors have been scaled consistently.
State state = context.getState(State::Positions);
Vec3 box[3];
state.getPeriodicBoxVectors(box[0], box[1], box[2]);
double xscale = box[2][0]/(0.1*initialLength);
double yscale = box[2][1]/(0.3*initialLength);
double zscale = box[2][2]/(1.0*initialLength);
for (int i = 0; i < 3; i++) {
ASSERT_EQUAL_VEC(Vec3(xscale*initialBox[i][0], yscale*initialBox[i][1], zscale*initialBox[i][2]), box[i], 1e-5);
}
// The barostat should have put all particles inside the first periodic box. One integration step
// has happened since then, so they may have moved slightly outside it.
for (int i = 0; i < numParticles; i++) {
Vec3 pos = state.getPositions()[i];
ASSERT(pos[2]/box[2][2] > -1 && pos[2]/box[2][2] < 2);
pos -= box[2]*floor(pos[2]/box[2][2]);
ASSERT(pos[1]/box[1][1] > -1 && pos[1]/box[1][1] < 2);
pos -= box[1]*floor(pos[1]/box[1][1]);
ASSERT(pos[0]/box[0][0] > -1 && pos[0]/box[0][0] < 2);
}
}
/**
* Run a constant pressure simulation on an anisotropic Einstein crystal
* using isotropic and anisotropic barostats. There are a total of 15 simulations:
*
* 1) 3 pressures: 9.0, 10.0, 11.0 bar, for each of the following groups:
* 2) 3 groups of simulations that scale just one axis: x, y, z
* 3) 1 group of simulations that scales all three axes in the anisotropic barostat
* 4) 1 group of simulations that scales all three axes in the isotropic barostat
*
* Results that we will check:
*
* a) In each group of simulations, the volume should decrease with increasing pressure
* b) In the three simulation groups that scale just one axis, the compressibility (i.e. incremental volume change
* with increasing pressure) should go like kx > ky > kz (because the spring constant is largest in the z-direction)
* c) The anisotropic barostat should produce the same result as the isotropic barostat when all three axes are scaled
*/
void testEinsteinCrystal() {
const int numParticles = 64;
const int frequency = 2;
const int equil = 10000;
const int steps = 5000;
const double pressure = 10.0;
const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3
const double temp = 300.0; // Only test one temperature since we're looking at three pressures.
const double pres3[] = {2.0, 8.0, 15.0};
const double initialVolume = numParticles*BOLTZ*temp/pressureInMD;
const double initialLength = std::pow(initialVolume, 1.0/3.0);
vector<double> initialPositions(3);
vector<double> results;
// Run four groups of anisotropic simulations; scaling just x, y, z, then all three.
for (int a = 0; a < 4; a++) {
// Test barostat for three different pressures.
for (int p = 0; p < 3; p++) {
// Create a system of noninteracting particles attached by harmonic springs to their initial positions.
System system;
system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, initialLength, 0), Vec3(0, 0, initialLength));
vector<Vec3> positions(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
// Anisotropic force constants.
CustomExternalForce* force = new CustomExternalForce("0.005*(x-x0)^2 + 0.01*(y-y0)^2 + 0.02*(z-z0)^2");
force->addPerParticleParameter("x0");
force->addPerParticleParameter("y0");
force->addPerParticleParameter("z0");
NonbondedForce* nb = new NonbondedForce();
nb->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
for (int i = 0; i < numParticles; ++i) {
system.addParticle(1.0);
positions[i] = Vec3(((i/16)%4+0.5)*initialLength/4, ((i/4)%4+0.5)*initialLength/4, (i%4+0.5)*initialLength/4);
initialPositions[0] = positions[i][0];
initialPositions[1] = positions[i][1];
initialPositions[2] = positions[i][2];
force->addParticle(i, initialPositions);
nb->addParticle(0, initialLength/6, 0.1);
}
system.addForce(force);
system.addForce(nb);
// Create the barostat.
MonteCarloAnisotropicBarostat* barostat = new MonteCarloAnisotropicBarostat(Vec3(pres3[p], pres3[p], pres3[p]), temp, (a==0||a==3), (a==1||a==3), (a==2||a==3), frequency);
system.addForce(barostat);
barostat->setTemperature(temp);
LangevinIntegrator integrator(temp, 0.1, 0.01);
Context context(system, integrator, platform);
context.setPositions(positions);
// Let it equilibrate.
integrator.step(equil);
// Now run it for a while and see if the volume is correct.
double volume = 0.0;
for (int j = 0; j < steps; ++j) {
Vec3 box[3];
context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]);
volume += box[0][0]*box[1][1]*box[2][2];
integrator.step(frequency);
}
volume /= steps;
results.push_back(volume);
}
}
for (int p = 0; p < 3; p++) {
// Create a system of noninteracting particles attached by harmonic springs to their initial positions.
System system;
system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, initialLength, 0), Vec3(0, 0, initialLength));
vector<Vec3> positions(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
// Anisotropic force constants.
CustomExternalForce* force = new CustomExternalForce("0.005*(x-x0)^2 + 0.01*(y-y0)^2 + 0.02*(z-z0)^2");
force->addPerParticleParameter("x0");
force->addPerParticleParameter("y0");
force->addPerParticleParameter("z0");
NonbondedForce* nb = new NonbondedForce();
nb->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
for (int i = 0; i < numParticles; ++i) {
system.addParticle(1.0);
positions[i] = Vec3(((i/16)%4+0.5)*initialLength/4, ((i/4)%4+0.5)*initialLength/4, (i%4+0.5)*initialLength/4);
initialPositions[0] = positions[i][0];
initialPositions[1] = positions[i][1];
initialPositions[2] = positions[i][2];
force->addParticle(i, initialPositions);
nb->addParticle(0, initialLength/6, 0.1);
}
system.addForce(force);
system.addForce(nb);
// Create the barostat.
MonteCarloBarostat* barostat = new MonteCarloBarostat(pres3[p], temp, frequency);
system.addForce(barostat);
barostat->setTemperature(temp);
LangevinIntegrator integrator(temp, 0.1, 0.001);
Context context(system, integrator, platform);
context.setPositions(positions);
// Let it equilibrate.
integrator.step(equil);
// Now run it for a while and see if the volume is correct.
double volume = 0.0;
for (int j = 0; j < steps; ++j) {
Vec3 box[3];
context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]);
volume += box[0][0]*box[1][1]*box[2][2];
integrator.step(frequency);
}
volume /= steps;
results.push_back(volume);
}
// Check to see if volumes decrease with increasing pressure.
ASSERT_USUALLY_TRUE(results[0] > results[1]);
ASSERT_USUALLY_TRUE(results[1] > results[2]);
ASSERT_USUALLY_TRUE(results[3] > results[4]);
ASSERT_USUALLY_TRUE(results[4] > results[5]);
ASSERT_USUALLY_TRUE(results[6] > results[7]);
ASSERT_USUALLY_TRUE(results[7] > results[8]);
// Check to see if incremental volume changes with increasing pressure go like kx > ky > kz.
ASSERT_USUALLY_TRUE((results[0] - results[1]) > (results[3] - results[4]));
ASSERT_USUALLY_TRUE((results[1] - results[2]) > (results[4] - results[5]));
ASSERT_USUALLY_TRUE((results[3] - results[4]) > (results[6] - results[7]));
ASSERT_USUALLY_TRUE((results[4] - results[5]) > (results[7] - results[8]));
// Check to see if the volumes are equal for isotropic and anisotropic (all axis).
ASSERT_USUALLY_EQUAL_TOL(results[9], results[12], 3/std::sqrt((double) steps));
ASSERT_USUALLY_EQUAL_TOL(results[10], results[13], 3/std::sqrt((double) steps));
ASSERT_USUALLY_EQUAL_TOL(results[11], results[14], 3/std::sqrt((double) steps));
}
void runPlatformTests();
int main(int argc, char* argv[]) {
try {
initializeTests(argc, argv);
testIdealGas();
testIdealGasAxis(0);
testIdealGasAxis(1);
testIdealGasAxis(2);
testRandomSeed();
testTriclinic();
//testEinsteinCrystal();
runPlatformTests();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2008-2015 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/MonteCarloBarostat.h"
#include "openmm/Context.h"
#include "openmm/NonbondedForce.h"
#include "openmm/System.h"
#include "openmm/LangevinIntegrator.h"
#include "openmm/VerletIntegrator.h"
#include "sfmt/SFMT.h"
#include "SimTKOpenMMRealType.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
void testChangingBoxSize() {
System system;
system.setDefaultPeriodicBoxVectors(Vec3(4, 0, 0), Vec3(0, 5, 0), Vec3(0, 0, 6));
system.addParticle(1.0);
NonbondedForce* nb = new NonbondedForce();
nb->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
nb->setCutoffDistance(2.0);
nb->addParticle(1, 0.5, 0.5);
system.addForce(nb);
LangevinIntegrator integrator(300.0, 1.0, 0.01);
Context context(system, integrator, platform);
vector<Vec3> positions;
positions.push_back(Vec3());
context.setPositions(positions);
Vec3 x, y, z;
context.getState(State::Forces).getPeriodicBoxVectors(x, y, z);
ASSERT_EQUAL_VEC(Vec3(4, 0, 0), x, 0);
ASSERT_EQUAL_VEC(Vec3(0, 5, 0), y, 0);
ASSERT_EQUAL_VEC(Vec3(0, 0, 6), z, 0);
context.setPeriodicBoxVectors(Vec3(7, 0, 0), Vec3(0, 8, 0), Vec3(0, 0, 9));
context.getState(State::Forces).getPeriodicBoxVectors(x, y, z);
ASSERT_EQUAL_VEC(Vec3(7, 0, 0), x, 0);
ASSERT_EQUAL_VEC(Vec3(0, 8, 0), y, 0);
ASSERT_EQUAL_VEC(Vec3(0, 0, 9), z, 0);
// Shrinking the box too small should produce an exception.
context.setPeriodicBoxVectors(Vec3(7, 0, 0), Vec3(0, 3.9, 0), Vec3(0, 0, 9));
bool ok = true;
try {
context.getState(State::Forces).getPeriodicBoxVectors(x, y, z);
ok = false;
}
catch (exception& ex) {
}
ASSERT(ok);
}
void testIdealGas() {
const int numParticles = 64;
const int frequency = 10;
const int steps = 1000;
const double pressure = 1.5;
const double pressureInMD = pressure*(AVOGADRO*1e-25); // pressure in kJ/mol/nm^3
const double temp[] = {300.0, 600.0, 1000.0};
const double initialVolume = numParticles*BOLTZ*temp[1]/pressureInMD;
const double initialLength = std::pow(initialVolume, 1.0/3.0);
// Create a gas of noninteracting particles.
System system;
system.setDefaultPeriodicBoxVectors(Vec3(initialLength, 0, 0), Vec3(0, 0.5*initialLength, 0), Vec3(0, 0, 2*initialLength));
vector<Vec3> positions(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numParticles; ++i) {
system.addParticle(1.0);
positions[i] = Vec3(initialLength*genrand_real2(sfmt), 0.5*initialLength*genrand_real2(sfmt), 2*initialLength*genrand_real2(sfmt));
}
MonteCarloBarostat* barostat = new MonteCarloBarostat(pressure, temp[0], frequency);
system.addForce(barostat);
ASSERT(barostat->usesPeriodicBoundaryConditions());
ASSERT(system.usesPeriodicBoundaryConditions());
// Test it for three different temperatures.
for (int i = 0; i < 3; i++) {
barostat->setTemperature(temp[i]);
LangevinIntegrator integrator(temp[i], 0.1, 0.01);
Context context(system, integrator, platform);
context.setPositions(positions);
// Let it equilibrate.
integrator.step(10000);
// Now run it for a while and see if the volume is correct.
double volume = 0.0;
for (int j = 0; j < steps; ++j) {
Vec3 box[3];
context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]);
volume += box[0][0]*box[1][1]*box[2][2];
ASSERT_EQUAL_TOL(0.5*box[0][0], box[1][1], 1e-5);
ASSERT_EQUAL_TOL(2*box[0][0], box[2][2], 1e-5);
integrator.step(frequency);
}
volume /= steps;
double expected = (numParticles+1)*BOLTZ*temp[i]/pressureInMD;
ASSERT_USUALLY_EQUAL_TOL(expected, volume, 3/std::sqrt((double) steps));
}
}
void testRandomSeed() {
const int numParticles = 8;
const double temp = 100.0;
const double pressure = 1.5;
System system;
system.setDefaultPeriodicBoxVectors(Vec3(8, 0, 0), Vec3(0, 8, 0), Vec3(0, 0, 8));
VerletIntegrator integrator(0.01);
NonbondedForce* forceField = new NonbondedForce();
forceField->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
for (int i = 0; i < numParticles; ++i) {
system.addParticle(2.0);
forceField->addParticle((i%2 == 0 ? 1.0 : -1.0), 1.0, 5.0);
}
system.addForce(forceField);
MonteCarloBarostat* barostat = new MonteCarloBarostat(pressure, temp, 1);
system.addForce(barostat);
ASSERT(barostat->usesPeriodicBoundaryConditions());
ASSERT(system.usesPeriodicBoundaryConditions());
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
for (int i = 0; i < numParticles; ++i) {
positions[i] = Vec3((i%2 == 0 ? 2 : -2), (i%4 < 2 ? 2 : -2), (i < 4 ? 2 : -2));
velocities[i] = Vec3(0, 0, 0);
}
// Try twice with the same random seed.
barostat->setRandomNumberSeed(5);
Context context(system, integrator, platform);
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state1 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state2 = context.getState(State::Positions);
// Try twice with a different random seed.
barostat->setRandomNumberSeed(10);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state3 = context.getState(State::Positions);
context.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
integrator.step(10);
State state4 = context.getState(State::Positions);
// Compare the results.
for (int i = 0; i < numParticles; i++) {
for (int j = 0; j < 3; j++) {
ASSERT(state1.getPositions()[i][j] == state2.getPositions()[i][j]);
ASSERT(state3.getPositions()[i][j] == state4.getPositions()[i][j]);
ASSERT(state1.getPositions()[i][j] != state3.getPositions()[i][j]);
}
}
}
void testWater() {
const int gridSize = 8;
const int numMolecules = gridSize*gridSize*gridSize;
const int frequency = 10;
const int steps = 400;
const double temp = 273.15;
const double pressure = 3;
const double spacing = 0.32;
const double angle = 109.47*M_PI/180;
const double dOH = 0.1;
const double dHH = dOH*2*std::sin(0.5*angle);
// Create a box of SPC water molecules.
System system;
system.setDefaultPeriodicBoxVectors(Vec3(gridSize*spacing, 0, 0), Vec3(0, gridSize*spacing, 0), Vec3(0, 0, gridSize*spacing));
NonbondedForce* nonbonded = new NonbondedForce();
nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
nonbonded->setUseDispersionCorrection(true);
vector<Vec3> positions;
Vec3 offset1(dOH, 0, 0);
Vec3 offset2(dOH*std::cos(angle), dOH*std::sin(angle), 0);
for (int i = 0; i < gridSize; ++i) {
for (int j = 0; j < gridSize; ++j) {
for (int k = 0; k < gridSize; ++k) {
int firstParticle = system.getNumParticles();
system.addParticle(16.0);
system.addParticle(1.0);
system.addParticle(1.0);
nonbonded->addParticle(-0.82, 0.316557, 0.650194);
nonbonded->addParticle(0.41, 1, 0);
nonbonded->addParticle(0.41, 1, 0);
Vec3 pos = Vec3(spacing*i, spacing*j, spacing*k);
positions.push_back(pos);
positions.push_back(pos+offset1);
positions.push_back(pos+offset2);
system.addConstraint(firstParticle, firstParticle+1, dOH);
system.addConstraint(firstParticle, firstParticle+2, dOH);
system.addConstraint(firstParticle+1, firstParticle+2, dHH);
nonbonded->addException(firstParticle, firstParticle+1, 0, 1, 0);
nonbonded->addException(firstParticle, firstParticle+2, 0, 1, 0);
nonbonded->addException(firstParticle+1, firstParticle+2, 0, 1, 0);
}
}
}
system.addForce(nonbonded);
MonteCarloBarostat* barostat = new MonteCarloBarostat(pressure, temp, frequency);
system.addForce(barostat);
// Simulate it and see if the density matches the expected value (1 g/mL).
LangevinIntegrator integrator(temp, 1.0, 0.002);
Context context(system, integrator, platform);
context.setPositions(positions);
integrator.step(2000);
double volume = 0.0;
for (int j = 0; j < steps; ++j) {
Vec3 box[3];
context.getState(0).getPeriodicBoxVectors(box[0], box[1], box[2]);
volume += box[0][0]*box[1][1]*box[2][2];
integrator.step(frequency);
}
volume /= steps;
double density = numMolecules*18/(AVOGADRO*volume*1e-21);
ASSERT_USUALLY_EQUAL_TOL(1.0, density, 0.02);
}
void runPlatformTests();
int main(int argc, char* argv[]) {
try {
initializeTests(argc, argv);
testChangingBoxSize();
testIdealGas();
testRandomSeed();
// Don't run testWater() here, because it's very slow on Reference platform.
// Individual platforms can run it from runPlatformTests().
runPlatformTests();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2008-2015 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "ReferencePlatform.h"
#include "openmm/HarmonicBondForce.h"
#include "openmm/NonbondedForce.h"
#include "openmm/System.h"
#include "openmm/VerletIntegrator.h"
#include "SimTKOpenMMRealType.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
const double TOL = 1e-5;
void testCoulomb() {
System system;
system.addParticle(1.0);
system.addParticle(1.0);
VerletIntegrator integrator(0.01);
NonbondedForce* forceField = new NonbondedForce();
forceField->addParticle(0.5, 1, 0);
forceField->addParticle(-1.5, 1, 0);
system.addForce(forceField);
ASSERT(!forceField->usesPeriodicBoundaryConditions());
ASSERT(!system.usesPeriodicBoundaryConditions());
Context context(system, integrator, platform);
vector<Vec3> positions(2);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(2, 0, 0);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
double force = ONE_4PI_EPS0*(-0.75)/4.0;
ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[1], TOL);
ASSERT_EQUAL_TOL(ONE_4PI_EPS0*(-0.75)/2.0, state.getPotentialEnergy(), TOL);
}
void testLJ() {
System system;
system.addParticle(1.0);
system.addParticle(1.0);
VerletIntegrator integrator(0.01);
NonbondedForce* forceField = new NonbondedForce();
forceField->addParticle(0, 1.2, 1);
forceField->addParticle(0, 1.4, 2);
system.addForce(forceField);
ASSERT(!forceField->usesPeriodicBoundaryConditions());
ASSERT(!system.usesPeriodicBoundaryConditions());
Context context(system, integrator, platform);
vector<Vec3> positions(2);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(2, 0, 0);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
double x = 1.3/2.0;
double eps = SQRT_TWO;
double force = 4.0*eps*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/2.0;
ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[1], TOL);
ASSERT_EQUAL_TOL(4.0*eps*(std::pow(x, 12.0)-std::pow(x, 6.0)), state.getPotentialEnergy(), TOL);
}
void testExclusionsAnd14() {
System system;
NonbondedForce* nonbonded = new NonbondedForce();
for (int i = 0; i < 5; ++i) {
system.addParticle(1.0);
nonbonded->addParticle(0, 1.5, 0);
}
vector<pair<int, int> > bonds;
bonds.push_back(pair<int, int>(0, 1));
bonds.push_back(pair<int, int>(1, 2));
bonds.push_back(pair<int, int>(2, 3));
bonds.push_back(pair<int, int>(3, 4));
nonbonded->createExceptionsFromBonds(bonds, 0.0, 0.0);
int first14, second14;
for (int i = 0; i < nonbonded->getNumExceptions(); i++) {
int particle1, particle2;
double chargeProd, sigma, epsilon;
nonbonded->getExceptionParameters(i, particle1, particle2, chargeProd, sigma, epsilon);
if ((particle1 == 0 && particle2 == 3) || (particle1 == 3 && particle2 == 0))
first14 = i;
if ((particle1 == 1 && particle2 == 4) || (particle1 == 4 && particle2 == 1))
second14 = i;
}
system.addForce(nonbonded);
VerletIntegrator integrator(0.01);
Context context(system, integrator, platform);
for (int i = 1; i < 5; ++i) {
// Test LJ forces
vector<Vec3> positions(5);
const double r = 1.0;
for (int j = 0; j < 5; ++j) {
nonbonded->setParticleParameters(j, 0, 1.5, 0);
positions[j] = Vec3(0, j, 0);
}
nonbonded->setParticleParameters(0, 0, 1.5, 1);
nonbonded->setParticleParameters(i, 0, 1.5, 1);
nonbonded->setExceptionParameters(first14, 0, 3, 0, 1.5, i == 3 ? 0.5 : 0.0);
nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0.0);
positions[i] = Vec3(r, 0, 0);
context.reinitialize();
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
double x = 1.5/r;
double eps = 1.0;
double force = 4.0*eps*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/r;
double energy = 4.0*eps*(std::pow(x, 12.0)-std::pow(x, 6.0));
if (i == 3) {
force *= 0.5;
energy *= 0.5;
}
if (i < 3) {
force = 0;
energy = 0;
}
ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[i], TOL);
ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL);
// Test Coulomb forces
nonbonded->setParticleParameters(0, 2, 1.5, 0);
nonbonded->setParticleParameters(i, 2, 1.5, 0);
nonbonded->setExceptionParameters(first14, 0, 3, i == 3 ? 4/1.2 : 0, 1.5, 0);
nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0);
context.reinitialize();
context.setPositions(positions);
state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces2 = state.getForces();
force = ONE_4PI_EPS0*4/(r*r);
energy = ONE_4PI_EPS0*4/r;
if (i == 3) {
force /= 1.2;
energy /= 1.2;
}
if (i < 3) {
force = 0;
energy = 0;
}
ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces2[0], TOL);
ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces2[i], TOL);
ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL);
}
}
void testCutoff() {
System system;
system.addParticle(1.0);
system.addParticle(1.0);
system.addParticle(1.0);
VerletIntegrator integrator(0.01);
NonbondedForce* forceField = new NonbondedForce();
forceField->addParticle(1.0, 1, 0);
forceField->addParticle(1.0, 1, 0);
forceField->addParticle(1.0, 1, 0);
forceField->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic);
const double cutoff = 2.9;
forceField->setCutoffDistance(cutoff);
const double eps = 50.0;
forceField->setReactionFieldDielectric(eps);
system.addForce(forceField);
ASSERT(!forceField->usesPeriodicBoundaryConditions());
ASSERT(!system.usesPeriodicBoundaryConditions());
Context context(system, integrator, platform);
vector<Vec3> positions(3);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(0, 2, 0);
positions[2] = Vec3(0, 3, 0);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
const double krf = (1.0/(cutoff*cutoff*cutoff))*(eps-1.0)/(2.0*eps+1.0);
const double crf = (1.0/cutoff)*(3.0*eps)/(2.0*eps+1.0);
const double force1 = ONE_4PI_EPS0*(1.0)*(0.25-2.0*krf*2.0);
const double force2 = ONE_4PI_EPS0*(1.0)*(1.0-2.0*krf*1.0);
ASSERT_EQUAL_VEC(Vec3(0, -force1, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(0, force1-force2, 0), forces[1], TOL);
ASSERT_EQUAL_VEC(Vec3(0, force2, 0), forces[2], TOL);
const double energy1 = ONE_4PI_EPS0*(1.0)*(0.5+krf*4.0-crf);
const double energy2 = ONE_4PI_EPS0*(1.0)*(1.0+krf*1.0-crf);
ASSERT_EQUAL_TOL(energy1+energy2, state.getPotentialEnergy(), TOL);
}
void testCutoff14() {
System system;
VerletIntegrator integrator(0.01);
NonbondedForce* nonbonded = new NonbondedForce();
nonbonded->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic);
for (int i = 0; i < 5; i++) {
system.addParticle(1.0);
nonbonded->addParticle(0, 1.5, 0);
}
const double cutoff = 3.5;
nonbonded->setCutoffDistance(cutoff);
const double eps = 30.0;
nonbonded->setReactionFieldDielectric(eps);
vector<pair<int, int> > bonds;
bonds.push_back(pair<int, int>(0, 1));
bonds.push_back(pair<int, int>(1, 2));
bonds.push_back(pair<int, int>(2, 3));
bonds.push_back(pair<int, int>(3, 4));
nonbonded->createExceptionsFromBonds(bonds, 0.0, 0.0);
int first14, second14;
for (int i = 0; i < nonbonded->getNumExceptions(); i++) {
int particle1, particle2;
double chargeProd, sigma, epsilon;
nonbonded->getExceptionParameters(i, particle1, particle2, chargeProd, sigma, epsilon);
if ((particle1 == 0 && particle2 == 3) || (particle1 == 3 && particle2 == 0))
first14 = i;
if ((particle1 == 1 && particle2 == 4) || (particle1 == 4 && particle2 == 1))
second14 = i;
}
system.addForce(nonbonded);
ASSERT(!nonbonded->usesPeriodicBoundaryConditions());
ASSERT(!system.usesPeriodicBoundaryConditions());
Context context(system, integrator, platform);
vector<Vec3> positions(5);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(1, 0, 0);
positions[2] = Vec3(2, 0, 0);
positions[3] = Vec3(3, 0, 0);
positions[4] = Vec3(4, 0, 0);
for (int i = 1; i < 5; ++i) {
// Test LJ forces
nonbonded->setParticleParameters(0, 0, 1.5, 1);
for (int j = 1; j < 5; ++j)
nonbonded->setParticleParameters(j, 0, 1.5, 0);
nonbonded->setParticleParameters(i, 0, 1.5, 1);
nonbonded->setExceptionParameters(first14, 0, 3, 0, 1.5, i == 3 ? 0.5 : 0.0);
nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0.0);
context.reinitialize();
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
double r = positions[i][0];
double x = 1.5/r;
double e = 1.0;
double force = 4.0*e*(12*std::pow(x, 12.0)-6*std::pow(x, 6.0))/r;
double energy = 4.0*e*(std::pow(x, 12.0)-std::pow(x, 6.0));
if (i == 3) {
force *= 0.5;
energy *= 0.5;
}
if (i < 3 || r > cutoff) {
force = 0;
energy = 0;
}
ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[i], TOL);
ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL);
// Test Coulomb forces
const double q = 0.7;
nonbonded->setParticleParameters(0, q, 1.5, 0);
nonbonded->setParticleParameters(i, q, 1.5, 0);
nonbonded->setExceptionParameters(first14, 0, 3, i == 3 ? q*q/1.2 : 0, 1.5, 0);
nonbonded->setExceptionParameters(second14, 1, 4, 0, 1.5, 0);
context.reinitialize();
context.setPositions(positions);
state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces2 = state.getForces();
force = ONE_4PI_EPS0*q*q/(r*r);
energy = ONE_4PI_EPS0*q*q/r;
if (i == 3) {
force /= 1.2;
energy /= 1.2;
}
if (i < 3 || r > cutoff) {
force = 0;
energy = 0;
}
ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces2[0], TOL);
ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces2[i], TOL);
ASSERT_EQUAL_TOL(energy, state.getPotentialEnergy(), TOL);
}
}
void testPeriodic() {
System system;
system.addParticle(1.0);
system.addParticle(1.0);
system.addParticle(1.0);
VerletIntegrator integrator(0.01);
NonbondedForce* nonbonded = new NonbondedForce();
nonbonded->addParticle(1.0, 1, 0);
nonbonded->addParticle(1.0, 1, 0);
nonbonded->addParticle(1.0, 1, 0);
nonbonded->addException(0, 1, 0.0, 1.0, 0.0);
nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
const double cutoff = 2.0;
nonbonded->setCutoffDistance(cutoff);
system.setDefaultPeriodicBoxVectors(Vec3(4, 0, 0), Vec3(0, 4, 0), Vec3(0, 0, 4));
system.addForce(nonbonded);
ASSERT(nonbonded->usesPeriodicBoundaryConditions());
ASSERT(system.usesPeriodicBoundaryConditions());
Context context(system, integrator, platform);
vector<Vec3> positions(3);
positions[0] = Vec3(0, 0, 0);
positions[1] = Vec3(2, 0, 0);
positions[2] = Vec3(3, 0, 0);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
const vector<Vec3>& forces = state.getForces();
const double eps = 78.3;
const double krf = (1.0/(cutoff*cutoff*cutoff))*(eps-1.0)/(2.0*eps+1.0);
const double crf = (1.0/cutoff)*(3.0*eps)/(2.0*eps+1.0);
const double force = ONE_4PI_EPS0*(1.0)*(1.0-2.0*krf*1.0);
ASSERT_EQUAL_VEC(Vec3(force, 0, 0), forces[0], TOL);
ASSERT_EQUAL_VEC(Vec3(-force, 0, 0), forces[1], TOL);
ASSERT_EQUAL_VEC(Vec3(0, 0, 0), forces[2], TOL);
ASSERT_EQUAL_TOL(2*ONE_4PI_EPS0*(1.0)*(1.0+krf*1.0-crf), state.getPotentialEnergy(), TOL);
}
void testTriclinic() {
System system;
system.addParticle(1.0);
system.addParticle(1.0);
Vec3 a(3.1, 0, 0);
Vec3 b(0.4, 3.5, 0);
Vec3 c(-0.1, -0.5, 4.0);
system.setDefaultPeriodicBoxVectors(a, b, c);
VerletIntegrator integrator(0.01);
NonbondedForce* nonbonded = new NonbondedForce();
nonbonded->addParticle(1.0, 1, 0);
nonbonded->addParticle(1.0, 1, 0);
nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
const double cutoff = 1.5;
nonbonded->setCutoffDistance(cutoff);
system.addForce(nonbonded);
Context context(system, integrator, platform);
vector<Vec3> positions(2);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
const double eps = 78.3;
const double krf = (1.0/(cutoff*cutoff*cutoff))*(eps-1.0)/(2.0*eps+1.0);
const double crf = (1.0/cutoff)*(3.0*eps)/(2.0*eps+1.0);
for (int iteration = 0; iteration < 50; iteration++) {
// Generate random positions for the two particles.
positions[0] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt);
positions[1] = a*genrand_real2(sfmt) + b*genrand_real2(sfmt) + c*genrand_real2(sfmt);
context.setPositions(positions);
// Loop over all possible periodic copies and find the nearest one.
Vec3 delta;
double distance2 = 100.0;
for (int i = -1; i < 2; i++)
for (int j = -1; j < 2; j++)
for (int k = -1; k < 2; k++) {
Vec3 d = positions[1]-positions[0]+a*i+b*j+c*k;
if (d.dot(d) < distance2) {
delta = d;
distance2 = d.dot(d);
}
}
double distance = sqrt(distance2);
// See if the force and energy are correct.
State state = context.getState(State::Forces | State::Energy);
if (distance >= cutoff) {
ASSERT_EQUAL(0.0, state.getPotentialEnergy());
ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getForces()[0], 0);
ASSERT_EQUAL_VEC(Vec3(0, 0, 0), state.getForces()[1], 0);
}
else {
const Vec3 force = delta*ONE_4PI_EPS0*(-1.0/(distance*distance*distance)+2.0*krf);
ASSERT_EQUAL_TOL(ONE_4PI_EPS0*(1.0/distance+krf*distance*distance-crf), state.getPotentialEnergy(), 1e-4);
ASSERT_EQUAL_VEC(force, state.getForces()[0], 1e-4);
ASSERT_EQUAL_VEC(-force, state.getForces()[1], 1e-4);
}
}
}
void testLargeSystem() {
const int numMolecules = 600;
const int numParticles = numMolecules*2;
const double cutoff = 2.0;
const double boxSize = 20.0;
const double tol = 2e-3;
ReferencePlatform reference;
System system;
for (int i = 0; i < numParticles; i++)
system.addParticle(1.0);
NonbondedForce* nonbonded = new NonbondedForce();
HarmonicBondForce* bonds = new HarmonicBondForce();
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numMolecules; i++) {
if (i < numMolecules/2) {
nonbonded->addParticle(-1.0, 0.2, 0.1);
nonbonded->addParticle(1.0, 0.1, 0.1);
}
else {
nonbonded->addParticle(-1.0, 0.2, 0.2);
nonbonded->addParticle(1.0, 0.1, 0.2);
}
positions[2*i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt));
positions[2*i+1] = Vec3(positions[2*i][0]+1.0, positions[2*i][1], positions[2*i][2]);
velocities[2*i] = Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt));
velocities[2*i+1] = Vec3(genrand_real2(sfmt), genrand_real2(sfmt), genrand_real2(sfmt));
bonds->addBond(2*i, 2*i+1, 1.0, 0.1);
nonbonded->addException(2*i, 2*i+1, 0.0, 0.15, 0.0);
}
// Try with cutoffs but not periodic boundary conditions, and make sure it agrees with the Reference platform.
nonbonded->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic);
nonbonded->setCutoffDistance(cutoff);
system.addForce(nonbonded);
system.addForce(bonds);
VerletIntegrator integrator1(0.01);
VerletIntegrator integrator2(0.01);
Context context(system, integrator1, platform);
Context referenceContext(system, integrator2, reference);
context.setPositions(positions);
context.setVelocities(velocities);
referenceContext.setPositions(positions);
referenceContext.setVelocities(velocities);
State state = context.getState(State::Positions | State::Velocities | State::Forces | State::Energy);
State referenceState = referenceContext.getState(State::Positions | State::Velocities | State::Forces | State::Energy);
for (int i = 0; i < numParticles; i++) {
ASSERT_EQUAL_VEC(state.getPositions()[i], referenceState.getPositions()[i], tol);
ASSERT_EQUAL_VEC(state.getVelocities()[i], referenceState.getVelocities()[i], tol);
ASSERT_EQUAL_VEC(state.getForces()[i], referenceState.getForces()[i], tol);
}
ASSERT_EQUAL_TOL(state.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol);
// Now do the same thing with periodic boundary conditions.
nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
context.reinitialize();
referenceContext.reinitialize();
context.setPositions(positions);
context.setVelocities(velocities);
referenceContext.setPositions(positions);
referenceContext.setVelocities(velocities);
state = context.getState(State::Positions | State::Velocities | State::Forces | State::Energy);
referenceState = referenceContext.getState(State::Positions | State::Velocities | State::Forces | State::Energy);
for (int i = 0; i < numParticles; i++) {
double dx = state.getPositions()[i][0]-referenceState.getPositions()[i][0];
double dy = state.getPositions()[i][1]-referenceState.getPositions()[i][1];
double dz = state.getPositions()[i][2]-referenceState.getPositions()[i][2];
ASSERT_EQUAL_TOL(dx-floor(dx/boxSize+0.5)*boxSize, 0, tol);
ASSERT_EQUAL_TOL(dy-floor(dy/boxSize+0.5)*boxSize, 0, tol);
ASSERT_EQUAL_TOL(dz-floor(dz/boxSize+0.5)*boxSize, 0, tol);
ASSERT_EQUAL_VEC(state.getVelocities()[i], referenceState.getVelocities()[i], tol);
ASSERT_EQUAL_VEC(state.getForces()[i], referenceState.getForces()[i], tol);
}
ASSERT_EQUAL_TOL(state.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol);
}
void testDispersionCorrection() {
// Create a box full of identical particles.
int gridSize = 5;
int numParticles = gridSize*gridSize*gridSize;
double boxSize = gridSize*0.7;
double cutoff = boxSize/3;
System system;
VerletIntegrator integrator(0.01);
NonbondedForce* nonbonded = new NonbondedForce();
vector<Vec3> positions(numParticles);
int index = 0;
for (int i = 0; i < gridSize; i++)
for (int j = 0; j < gridSize; j++)
for (int k = 0; k < gridSize; k++) {
system.addParticle(1.0);
nonbonded->addParticle(0, 1.1, 0.5);
positions[index] = Vec3(i*boxSize/gridSize, j*boxSize/gridSize, k*boxSize/gridSize);
index++;
}
nonbonded->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
nonbonded->setCutoffDistance(cutoff);
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
system.addForce(nonbonded);
// See if the correction has the correct value.
Context context(system, integrator, platform);
context.setPositions(positions);
double energy1 = context.getState(State::Energy).getPotentialEnergy();
nonbonded->setUseDispersionCorrection(false);
context.reinitialize();
context.setPositions(positions);
double energy2 = context.getState(State::Energy).getPotentialEnergy();
double term1 = (0.5*pow(1.1, 12)/pow(cutoff, 9))/9;
double term2 = (0.5*pow(1.1, 6)/pow(cutoff, 3))/3;
double expected = 8*M_PI*numParticles*numParticles*(term1-term2)/(boxSize*boxSize*boxSize);
ASSERT_EQUAL_TOL(expected, energy1-energy2, 1e-4);
// Now modify half the particles to be different, and see if it is still correct.
int numType2 = 0;
for (int i = 0; i < numParticles; i += 2) {
nonbonded->setParticleParameters(i, 0, 1, 1);
numType2++;
}
int numType1 = numParticles-numType2;
nonbonded->updateParametersInContext(context);
energy2 = context.getState(State::Energy).getPotentialEnergy();
nonbonded->setUseDispersionCorrection(true);
context.reinitialize();
context.setPositions(positions);
energy1 = context.getState(State::Energy).getPotentialEnergy();
term1 = ((numType1*(numType1+1))/2)*(0.5*pow(1.1, 12)/pow(cutoff, 9))/9;
term2 = ((numType1*(numType1+1))/2)*(0.5*pow(1.1, 6)/pow(cutoff, 3))/3;
term1 += ((numType2*(numType2+1))/2)*(1*pow(1.0, 12)/pow(cutoff, 9))/9;
term2 += ((numType2*(numType2+1))/2)*(1*pow(1.0, 6)/pow(cutoff, 3))/3;
double combinedSigma = 0.5*(1+1.1);
double combinedEpsilon = sqrt(1*0.5);
term1 += (numType1*numType2)*(combinedEpsilon*pow(combinedSigma, 12)/pow(cutoff, 9))/9;
term2 += (numType1*numType2)*(combinedEpsilon*pow(combinedSigma, 6)/pow(cutoff, 3))/3;
term1 /= (numParticles*(numParticles+1))/2;
term2 /= (numParticles*(numParticles+1))/2;
expected = 8*M_PI*numParticles*numParticles*(term1-term2)/(boxSize*boxSize*boxSize);
ASSERT_EQUAL_TOL(expected, energy1-energy2, 1e-4);
}
void testChangingParameters() {
const int numMolecules = 600;
const int numParticles = numMolecules*2;
const double cutoff = 2.0;
const double boxSize = 20.0;
const double tol = 2e-3;
ReferencePlatform reference;
System system;
for (int i = 0; i < numParticles; i++)
system.addParticle(1.0);
NonbondedForce* nonbonded = new NonbondedForce();
vector<Vec3> positions(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numMolecules; i++) {
if (i < numMolecules/2) {
nonbonded->addParticle(-1.0, 0.2, 0.1);
nonbonded->addParticle(1.0, 0.1, 0.1);
}
else {
nonbonded->addParticle(-1.0, 0.2, 0.2);
nonbonded->addParticle(1.0, 0.1, 0.2);
}
positions[2*i] = Vec3(boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt), boxSize*genrand_real2(sfmt));
positions[2*i+1] = Vec3(positions[2*i][0]+1.0, positions[2*i][1], positions[2*i][2]);
system.addConstraint(2*i, 2*i+1, 1.0);
nonbonded->addException(2*i, 2*i+1, 0.0, 0.15, 0.0);
}
nonbonded->setNonbondedMethod(NonbondedForce::PME);
nonbonded->setCutoffDistance(cutoff);
system.addForce(nonbonded);
system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
// See if the forces and energies match the Reference platform.
VerletIntegrator integrator1(0.01);
VerletIntegrator integrator2(0.01);
Context context(system, integrator1, platform);
Context referenceContext(system, integrator2, reference);
context.setPositions(positions);
referenceContext.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
State referenceState = referenceContext.getState(State::Forces | State::Energy);
for (int i = 0; i < numParticles; i++)
ASSERT_EQUAL_VEC(state.getForces()[i], referenceState.getForces()[i], tol);
ASSERT_EQUAL_TOL(state.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol);
// Now modify parameters and see if they still agree.
for (int i = 0; i < numParticles; i += 5) {
double charge, sigma, epsilon;
nonbonded->getParticleParameters(i, charge, sigma, epsilon);
nonbonded->setParticleParameters(i, 1.5*charge, 1.1*sigma, 1.7*epsilon);
}
nonbonded->updateParametersInContext(context);
nonbonded->updateParametersInContext(referenceContext);
state = context.getState(State::Forces | State::Energy);
referenceState = referenceContext.getState(State::Forces | State::Energy);
for (int i = 0; i < numParticles; i++)
ASSERT_EQUAL_VEC(state.getForces()[i], referenceState.getForces()[i], tol);
ASSERT_EQUAL_TOL(state.getPotentialEnergy(), referenceState.getPotentialEnergy(), tol);
}
void testSwitchingFunction(NonbondedForce::NonbondedMethod method) {
System system;
system.setDefaultPeriodicBoxVectors(Vec3(6, 0, 0), Vec3(0, 6, 0), Vec3(0, 0, 6));
system.addParticle(1.0);
system.addParticle(1.0);
VerletIntegrator integrator(0.01);
NonbondedForce* nonbonded = new NonbondedForce();
nonbonded->addParticle(0, 1.2, 1);
nonbonded->addParticle(0, 1.4, 2);
nonbonded->setNonbondedMethod(method);
nonbonded->setCutoffDistance(2.0);
nonbonded->setUseSwitchingFunction(true);
nonbonded->setSwitchingDistance(1.5);
nonbonded->setUseDispersionCorrection(false);
system.addForce(nonbonded);
Context context(system, integrator, platform);
vector<Vec3> positions(2);
positions[0] = Vec3(0, 0, 0);
double eps = SQRT_TWO;
// Compute the interaction at various distances.
for (double r = 1.0; r < 2.5; r += 0.1) {
positions[1] = Vec3(r, 0, 0);
context.setPositions(positions);
State state = context.getState(State::Forces | State::Energy);
// See if the energy is correct.
double x = 1.3/r;
double expectedEnergy = 4.0*eps*(std::pow(x, 12.0)-std::pow(x, 6.0));
double switchValue;
if (r <= 1.5)
switchValue = 1;
else if (r >= 2.0)
switchValue = 0;
else {
double t = (r-1.5)/0.5;
switchValue = 1+t*t*t*(-10+t*(15-t*6));
}
ASSERT_EQUAL_TOL(switchValue*expectedEnergy, state.getPotentialEnergy(), TOL);
// See if the force is the gradient of the energy.
double delta = 1e-3;
positions[1] = Vec3(r-delta, 0, 0);
context.setPositions(positions);
double e1 = context.getState(State::Energy).getPotentialEnergy();
positions[1] = Vec3(r+delta, 0, 0);
context.setPositions(positions);
double e2 = context.getState(State::Energy).getPotentialEnergy();
ASSERT_EQUAL_TOL((e2-e1)/(2*delta), state.getForces()[0][0], 1e-3);
}
}
void runPlatformTests();
int main(int argc, char* argv[]) {
try {
initializeTests(argc, argv);
testCoulomb();
testLJ();
testExclusionsAnd14();
testCutoff();
testCutoff14();
testPeriodic();
testTriclinic();
testLargeSystem();
testDispersionCorrection();
testChangingParameters();
testSwitchingFunction(NonbondedForce::CutoffNonPeriodic);
testSwitchingFunction(NonbondedForce::PME);
runPlatformTests();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2008-2015 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "openmm/NonbondedForce.h"
#include "openmm/System.h"
#include "openmm/LangevinIntegrator.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <vector>
using namespace OpenMM;
using namespace std;
void testConstraints() {
const int numMolecules = 10;
const int numParticles = numMolecules*3;
const int numConstraints = numMolecules*3;
const double temp = 100.0;
System system;
LangevinIntegrator integrator(temp, 2.0, 0.001);
integrator.setConstraintTolerance(1e-5);
NonbondedForce* forceField = new NonbondedForce();
for (int i = 0; i < numMolecules; ++i) {
system.addParticle(16.0);
system.addParticle(1.0);
system.addParticle(1.0);
forceField->addParticle(-0.82, 0.317, 0.65);
forceField->addParticle(0.41, 1.0, 0.0);
forceField->addParticle(0.41, 1.0, 0.0);
system.addConstraint(i*3, i*3+1, 0.1);
system.addConstraint(i*3, i*3+2, 0.1);
system.addConstraint(i*3+1, i*3+2, 0.163);
}
system.addForce(forceField);
Context context(system, integrator, platform);
vector<Vec3> positions(numParticles);
vector<Vec3> velocities(numParticles);
OpenMM_SFMT::SFMT sfmt;
init_gen_rand(0, sfmt);
for (int i = 0; i < numMolecules; ++i) {
positions[i*3] = Vec3((i%4)*0.4, (i/4)*0.4, 0);
positions[i*3+1] = positions[i*3]+Vec3(0.1, 0, 0);
positions[i*3+2] = positions[i*3]+Vec3(-0.03333, 0.09428, 0);
velocities[i*3] = Vec3(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5);
velocities[i*3+1] = Vec3(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5);
velocities[i*3+2] = Vec3(genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5, genrand_real2(sfmt)-0.5);
}
context.setPositions(positions);
context.setVelocities(velocities);
// Simulate it and see whether the constraints remain satisfied.
for (int i = 0; i < 1000; ++i) {
integrator.step(1);
State state = context.getState(State::Positions | State::Forces);
for (int j = 0; j < numConstraints; ++j) {
int particle1, particle2;
double distance;
system.getConstraintParameters(j, particle1, particle2, distance);
Vec3 p1 = state.getPositions()[particle1];
Vec3 p2 = state.getPositions()[particle2];
double dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2]));
ASSERT_EQUAL_TOL(distance, dist, 1e-5);
}
}
}
void runPlatformTests();
int main(int argc, char* argv[]) {
try {
initializeTests(argc, argv);
testConstraints();
runPlatformTests();
}
catch(const exception& e) {
cout << "exception: " << e.what() << endl;
return 1;
}
cout << "Done" << endl;
return 0;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment