185 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			185 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * =======================================================================================
 | 
						|
 *
 | 
						|
 *   Author:   Jan Eitzinger (je), jan.eitzinger@fau.de
 | 
						|
 *   Copyright (c) 2021 RRZE, University Erlangen-Nuremberg
 | 
						|
 *
 | 
						|
 *   This file is part of MD-Bench.
 | 
						|
 *
 | 
						|
 *   MD-Bench is free software: you can redistribute it and/or modify it
 | 
						|
 *   under the terms of the GNU Lesser General Public License as published
 | 
						|
 *   by the Free Software Foundation, either version 3 of the License, or
 | 
						|
 *   (at your option) any later version.
 | 
						|
 *
 | 
						|
 *   MD-Bench is distributed in the hope that it will be useful, but WITHOUT ANY
 | 
						|
 *   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 | 
						|
 *   PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
 | 
						|
 *   details.
 | 
						|
 *
 | 
						|
 *   You should have received a copy of the GNU Lesser General Public License along
 | 
						|
 *   with MD-Bench.  If not, see <https://www.gnu.org/licenses/>.
 | 
						|
 * =======================================================================================
 | 
						|
 */
 | 
						|
#include <likwid-marker.h>
 | 
						|
 | 
						|
#include <timing.h>
 | 
						|
#include <neighbor.h>
 | 
						|
#include <parameter.h>
 | 
						|
#include <atom.h>
 | 
						|
#include <stats.h>
 | 
						|
 | 
						|
double computeForceLJFullNeigh(Parameter *param, Atom *atom, Neighbor *neighbor, Stats *stats) {
 | 
						|
    int Nlocal = atom->Nlocal;
 | 
						|
    int* neighs;
 | 
						|
#ifndef EXPLICIT_TYPES
 | 
						|
    MD_FLOAT cutforcesq = param->cutforce * param->cutforce;
 | 
						|
    MD_FLOAT sigma6 = param->sigma6;
 | 
						|
    MD_FLOAT epsilon = param->epsilon;
 | 
						|
#endif
 | 
						|
 | 
						|
    for(int i = 0; i < Nlocal; i++) {
 | 
						|
        atom_fx(i) = 0.0;
 | 
						|
        atom_fy(i) = 0.0;
 | 
						|
        atom_fz(i) = 0.0;
 | 
						|
    }
 | 
						|
 | 
						|
    double S = getTimeStamp();
 | 
						|
    LIKWID_MARKER_START("force");
 | 
						|
 | 
						|
#pragma omp parallel for
 | 
						|
    for(int i = 0; i < Nlocal; i++) {
 | 
						|
        neighs = &neighbor->neighbors[i * neighbor->maxneighs];
 | 
						|
        int numneighs = neighbor->numneigh[i];
 | 
						|
        MD_FLOAT xtmp = atom_x(i);
 | 
						|
        MD_FLOAT ytmp = atom_y(i);
 | 
						|
        MD_FLOAT ztmp = atom_z(i);
 | 
						|
        MD_FLOAT fix = 0;
 | 
						|
        MD_FLOAT fiy = 0;
 | 
						|
        MD_FLOAT fiz = 0;
 | 
						|
 | 
						|
#ifdef EXPLICIT_TYPES
 | 
						|
        const int type_i = atom->type[i];
 | 
						|
#endif
 | 
						|
 | 
						|
        for(int k = 0; k < numneighs; k++) {
 | 
						|
            int j = neighs[k];
 | 
						|
            MD_FLOAT delx = xtmp - atom_x(j);
 | 
						|
            MD_FLOAT dely = ytmp - atom_y(j);
 | 
						|
            MD_FLOAT delz = ztmp - atom_z(j);
 | 
						|
            MD_FLOAT rsq = delx * delx + dely * dely + delz * delz;
 | 
						|
 | 
						|
#ifdef EXPLICIT_TYPES
 | 
						|
            const int type_j = atom->type[j];
 | 
						|
            const int type_ij = type_i * atom->ntypes + type_j;
 | 
						|
            const MD_FLOAT cutforcesq = atom->cutforcesq[type_ij];
 | 
						|
            const MD_FLOAT sigma6 = atom->sigma6[type_ij];
 | 
						|
            const MD_FLOAT epsilon = atom->epsilon[type_ij];
 | 
						|
#endif
 | 
						|
 | 
						|
            if(rsq < cutforcesq) {
 | 
						|
                MD_FLOAT sr2 = 1.0 / rsq;
 | 
						|
                MD_FLOAT sr6 = sr2 * sr2 * sr2 * sigma6;
 | 
						|
                MD_FLOAT force = 48.0 * sr6 * (sr6 - 0.5) * sr2 * epsilon;
 | 
						|
                fix += delx * force;
 | 
						|
                fiy += dely * force;
 | 
						|
                fiz += delz * force;
 | 
						|
#ifdef USE_REFERENCE_VERSION
 | 
						|
                addStat(stats->atoms_within_cutoff, 1);
 | 
						|
            } else {
 | 
						|
                addStat(stats->atoms_outside_cutoff, 1);
 | 
						|
#endif
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        atom_fx(i) += fix;
 | 
						|
        atom_fy(i) += fiy;
 | 
						|
        atom_fz(i) += fiz;
 | 
						|
 | 
						|
        addStat(stats->total_force_neighs, numneighs);
 | 
						|
        addStat(stats->total_force_iters, (numneighs + VECTOR_WIDTH - 1) / VECTOR_WIDTH);
 | 
						|
    }
 | 
						|
 | 
						|
    LIKWID_MARKER_STOP("force");
 | 
						|
    double E = getTimeStamp();
 | 
						|
    return E-S;
 | 
						|
}
 | 
						|
 | 
						|
double computeForceLJHalfNeigh(Parameter *param, Atom *atom, Neighbor *neighbor, Stats *stats) {
 | 
						|
    int Nlocal = atom->Nlocal;
 | 
						|
    int* neighs;
 | 
						|
#ifndef EXPLICIT_TYPES
 | 
						|
    MD_FLOAT cutforcesq = param->cutforce * param->cutforce;
 | 
						|
    MD_FLOAT sigma6 = param->sigma6;
 | 
						|
    MD_FLOAT epsilon = param->epsilon;
 | 
						|
#endif
 | 
						|
 | 
						|
    for(int i = 0; i < Nlocal; i++) {
 | 
						|
        atom_fx(i) = 0.0;
 | 
						|
        atom_fy(i) = 0.0;
 | 
						|
        atom_fz(i) = 0.0;
 | 
						|
    }
 | 
						|
 | 
						|
    double S = getTimeStamp();
 | 
						|
    LIKWID_MARKER_START("forceLJ-halfneigh");
 | 
						|
 | 
						|
    for(int i = 0; i < Nlocal; i++) {
 | 
						|
        neighs = &neighbor->neighbors[i * neighbor->maxneighs];
 | 
						|
        int numneighs = neighbor->numneigh[i];
 | 
						|
        MD_FLOAT xtmp = atom_x(i);
 | 
						|
        MD_FLOAT ytmp = atom_y(i);
 | 
						|
        MD_FLOAT ztmp = atom_z(i);
 | 
						|
        MD_FLOAT fix = 0;
 | 
						|
        MD_FLOAT fiy = 0;
 | 
						|
        MD_FLOAT fiz = 0;
 | 
						|
 | 
						|
#ifdef EXPLICIT_TYPES
 | 
						|
        const int type_i = atom->type[i];
 | 
						|
#endif
 | 
						|
 | 
						|
        // Pragma required to vectorize the inner loop
 | 
						|
        #pragma simd reduction(+: fix,fiy,fiz)
 | 
						|
        for(int k = 0; k < numneighs; k++) {
 | 
						|
            int j = neighs[k];
 | 
						|
            MD_FLOAT delx = xtmp - atom_x(j);
 | 
						|
            MD_FLOAT dely = ytmp - atom_y(j);
 | 
						|
            MD_FLOAT delz = ztmp - atom_z(j);
 | 
						|
            MD_FLOAT rsq = delx * delx + dely * dely + delz * delz;
 | 
						|
 | 
						|
#ifdef EXPLICIT_TYPES
 | 
						|
            const int type_j = atom->type[j];
 | 
						|
            const int type_ij = type_i * atom->ntypes + type_j;
 | 
						|
            const MD_FLOAT cutforcesq = atom->cutforcesq[type_ij];
 | 
						|
            const MD_FLOAT sigma6 = atom->sigma6[type_ij];
 | 
						|
            const MD_FLOAT epsilon = atom->epsilon[type_ij];
 | 
						|
#endif
 | 
						|
 | 
						|
            if(rsq < cutforcesq) {
 | 
						|
                MD_FLOAT sr2 = 1.0 / rsq;
 | 
						|
                MD_FLOAT sr6 = sr2 * sr2 * sr2 * sigma6;
 | 
						|
                MD_FLOAT force = 48.0 * sr6 * (sr6 - 0.5) * sr2 * epsilon;
 | 
						|
                fix += delx * force;
 | 
						|
                fiy += dely * force;
 | 
						|
                fiz += delz * force;
 | 
						|
 | 
						|
                // We do not need to update forces for ghost atoms
 | 
						|
                if(j < Nlocal) {
 | 
						|
                    atom_fx(j) -= delx * force;
 | 
						|
                    atom_fy(j) -= dely * force;
 | 
						|
                    atom_fz(j) -= delz * force;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        atom_fx(i) += fix;
 | 
						|
        atom_fy(i) += fiy;
 | 
						|
        atom_fz(i) += fiz;
 | 
						|
 | 
						|
        addStat(stats->total_force_neighs, numneighs);
 | 
						|
        addStat(stats->total_force_iters, (numneighs + VECTOR_WIDTH - 1) / VECTOR_WIDTH);
 | 
						|
    }
 | 
						|
 | 
						|
    LIKWID_MARKER_STOP("forceLJ-halfneigh");
 | 
						|
    double E = getTimeStamp();
 | 
						|
    return E-S;
 | 
						|
}
 |