int test_kinetic_energy()
{
	const unsigned long ndim=100000;
	double * mtm;
	unsigned long i;
	double kin_eng,kin_eng_test;
	
	mtm=(double*)malloc(ndim*sizeof(double));
	
	kin_eng=0;
	for(i=0;i<ndim;++i)
	{
		mtm[i]=1.;
		kin_eng+=mtm[i]*mtm[i];
	}
	kin_eng*=0.5;
	
	kinetic_energy(ndim,mtm,&kin_eng_test);
	
	if(kin_eng != kin_eng_test)
	{
		free(mtm);
		return EXIT_FAILURE;
	}
	
	
	free(mtm);
	return EXIT_SUCCESS;
	
}
double* get_statistics()
{
    //kinetic energy, LJ potential energy, springiness potential energy, pressure, instantaneous tempretature
//     double* stats = (double*) malloc( (INST_TEMP+1) * sizeof(double) ); // to nice extending for another constants
    double* stats = (double*) malloc( (5) * sizeof(double) ); // to nice extending for another constants
    
    stats[0] = kinetic_energy();
#ifdef VERBOSE
    printf("kinetic: %lf\n",stats[0]);
#endif
    stats[1] = LJ_potential();
#ifdef VERBOSE
    printf("Lj     : %lf\n",stats[1]);
#endif
    stats[2] = springiness_potential();
#ifdef VERBOSE
    printf("spring : %lf\n",stats[2]);
#endif
    stats[3] = pressure();
#ifdef VERBOSE
    printf("press. : %lf\n",stats[3]);
#endif
    //stats[4] = temperature();
    stats[4] = temperature_from_kinetic(stats[0]);
#ifdef VERBOSE
    printf("temp.  : %lf\n",stats[4]);
#endif
    
    return stats;
}
Exemple #3
0
int main(int argc, char *argv[])
{
    //============= set up MPI =================
    
    MPI_Status status;
    const int root_process = 0;
    int ierr, my_id, an_id, num_procs;

    // tag for MPI message: energy minimization convergence 
    const int tag_99 = 99;

    // initialize MPI, get my_id for this process and total number of processes
    ierr = MPI_Init(&argc, &argv);
    ierr = MPI_Comm_rank(MPI_COMM_WORLD, &my_id);
    ierr = MPI_Comm_size(MPI_COMM_WORLD, &num_procs);


    //============ get input files =============

    // default filenames
    char input_gro[MAX_STR_LEN], input_param[MAX_STR_LEN], input_mdset[MAX_STR_LEN];
    strcpy(input_gro,   "init.gro");
    strcpy(input_param, "param.txt");
    strcpy(input_mdset, "mdset.txt");

    // parse arguments (input files)
    // -gro for gro file
    // -par for parameter file
    // -mds for MD settings
    int iarg = 1;
    while (1)
    {
        if (iarg >= argc) { break; }

        if (0 == strcmp(argv[iarg], "-gro") && iarg < argc)
        {
            strcpy(input_gro, argv[iarg + 1]);
            iarg += 2;
        }
        else if (0 == strcmp(argv[iarg], "-par") && iarg < argc)
        {
            strcpy(input_param, argv[iarg + 1]);
            iarg += 2;
        }
        else if (0 == strcmp(argv[iarg], "-mds") && iarg < argc)
        {
            strcpy(input_mdset, argv[iarg + 1]);
            iarg += 2;
        }
        else
        {
            ++ iarg;
        }
    }


    //========= define variables and read MD settings ===========

    // varialbles to read from input_mdset
    RunSet *p_runset = my_malloc(sizeof(RunSet));
    Metal  *p_metal  = my_malloc(sizeof(Metal));


    // read md settings from input_mdset
    read_settings(input_mdset, p_runset, p_metal);


    // initialize timer
    time_t start_t = time(NULL);
    struct timeval tv;
    gettimeofday(&tv, NULL);
    double start_time = (tv.tv_sec) + (tv.tv_usec) * 1.0e-6;

    // time_used[0] = total
    // time_used[1] = QSC density
    // time_used[2] = QSC force
    // time_used[3] = Bonded
    // time_used[4] = Nonbonded
    // time_used[5] = CPIM matrix
    // time_used[6] = CPIM vector
    // time_used[7] = CPIM solve
    // time_used[8] = CPIM force
    // time_used[10] = QSC density communication
    
    double **time_used = my_malloc(sizeof(double *) * num_procs);
    for(an_id = 0; an_id < num_procs; ++ an_id)
    {
        time_used[an_id] = my_malloc(sizeof(double) * 15);

        int it;
        for(it = 0; it < 15; ++ it)
        {
            time_used[an_id][it] = 0.0;
        }
    }


    // Coulomb type: cut_off, wolf_sum
    if (0 == strcmp(p_runset->coulomb_type, "cut_off" )) 
    { 
        p_runset->use_coulomb = 0; 
    }
    else if (0 == strcmp(p_runset->coulomb_type, "wolf_sum")) 
    { 
        p_runset->use_coulomb = 1; 
    }
    else 
    { 
        printf("Error: unknown coulomb_type %s!\n", p_runset->coulomb_type); 
        exit(1); 
    }


    // Damped shifted force (DSF) approach for electrostatics 
    // Ref.:      Fennell and Gezelter, J. Chem. Phys. 2006, 124, 234104
    //            dx.doi.org/10.1063/1.2206581
    // Based on:  Wolf et al., J. Chem. Phys. 1999, 110, 8254
    //            dx.doi.org/10.1063/1.478738
    //            Zahn et al., J. Phys. Chem. B 2002, 106, 10725-10732
    //            dx.doi.org/10.1021/jp025949h
    // Benchmark: McCann and Acevedo, J. Chem. Theory Comput. 2013, 9, 944-950
    //            dx.doi.org/10.1021/ct300961e

    // note: p_runset->rCut and p_runset->w_alpha were read from mdset.txt
    p_runset->rCut2 = p_runset->rCut * p_runset->rCut;
    double rCut     = p_runset->rCut;
    double rCut2    = p_runset->rCut2;

    double w_alpha         = p_runset->w_alpha;
    p_runset->w_a2_sqrtPI  = w_alpha * 2.0 * INV_SQRT_PI;
    p_runset->w_Const      = erfc(w_alpha * rCut) / rCut2 + 
                             p_runset->w_a2_sqrtPI * exp(-w_alpha * w_alpha * rCut2) / rCut;
    p_runset->w_erfc_arCut = erfc(w_alpha * rCut)/ rCut;



    // van der Waals type: cut_off or shifted
    if (0 == strcmp(p_runset->vdw_type, "cut_off")) 
    { 
        p_runset->use_vdw = 0; 
    }
    else if (0 == strcmp(p_runset->vdw_type, "shifted")) 
    { 
        p_runset->use_vdw = 1; 
    }
    else 
    { 
        printf("Error: unknown vdw_type %s!\n", p_runset->vdw_type); 
        exit(1); 
    }


    // Shifted force method for Lennard-Jones potential
    // Ref:   Toxvaerd and Dyre, J. Chem. Phys. 2011, 134, 081102
    //        dx.doi.org/10.1063/1.3558787

    p_runset->inv_rc12 = 1.0 / pow(rCut, 12.0);
    p_runset->inv_rc6  = 1.0 / pow(rCut, 6.0);


    //============== read force field parameters from param.txt =================
    
    Topol *p_topol = my_malloc(sizeof(Topol));

    int mol, atom;
    int number_VSites, number_Cstrs;

    // variables for bonded and nonbonded interaction


    // CPIM: capacitance-polarizability interaction model
    // Ref.: a) Jensen and Jensen, J. Phys. Chem. C, 2008, 112, 15697-15703
    //          dx.doi.org/10.1021/jp804116z
    //       b) Morton and Jensen, J. Chem. Phys., 2010, 133, 074103
    //          dx.doi.org/10.1063/1.3457365
    //
    // p_metal->cpff_polar: polarizability
    // p_metal->cpff_capac: capacitance
    // p_metal->n_NPs:      number of nanoparticles
    // p_metal->cpff_chg:   total charge of a nanoparticle
    // p_metal->start_NP:   first atom of a nanoparticle
    // p_metal->end_NP:     last atom of a nanoparticle
    

    // read parameters from input_param, step 1
    read_param_1(input_param, p_topol, p_metal);


    // allocate memory for arrays

    // CPIM charge and indices
    p_metal->cpff_chg = my_malloc(p_metal->n_NPs * sizeof(double));
    p_metal->start_NP = my_malloc(p_metal->n_NPs * sizeof(int));
    p_metal->end_NP   = my_malloc(p_metal->n_NPs * sizeof(int));


    // molecules and atom parameters
    // For a given molecule type (mol from 0 to p_topol->mol_types-1):
    // p_topol->atom_num[mol]:  its number of atoms
    // p_topol->mol_num[mol]:   the number of this type of molecule in the system
    p_topol->atom_num   = my_malloc(p_topol->mol_types * sizeof(int));
    p_topol->mol_num    = my_malloc(p_topol->mol_types * sizeof(int));
    p_topol->atom_param = my_malloc(p_topol->mol_types * sizeof(AtomParam *));


    // van der Waals interaction parameters
    NonbondedParam *data_nonbonded = 
        my_malloc_2(p_topol->n_types * p_topol->n_types * sizeof(NonbondedParam), "data_nonbonded");

    p_topol->nonbonded_param =
        my_malloc(p_topol->n_types * sizeof(NonbondedParam *));

    int i_type;
    for(i_type = 0; i_type < p_topol->n_types; ++ i_type)
    {
        p_topol->nonbonded_param[i_type] =
            &(data_nonbonded[p_topol->n_types * i_type]);
    }


    // bonded potentials: bond, pair, angle, dihedral
    int *data_bonded = my_malloc(sizeof(int) * p_topol->mol_types * 6);
    p_topol->n_bonds       = &(data_bonded[0]);
    p_topol->n_pairs       = &(data_bonded[p_topol->mol_types]);
    p_topol->n_angles      = &(data_bonded[p_topol->mol_types * 2]);
    p_topol->n_dihedrals   = &(data_bonded[p_topol->mol_types * 3]);
    p_topol->n_vsites      = &(data_bonded[p_topol->mol_types * 4]);
    p_topol->n_constraints = &(data_bonded[p_topol->mol_types * 5]);

    p_topol->vsite_funct = my_malloc(p_topol->mol_types * sizeof(int *)) ;

    p_topol->bond_param     = my_malloc(p_topol->mol_types * sizeof(BondParam *));
    p_topol->pair_param     = my_malloc(p_topol->mol_types * sizeof(PairParam *)) ;
    p_topol->angle_param    = my_malloc(p_topol->mol_types * sizeof(AngleParam *));
    p_topol->dihedral_param = my_malloc(p_topol->mol_types * sizeof(DihedralParam *)) ;
    p_topol->vsite_4        = my_malloc(p_topol->mol_types * sizeof(VSite_4 *)) ;
    p_topol->constraint     = my_malloc(p_topol->mol_types * sizeof(Constraint *)) ;

    p_topol->exclude = my_malloc(p_topol->mol_types * sizeof(int **)) ;


    // Quantum Sutton-Chen densities for metal
    if (p_metal->min >=0 && p_metal->max >= p_metal->min)
    {
        p_metal->inv_sqrt_dens = my_malloc(sizeof(double) * p_metal->num);
    }


    // read parameters from input_param, step 2
    read_param_2(input_param, p_topol, p_metal);

    int nAtoms = p_topol->n_atoms;
    int nMols  = p_topol->n_mols;


    // count number of virtual sites and constraints
    number_VSites = 0;
    number_Cstrs  = 0;
    for(mol = 0; mol < p_topol->mol_types; ++ mol)
    {
        number_VSites += p_topol->n_vsites[mol] * p_topol->mol_num[mol];
        number_Cstrs  += p_topol->n_constraints[mol] * p_topol->mol_num[mol];
    }


    // Gaussian distribution width for capacitance-polarizability model
    // see Mayer, Phys. Rev. B 2007, 75, 045407
    // and Jensen, J. Phys. Chem. C 2008, 112, 15697

    p_metal->inv_polar = 1.0 / p_metal->cpff_polar;
    p_metal->inv_capac = 1.0 / p_metal->cpff_capac;
    
    double R_q = sqrt(2.0 / M_PI) * p_metal->cpff_capac;
    double R_p = pow(sqrt(2.0 / M_PI) * p_metal->cpff_polar / 3.0, 1.0 / 3.0);

    p_metal->inv_R_qq = 1.0 / sqrt(R_q * R_q + R_q * R_q);
    p_metal->inv_R_pq = 1.0 / sqrt(R_p * R_p + R_q * R_q);
    p_metal->inv_R_pp = 1.0 / sqrt(R_p * R_p + R_p * R_p);


    // print info
    if (root_process == my_id) 
    {
        printf("\n");
        printf("              +-----------------------------------------------------+\n");
        printf("              |             CapacMD program version 1.0             |\n");
        printf("              |         Xin Li, TheoChemBio, KTH, Stockholm         |\n");
        printf("              +-----------------------------------------------------+\n");
        printf("\n");

        printf("              .------------------ reference paper ------------------.\n");
        printf("\n");
        printf("    Molecular Dynamics Simulations using a Capacitance-Polarizability Force Field,\n");
        printf("    Xin Li and Hans Agren, J. Phys. Chem. C, 2015, DOI: 10.1021/acs.jpcc.5b04347\n");
        printf("\n");
        printf("\n");

        printf("    Calculation started at %s", ctime(&start_t));
        printf("    Parallelized via MPI, number of processors = %d\n", num_procs);
        printf("\n");
        printf("\n");

        printf("              .------------------ run parameters -------------------.\n");
        printf("\n");
        printf("    run_type = %s, ensemble = %s\n", p_runset->run_type, p_runset->ensemble);
        printf("    vdw_type = %s, coulomb_type = %s\n", p_runset->vdw_type, p_runset->coulomb_type);

        printf("    rCut = %.3f nm, ", rCut);
        if (1 == p_runset->use_coulomb)
        {
            printf("alpha = %.3f nm^-1", p_runset->w_alpha);
        }
        printf("\n");

        printf("    ref_T = %.1f K\n", p_runset->ref_temp);
        printf("\n");
        printf("\n");

        printf("              .------------------- molecule info -------------------.\n");
        printf("\n");
        printf("    There are %d types of molecules.\n", p_topol->mol_types);
        printf("\n");

        for(mol = 0; mol < p_topol->mol_types; ++ mol)
        {
            printf("    Molecule[%5d], num= %5d\n", mol, p_topol->mol_num[mol]);
            for(atom = 0; atom < p_topol->atom_num[mol]; ++ atom)
            {
                printf("    Atom[%5d], charge= %8.3f, mass= %8.3f, atomtype= %5d\n",
                       atom, p_topol->atom_param[mol][atom].charge,
                       p_topol->atom_param[mol][atom].mass, 
                       p_topol->atom_param[mol][atom].atomtype);
            }
            printf("\n");
        }
        printf("\n");
    }


    //=========== distribute molecules/atoms/metals among the procs ==============

    Task *p_task = my_malloc(sizeof(Task));

    int *data_start_end = my_malloc(sizeof(int) * num_procs * 6);
    p_task->start_mol   = &(data_start_end[0]);
    p_task->end_mol     = &(data_start_end[num_procs]);
    p_task->start_atom  = &(data_start_end[num_procs * 2]);
    p_task->end_atom    = &(data_start_end[num_procs * 3]);
    p_task->start_metal = &(data_start_end[num_procs * 4]);
    p_task->end_metal   = &(data_start_end[num_procs * 5]);

    find_start_end(p_task->start_mol,   p_task->end_mol,   nMols,        num_procs);
    find_start_end(p_task->start_atom,  p_task->end_atom,  nAtoms,       num_procs);
    find_start_end(p_task->start_metal, p_task->end_metal, p_metal->num, num_procs);

    long int *data_long_start_end = my_malloc(sizeof(long int) * num_procs * 2);
    p_task->start_pair = &(data_long_start_end[0]);
    p_task->end_pair   = &(data_long_start_end[num_procs]);

    long int n_pairs = nAtoms * (nAtoms - 1) / 2;
    find_start_end_long(p_task->start_pair,  p_task->end_pair,  n_pairs, num_procs);


    //============= assign indices, masses and charges =======================

    // For each atom in the system (i from 0 to p_topol->n_atoms-1)
    // atom_info[i].iAtom:  the index of this atom in its molecule type
    // atom_info[i].iMol:   the index of its molecule type
    // atom_info[i].molID:  the index of its molecule in the system

    // For each molecule in the system (im from 0 to p_topol->n_mols-1)
    // mol_info[im].mini:  the index of its first atom in the system
    // mol_info[im].maxi:  the index of its last atom in the system
    
    Atom_Info *atom_info = my_malloc(nAtoms * sizeof(Atom_Info));
    Mol_Info  *mol_info  = my_malloc(nMols  * sizeof(Mol_Info));

    assign_indices(p_topol, p_metal, atom_info, mol_info);


    //======= allocate memory for coordinates, velocities and forces ==========

    System *p_system = my_malloc(sizeof(System));

    // potential energy
    // p_system->potential[0] = total energy
    // p_system->potential[1] = metal quantum Sutton-Chen energy
    // p_system->potential[2] = non-metal bond stretching energy
    // p_system->potential[3] = non-metal angle bending energy
    // p_system->potential[4] = non-metal torsional energy
    // p_system->potential[5] = 
    // p_system->potential[6] = Long range Coulomb
    // p_system->potential[7] = Coulomb energy (including 1-4)
    // p_system->potential[8] = vdW energy (including 1-4)
    // p_system->potential[9] = 
    // p_system->potential[10] = CPIM metal charge - non-metal charge
    // p_system->potential[11] = CPIM metal dipole - non-metal charge
    // p_system->potential[12] = CPIM metal charge - metal charge
    // p_system->potential[13] = CPIM metal charge - metal dipole
    // p_system->potential[14] = CPIM metal dipole - metal dipole
    
    double *data_potential = my_malloc(sizeof(double) * 15 * 2);
    p_system->potential   = &(data_potential[0]);
    p_system->partial_pot = &(data_potential[15]);
    p_system->old_potential = 0.0;


    // virial tensor
    p_system->virial      = my_malloc(DIM * sizeof(double*));
    p_system->partial_vir = my_malloc(DIM * sizeof(double*));

    double *data_vir = my_malloc(DIM*2 * DIM * sizeof(double));
    int i;
    for (i = 0; i < DIM; ++ i)
    {
        p_system->virial[i]      = &(data_vir[DIM * i]);
        p_system->partial_vir[i] = &(data_vir[DIM * (DIM + i)]);
    }


    // box size
    // Note: for now we treat rectangular box only.
    // "p_system->box" has six elements
    // the first three are length in x, y, z
    // the second three are half of the length in x, y, z
    p_system->box = my_malloc(sizeof(double) * DIM*2);


    // coordinates, velocities and forces
    double *data_rvf = my_malloc_2(nAtoms*7 * DIM * sizeof(double), "data_rvf");
            
    p_system->rx = &(data_rvf[0]);
    p_system->ry = &(data_rvf[nAtoms]);
    p_system->rz = &(data_rvf[nAtoms*2]);
            
    p_system->vx = &(data_rvf[nAtoms*3]);
    p_system->vy = &(data_rvf[nAtoms*4]);
    p_system->vz = &(data_rvf[nAtoms*5]);
    
    p_system->fx = &(data_rvf[nAtoms*6]);
    p_system->fy = &(data_rvf[nAtoms*7]);
    p_system->fz = &(data_rvf[nAtoms*8]);
            
    // forces from slave processors
    p_system->partial_fx = &(data_rvf[nAtoms*9]);
    p_system->partial_fy = &(data_rvf[nAtoms*10]);
    p_system->partial_fz = &(data_rvf[nAtoms*11]);
            
    // old position for RATTLE constraints
    p_system->old_rx = &(data_rvf[nAtoms*12]);
    p_system->old_ry = &(data_rvf[nAtoms*13]);
    p_system->old_rz = &(data_rvf[nAtoms*14]);
            
    // old force for CG optimization
    p_system->old_fx = &(data_rvf[nAtoms*15]);
    p_system->old_fy = &(data_rvf[nAtoms*16]);
    p_system->old_fz = &(data_rvf[nAtoms*17]);

    // direction for CG optimization
    p_system->sx = &(data_rvf[nAtoms*18]);
    p_system->sy = &(data_rvf[nAtoms*19]);
    p_system->sz = &(data_rvf[nAtoms*20]);


    //================ read input gro file ==================
    
    // vQ and vP are "velocities" of the thermostat/barostat particles
    p_system->vQ = 0.0;
    p_system->vP = 0.0;

    int groNAtoms;
    read_gro(input_gro, p_system, &groNAtoms, atom_info);

    if (groNAtoms != nAtoms)
    {
       printf("Error: groNAtoms(%d) not equal to nAtoms(%d)!\n", 
              groNAtoms, nAtoms);
       exit(1);
    }

    // half of box length for PBC
    p_system->box[3] = p_system->box[0] * 0.5;
    p_system->box[4] = p_system->box[1] * 0.5;
    p_system->box[5] = p_system->box[2] * 0.5;

    p_system->volume = p_system->box[0] * p_system->box[1] * p_system->box[2];
    p_system->inv_volume = 1.0 / p_system->volume;



    //================== set MD variables ==========================

    // degree of freedom
    p_system->ndf = 3 * (nAtoms - number_VSites) - 3 - number_Cstrs;

    // temperature coupling; kT = kB*T, in kJ mol^-1
    p_runset->kT    = K_BOLTZ * p_runset->ref_temp;
    p_system->qMass = (double)p_system->ndf * p_runset->kT * p_runset->tau_temp * p_runset->tau_temp;
    //p_system->pMass = (double)p_system->ndf * p_runset->kT * p_runset->tau_pres * p_runset->tau_pres;


    // temperature control
    p_system->first_temp = 0.0;
    p_system->ext_temp = 0.0;


    // time step
    p_runset->dt_2 = 0.5 * p_runset->dt;


    //=================== CPIM matrix and arrays =========================
    // Relay matrix
    // external electric field and potential
    // induced dipoles and charges
    
    double *data_relay = NULL;

    // dimension of matrix: 4M + n_NPs
    int n_mat = p_metal->num * 4 + p_metal->n_NPs;

    // initialize mat_relay, vec_ext and vec_pq
    if (p_metal->min >=0 && p_metal->max >= p_metal->min)
    {
        data_relay = my_malloc_2(sizeof(double) * n_mat * 3, "data_relay");

        p_metal->vec_pq  = &(data_relay[0]);
        p_metal->vec_ext = &(data_relay[n_mat]);
        p_metal->diag_relay = &(data_relay[n_mat * 2]);

        int i_mat;
        for(i_mat = 0; i_mat < n_mat; ++ i_mat)
        {
            p_metal->vec_pq[i_mat]  = 0.0;
            p_metal->vec_ext[i_mat] = 0.0;
            p_metal->diag_relay[i_mat] = 1.0;
        }
    }


    //================== compute forces ==========================

    mpi_force(p_task, p_topol, atom_info, mol_info,
              p_runset, p_metal, p_system,
              my_id, num_procs, time_used);


    //========== file handles: gro, vec_pq, binary dat, parameters ========
    
    FILE *file_gro, *file_pq, *file_dat;
    file_gro = NULL;
    file_pq  = NULL;
    file_dat = NULL;


    //========== adjust velocities and write trajectories =================

    if (root_process == my_id) 
    {
        // sum potential energies
        sum_potential(p_system->potential);

        // update temperature
        remove_comm(nAtoms, atom_info, p_system);
        kinetic_energy(p_system, nAtoms, atom_info);

        // save the starting temperature
        p_system->first_temp = p_system->inst_temp;
        p_system->ext_temp   = p_runset->ref_temp;

        // creat traj.gro for writing
        file_gro = fopen("traj.gro","w") ;
        if (NULL == file_gro) 
        {
            printf( "Cannot write to traj.gro!\n" ) ;
            exit(1);
        }

        // creat vec_pq.txt for writing
        file_pq = fopen("vec_pq.txt","w") ;
        if (NULL == file_pq) 
        {
            printf( "Cannot write to vec_pq.txt!\n" ) ;
            exit(1);
        }

        // creat traj.dat for writing
        file_dat = fopen("traj.dat","w") ;
        if (NULL == file_dat) 
        {
            printf( "Cannot write to traj.dat!\n" ) ;
            exit(1);
        }

        // get maximal force
        get_fmax_rms(nAtoms, p_system);

        // write the starting geometry to gro and dat file
        write_gro(file_gro, p_system, nAtoms, atom_info, 0);
        write_binary(file_dat, p_system, nAtoms, 0);

        if (p_metal->min >=0 && p_metal->max >= p_metal->min)
        {
            write_vec_pq(file_pq, p_metal, 0);
        }


        printf("              .---------------- start MD calculation ---------------.\n");
        printf("\n");

        // check p_runset->run_type
        if (0 == strcmp(p_runset->run_type, "em") || 
            0 == strcmp(p_runset->run_type, "cg"))
        {
            printf("    Step %-5d Fmax=%10.3e  E=%15.8e\n", 
                    0, p_system->f_max, p_system->potential[0]);
        }
        else if (0 == strcmp(p_runset->run_type, "md"))
        {
            printf("  %10.3f  Fmax=%.2e  E=%.6e  T=%.3e\n", 
                   0.0, p_system->f_max, p_system->potential[0], 
                   p_system->inst_temp);
        }
    }


    //========= Now start MD steps ============================

    int step = 0;

    //===================================================
    // Energy minimization using steepest descent or CG
    //===================================================

    if (0 == strcmp(p_runset->run_type, "em") || 
        0 == strcmp(p_runset->run_type, "cg"))
    {
        p_system->vQ = 0.0;
        p_system->vP = 0.0;

        int converged = 0;
        double gamma = 0.0;
        double delta_pot;

        // initialize direction sx,sy,sz
        for(i = 0; i < nAtoms; ++ i)
        {
            p_system->old_fx[i] = p_system->fx[i];
            p_system->old_fy[i] = p_system->fy[i];
            p_system->old_fz[i] = p_system->fz[i];

            p_system->sx[i] = p_system->fx[i];
            p_system->sy[i] = p_system->fy[i];
            p_system->sz[i] = p_system->fz[i];
        }

        for(step = 1; step <= p_runset->em_steps && 0 == converged; ++ step) 
        {
            // update coordinates on root processor
            if (root_process == my_id) 
            {
                p_system->old_potential = p_system->potential[0];

                for(i = 0; i < nAtoms; ++ i)
                {
                    p_system->old_rx[i] = p_system->rx[i];
                    p_system->old_ry[i] = p_system->ry[i];
                    p_system->old_rz[i] = p_system->rz[i];

                    // fix metal coordinates?
                    if (1 == p_metal->fix_pos && 1 == atom_info[i].is_metal)
                    {
                        continue;
                    }

                    p_system->rx[i] += p_system->sx[i] / p_system->f_max * p_runset->em_length;
                    p_system->ry[i] += p_system->sy[i] / p_system->f_max * p_runset->em_length;
                    p_system->rz[i] += p_system->sz[i] / p_system->f_max * p_runset->em_length;
                }

                // apply constraints
                rattle_1st(p_runset->dt, mol_info, atom_info, p_topol, p_system);

                // zero velocities
                for(i = 0; i < nAtoms; ++ i)
                {
                    p_system->vx[i] = 0.0;
                    p_system->vy[i] = 0.0;
                    p_system->vz[i] = 0.0;
                }
            }

            // update forces
            mpi_force(p_task, p_topol, atom_info, mol_info,
                       p_runset, p_metal, p_system,
                      my_id, num_procs, time_used);

            if (root_process == my_id) 
            {
                // check potential and fmax on root processor
                sum_potential(p_system->potential);
                get_fmax_rms(nAtoms, p_system);
                delta_pot = p_system->potential[0] - p_system->old_potential;

                if (delta_pot <= 0.0) 
                { 
                    p_runset->em_length *= 1.2; 
                }
                else 
                { 
                    p_runset->em_length *= 0.2; 
                }
                
                // print info and write to the gro file
                printf("    Step %-5d Fmax=%10.3e  E=%15.8e\n", 
                        step, p_system->f_max, p_system->potential[0]);

                // write trajectories
                write_gro(file_gro, p_system, nAtoms, atom_info, step);
                write_binary(file_dat, p_system, nAtoms, step);

                if (p_metal->min >=0 && p_metal->max >= p_metal->min)
                {
                    write_vec_pq(file_pq, p_metal, step);
                }

                // check convergence
                if (p_system->f_max < p_runset->em_tol && 
                    p_system->f_rms < p_runset->em_tol * 0.5 && 
                    fabs(delta_pot) < p_runset->em_tol * 0.1)
                {
                    printf("\n");
                    printf("    F_max   (%13.6e) smaller than %e\n", 
                            p_system->f_max, p_runset->em_tol);
                    printf("    F_rms   (%13.6e) smaller than %e\n", 
                            p_system->f_rms, p_runset->em_tol * 0.5);
                    printf("    delta_E (%13.6e) smaller than %e\n", 
                            delta_pot, p_runset->em_tol * 0.1);
                    printf("\n");
                    printf("    ===========  Optimization converged ============\n");
                    converged = 1;
                }
                else
                {
                    // update gamma for CG optimization
                    // for steep descent, gamma = 0.0
                    if (0 == strcmp(p_runset->run_type, "cg"))
                    {
                        double g22 = 0.0;
                        double g12 = 0.0;
                        double g11 = 0.0;
                        for(i = 0; i < nAtoms; ++ i)
                        {
                            g22 += p_system->fx[i] * p_system->fx[i] + 
                                   p_system->fy[i] * p_system->fy[i] + 
                                   p_system->fz[i] * p_system->fz[i];
                            g12 += p_system->old_fx[i] * p_system->fx[i] + 
                                   p_system->old_fy[i] * p_system->fy[i] + 
                                   p_system->old_fz[i] * p_system->fz[i];
                            g11 += p_system->old_fx[i] * p_system->old_fx[i] + 
                                   p_system->old_fy[i] * p_system->old_fy[i] + 
                                   p_system->old_fz[i] * p_system->old_fz[i];
                        }
                        gamma = (g22 - g12) / g11;
                    }

                    for(i = 0; i < nAtoms; ++ i)
                    {
                        p_system->sx[i] = p_system->fx[i] + gamma * p_system->sx[i];
                        p_system->sy[i] = p_system->fy[i] + gamma * p_system->sy[i];
                        p_system->sz[i] = p_system->fz[i] + gamma * p_system->sz[i];

                        p_system->old_fx[i] = p_system->fx[i];
                        p_system->old_fy[i] = p_system->fy[i];
                        p_system->old_fz[i] = p_system->fz[i];
                    }
                }

                // communicate convergence
                for(an_id = 1; an_id < num_procs; ++ an_id) 
                {
                    ierr = MPI_Send(&converged, 1, MPI_INT, an_id, tag_99, MPI_COMM_WORLD);
                }
            }
            else
            {
                ierr = MPI_Recv(&converged, 1, MPI_INT, root_process, tag_99, 
                                MPI_COMM_WORLD, &status);
            }

            // exit loop if converged
            if (1 == converged) { break; }
        }
    }


    //===============================
    // MD with nvt ensemble
    //===============================

    else if (0 == strcmp(p_runset->run_type, "md"))
    {
        for (step = 1; step <= p_runset->nSteps; ++ step) 
        {
            if (root_process == my_id) 
            {
                // gradually increase the reference temperature
                if (step < p_runset->nHeating)
                {
                    p_runset->ref_temp = 
                        p_system->first_temp + 
                        (p_system->ext_temp - p_system->first_temp) * step / p_runset->nHeating;
                }
                else
                {
                    p_runset->ref_temp = p_system->ext_temp;
                }

                // update kT accordingly
                p_runset->kT = K_BOLTZ * p_runset->ref_temp;
            
                // thermostat for 1st half step
                if (0 == strcmp(p_runset->ensemble, "nvt"))
                {
                    nose_hoover(p_runset, p_system, nAtoms);
                }

                // update velocity for 1st half step
                for(i = 0; i < nAtoms; ++ i)
                {
                    // fix metal coordinates?
                    if (1 == p_metal->fix_pos && 1 == atom_info[i].is_metal)
                    {
                        continue;
                    }

                    // for virtual sites, inv_mass == 0.0;
                    double inv_mass = atom_info[i].inv_mass;
                    p_system->vx[i] += p_runset->dt_2 * p_system->fx[i] * inv_mass;
                    p_system->vy[i] += p_runset->dt_2 * p_system->fy[i] * inv_mass;
                    p_system->vz[i] += p_runset->dt_2 * p_system->fz[i] * inv_mass;
                }

                // update position for the whole time step
                // using velocity at half time step
                for(i = 0; i < nAtoms; ++ i)
                {
                    // fix metal coordinates?
                    if (1 == p_metal->fix_pos && 1 == atom_info[i].is_metal)
                    {
                        continue;
                    }

                    p_system->old_rx[i] = p_system->rx[i];
                    p_system->old_ry[i] = p_system->ry[i];
                    p_system->old_rz[i] = p_system->rz[i];

                    p_system->rx[i] += p_runset->dt * p_system->vx[i];
                    p_system->ry[i] += p_runset->dt * p_system->vy[i];
                    p_system->rz[i] += p_runset->dt * p_system->vz[i];
                }

                // apply constraints for the 1st half
                rattle_1st(p_runset->dt, mol_info, atom_info, p_topol, p_system);
            }


            // compute forces
            mpi_force(p_task, p_topol, atom_info, mol_info,
                       p_runset, p_metal, p_system,
                      my_id, num_procs, time_used);
            

            // update velocities
            if (root_process == my_id) 
            {
                // sum potential energies
                sum_potential(p_system->potential);

                // update velocity for 2nd half step
                for(i = 0; i < nAtoms; ++ i)
                {
                    // fix metal coordinates?
                    if (1 == p_metal->fix_pos && 1 == atom_info[i].is_metal)
                    {
                        continue;
                    }

                    // for virtual sites, inv_mass == 0.0;
                    double inv_mass = atom_info[i].inv_mass;
                    p_system->vx[i] += p_runset->dt_2 * p_system->fx[i] * inv_mass;
                    p_system->vy[i] += p_runset->dt_2 * p_system->fy[i] * inv_mass;
                    p_system->vz[i] += p_runset->dt_2 * p_system->fz[i] * inv_mass;
                }

                // apply constraints for the 2nd half
                rattle_2nd(p_runset->dt, mol_info, atom_info, p_topol, p_system);

                // update temperature
                kinetic_energy(p_system, nAtoms, atom_info);


                // thermostat for 2nd half step
                if (0 == strcmp(p_runset->ensemble, "nvt"))
                {
                    nose_hoover(p_runset, p_system, nAtoms);
                }


                // remove center of mass motion and update temperature
                remove_comm(nAtoms, atom_info, p_system);
                kinetic_energy(p_system, nAtoms, atom_info);


                // print information for this step
                if (0 == step % p_runset->nSave)
                {
                    // apply PBC
                    apply_pbc(nMols, mol_info, p_system->rx, p_system->ry, p_system->rz, p_system->box);
             
                    get_fmax_rms(nAtoms, p_system);
                    printf("  %10.3f  Fmax=%.2e  E=%.6e  T=%.3e (%.1f)\n", 
                           p_runset->dt * step, p_system->f_max, p_system->potential[0], 
                           p_system->inst_temp, p_runset->ref_temp);

                    // write to dat file
                    write_binary(file_dat, p_system, nAtoms, step);
                }
             
                // regularly write to gro file
                if (0 == step % (p_runset->nSave*10))
                {
                    write_gro(file_gro, p_system, nAtoms, atom_info, step);

                    if (p_metal->min >=0 && p_metal->max >= p_metal->min)
                    {
                        write_vec_pq(file_pq, p_metal, step);
                    }
                }
            }

        }
    }


    //=========== Finalize MD ====================
    
    sum_time_used(time_used, my_id, num_procs);

    if (root_process == my_id) 
    {
        fclose(file_dat);
        fclose(file_pq);
        fclose(file_gro);

#ifdef DEBUG
        int i;
        for(i = 0; i < nAtoms; ++ i)
        {
            printf("    f[%5d]= %12.5e, %12.5e, %12.5e\n", 
                    i, p_system->fx[i], p_system->fy[i], p_system->fz[i]);
        }
#endif

        printf("\n");
        printf("\n");
        printf("              .------------- final potential energies --------------.\n");
        printf("\n");

        print_potential(p_system->potential);

        time_t end_t = time(NULL);
        gettimeofday(&tv, NULL);
        double end_time = (tv.tv_sec) + (tv.tv_usec) * 1.0e-6;

        printf("    Calculation ended normally at %s", ctime(&end_t));
        printf("    %.3f seconds were used\n", end_time - start_time );
        printf("\n");
        printf("\n");

        printf("              .------------------- time usage ----------------------.\n");
        printf("\n");

        analyze_time_used(time_used, num_procs);
        printf("\n");
    }

    // free arrays
    for(an_id = 0; an_id < num_procs; ++ an_id)
    {
        free(time_used[an_id]);
    }
    free(time_used);

    free(p_metal->cpff_chg);
    free(p_metal->start_NP);
    free(p_metal->end_NP);

    free(data_bonded);
    data_bonded = NULL;

    for(mol = 0; mol < p_topol->mol_types; ++ mol) 
    {
        int atom_i;
        for(atom_i = 0; atom_i < p_topol->atom_num[mol]; ++ atom_i) 
        {
            free(p_topol->exclude[mol][atom_i]);
        }

        free(p_topol->exclude[mol]);

        free(p_topol->bond_param[mol]);
        free(p_topol->pair_param[mol]);
        free(p_topol->angle_param[mol]);
        free(p_topol->dihedral_param[mol]);

        free(p_topol->vsite_4[mol]);
        free(p_topol->vsite_funct[mol]);

        free(p_topol->constraint[mol]);
    }

    free(p_topol->exclude);

    free(p_topol->bond_param);
    free(p_topol->pair_param);
    free(p_topol->angle_param);
    free(p_topol->dihedral_param);
    p_topol->bond_param = NULL;
    p_topol->pair_param = NULL;
    p_topol->angle_param = NULL;
    p_topol->dihedral_param = NULL;

    free(p_topol->vsite_4);
    free(p_topol->vsite_funct);
    p_topol->vsite_4 = NULL;
    p_topol->vsite_funct = NULL;

    free(p_topol->constraint);
    p_topol->constraint = NULL;

    free(p_topol->mol_num);
    free(p_topol->atom_num);
    for(mol = 0; mol < p_topol->mol_types; ++ mol) 
    {
        free(p_topol->atom_param[mol]);
    }
    free(p_topol->atom_param);

    if (p_metal->min >=0 && p_metal->max >= p_metal->min)
    {
        free(p_metal->inv_sqrt_dens);
        p_metal->inv_sqrt_dens = NULL;

        free(data_relay);
        //free(p_metal->mat_relay);
        data_relay = NULL;
        //p_metal->mat_relay = NULL;
        p_metal->vec_pq    = NULL;
        p_metal->vec_ext   = NULL;
        p_metal->diag_relay = NULL;
    }



    free(data_start_end);
    free(data_long_start_end);
    data_start_end      = NULL;
    data_long_start_end = NULL;

    p_task->start_mol   = NULL;
    p_task->end_mol     = NULL;
    p_task->start_atom  = NULL;
    p_task->end_atom    = NULL;
    p_task->start_metal = NULL;
    p_task->end_metal   = NULL;
    p_task->start_pair  = NULL;
    p_task->end_pair    = NULL;

    free(atom_info);
    free(mol_info);
    atom_info = NULL;
    mol_info  = NULL;

    free(data_potential);
    data_potential = NULL;
    p_system->potential   = NULL;
    p_system->partial_pot = NULL;


    free(p_system->virial);
    free(p_system->partial_vir);
    free(data_vir);


    free(p_system->box);
    p_system->box = NULL;

    free(data_rvf);
    data_rvf = NULL;
    p_system->rx = NULL;
    p_system->ry = NULL;
    p_system->rz = NULL;
    p_system->vx = NULL;
    p_system->vy = NULL;
    p_system->vz = NULL;
    p_system->fx = NULL;
    p_system->fy = NULL;
    p_system->fz = NULL;
    p_system->partial_fx = NULL;
    p_system->partial_fy = NULL;
    p_system->partial_fz = NULL;
    p_system->old_rx = NULL;
    p_system->old_ry = NULL;
    p_system->old_rz = NULL;
    p_system->old_fx = NULL;
    p_system->old_fy = NULL;
    p_system->old_fz = NULL;
    p_system->sx = NULL;
    p_system->sy = NULL;
    p_system->sz = NULL;

    free(p_topol->nonbonded_param);
    free(data_nonbonded);
    p_topol->nonbonded_param = NULL;
    data_nonbonded = NULL;

    free(p_task);
    free(p_system);
    free(p_topol);
    free(p_metal);
    free(p_runset);
    p_task   = NULL;
    p_system = NULL;
    p_topol  = NULL;
    p_metal  = NULL;
    p_runset = NULL;

    ierr = MPI_Finalize();

    if (ierr) {}

    return 0;
}
Exemple #4
0
EXPORT	bool output_spectral_in_time(
	char		*basename,
	Wave		*wave,
	Front		*front)
{
	COMPONENT	comp;
	Locstate	state;
	float		*coords;
	float		*L = wave->rect_grid->L;
	float		*U = wave->rect_grid->U;
	float		*h = wave->rect_grid->h;
	float		kk,kx,ky,dk,Ek,Vk;
	int		icoords[MAXD];
	int		dim = wave->rect_grid->dim;
	int		status;
	char		eng_name[100],vor_name[100];
	static	FILE	*eng_file,*vor_file;
	static  int	first = YES;
	int		i, ix, iy;
	int		xmax, ymax, kmax, mx, my, dummy;
	COMPLEX		**mesh_eng,**mesh_vor;
	Locstate	lstate,rstate,bstate,tstate;

	debug_print("fft","Entered output_spectral_in_time()\n");

	if (first)
	{
	    first = NO;
	    (void) sprintf(eng_name,"%s.energy-time.dat",basename);
	    (void) sprintf(vor_name,"%s.vorticity-time.dat",basename);
	    eng_file    = fopen(eng_name,"w");
	    vor_file = fopen(vor_name,"w");
	    fprintf(eng_file,"VARIABLES=k,E(k)\n",xmax,ymax);
	    fprintf(vor_file,"VARIABLES=k,V(k)\n",xmax,ymax);
	}


 	xmax = wave->rect_grid->gmax[0];
 	ymax = wave->rect_grid->gmax[1];
	if (!Powerof2(xmax,&mx,&dummy) || !Powerof2(ymax,&my,&dummy))
	{
	    screen("output_spectral_in_time() cannot analyze "
				"mesh not power of 2\n");
	    screen("xmax = %d  ymax = %d\n",xmax,ymax);
	    return FUNCTION_FAILED;
	}
	bi_array(&mesh_eng,xmax,ymax,sizeof(COMPLEX));
	bi_array(&mesh_vor,xmax,ymax,sizeof(COMPLEX));
	for (iy = 0; iy < ymax; ++iy)
	{
	    for (ix = 0; ix < xmax; ++ix)
	    {
	    	icoords[0] = ix; icoords[1] = iy;
	    	coords = Rect_coords(icoords,wave);
	    	comp = Rect_comp(icoords,wave);
	    	state = Rect_state(icoords,wave);

		if (ix != 0) icoords[0] = ix - 1;
		else icoords[0] = ix;
	    	lstate = Rect_state(icoords,wave);
		if (ix != xmax-1) icoords[0] = ix + 1;
		else icoords[0] = ix;
	    	rstate = Rect_state(icoords,wave);

		icoords[0] = ix;
		if (iy != 0) icoords[1] = iy - 1;
		else icoords[1] = iy;
	    	bstate = Rect_state(icoords,wave);
		if (iy != ymax-1) icoords[1] = iy + 1;
		else icoords[1] = iy;
	    	tstate = Rect_state(icoords,wave);

		mesh_eng[ix][iy].real = kinetic_energy(state);
		mesh_eng[ix][iy].imag = 0.0;
		mesh_vor[ix][iy].real = (Mom(rstate)[1]/Dens(rstate) 
			    	- Mom(lstate)[1]/Dens(lstate))/h[0]
				- (Mom(tstate)[0]/Dens(tstate)
				- Mom(bstate)[0]/Dens(bstate))/h[1];
		mesh_vor[ix][iy].imag = 0.0;
	    }
	}
	fft2d(mesh_eng,xmax,ymax,1);
	fft2d(mesh_vor,xmax,ymax,1);

	kmax = xmax/2;
        dk = 2.0*PI/(U[0] - L[0]);
	fprintf(eng_file,"ZONE\n",kk,Ek);
	fprintf(vor_file,"ZONE\n",kk,Vk);
	for (i = 0; i < kmax; ++i)
	{
	    Ek = 0.0;
	    Vk = 0.0;
	    kk = 2.0*i*PI/(U[0] - L[0]);
	    for (iy = 0; iy < ymax/2; ++iy)
	    {
	    	for (ix = 0; ix < xmax/2; ++ix)
		{
		    kx = 2.0*ix*PI/(U[0] - L[0]);
		    ky = 2.0*iy*PI/(U[1] - L[1]);
		    if (sqrt(sqr(kx)+sqr(ky)) >= kk-0.5*dk &&
		        sqrt(sqr(kx)+sqr(ky)) < kk+0.5*dk)
		    {
		    	Ek += 2.0*sqrt(sqr(mesh_eng[ix][iy].real) +
				       sqr(mesh_eng[ix][iy].imag));
		    	Vk += 2.0*sqrt(sqr(mesh_vor[ix][iy].real) +
				       sqr(mesh_vor[ix][iy].imag));
		    }
		}
	    }
	    fprintf(eng_file,"%lf\t%lf\n",kk,Ek);
	    fprintf(vor_file,"%lf\t%lf\n",kk,Vk);
	}
	fflush(eng_file);
	fflush(vor_file);

	free_these(2,mesh_eng,mesh_vor);

	debug_print("fft","Left output_spectral_in_time()\n");
	return FUNCTION_SUCCEEDED;
}		/*end output_spectral_in_time*/
Exemple #5
0
EXPORT	bool output_spectral_analysis(
	char		*basename,
	Wave		*wave,
	Front		*front)
{
	COMPONENT	comp;
	Locstate	state;
	float		*coords;
	float		*L = wave->rect_grid->L;
	float		*U = wave->rect_grid->U;
	float		*h = wave->rect_grid->h;
	int		icoords[MAXD];
	int		dim = wave->rect_grid->dim;
	int		status;
	int		step = front->step;
	char		energy_name[100],vorticity_name[100],
			enstrophy_name[100],dens_name[100],pres_name[100];
	FILE		*energy_file,*vorticity_file,
			*enstrophy_file,*dens_file,*pres_file;

	debug_print("fft","Entered fft_energy_spectral()\n");

	(void) sprintf(energy_name,"%s.energy%s.dat",basename,
                         right_flush(step,TSTEP_FIELD_WIDTH));
	(void) sprintf(vorticity_name,"%s.vorticity%s.dat",basename,
                         right_flush(step,TSTEP_FIELD_WIDTH));
	(void) sprintf(enstrophy_name,"%s.enstrophy%s.dat",basename,
                         right_flush(step,TSTEP_FIELD_WIDTH));
	(void) sprintf(dens_name,"%s.density%s.dat",basename,
                         right_flush(step,TSTEP_FIELD_WIDTH));
	(void) sprintf(pres_name,"%s.pressure%s.dat",basename,
                         right_flush(step,TSTEP_FIELD_WIDTH));
	energy_file    = fopen(energy_name,"w");
	vorticity_file = fopen(vorticity_name,"w");
	enstrophy_file = fopen(enstrophy_name,"w");
	dens_file = fopen(dens_name,"w");
	pres_file = fopen(pres_name,"w");

	if (wave->sizest == 0)
	{
	    debug_print("fft","Left fft_energy_spectral()\n");
	    return FUNCTION_FAILED;
	}

	switch (dim)
	{
#if defined(ONED)
	case 1:
	{
	    int		ix;
	    int		xmax;
	    COMPLEX	*mesh_energy;

	    xmax = wave->rect_grid->gmax[0];
	    uni_array(&mesh_energy,xmax,sizeof(COMPLEX));
	    for (ix = 0; ix < xmax; ++ix)
	    {
	    	icoords[0] = ix;
	    	coords = Rect_coords(icoords,wave);
	    	comp = Rect_comp(icoords,wave);
	    	state = Rect_state(icoords,wave);
		mesh_energy[ix].real = Energy(state);
		mesh_energy[ix].imag = 0.0;
	    }
	    break;
	}
#endif /* defined(ONED) */
#if defined(TWOD)
	case 2:
	{
	    int		ix, iy;
	    int		xmax, ymax, mx, my, dummy;
	    COMPLEX	**mesh_energy,**mesh_vorticity,**mesh_enstrophy;
	    Locstate	lstate,rstate,bstate,tstate;
	    float	kk,kx,ky,dk;

	    xmax = wave->rect_grid->gmax[0];
	    ymax = wave->rect_grid->gmax[1];
	    if (!Powerof2(xmax,&mx,&dummy) || !Powerof2(ymax,&my,&dummy))
	    {
		screen("fft_energy_spectral() cannot analyze "
				"mesh not power of 2\n");
		screen("xmax = %d  ymax = %d\n",xmax,ymax);
		return FUNCTION_FAILED;
	    }
	    bi_array(&mesh_energy,xmax,ymax,sizeof(COMPLEX));
	    bi_array(&mesh_vorticity,xmax,ymax,sizeof(COMPLEX));
	    fprintf(energy_file,"zone  i=%d, j=%d\n",xmax,ymax);
	    fprintf(vorticity_file,"zone  i=%d, j=%d\n",xmax,ymax);
	    fprintf(dens_file,"zone  i=%d, j=%d\n",xmax,ymax);
	    fprintf(pres_file,"zone  i=%d, j=%d\n",xmax,ymax);
	    fprintf(enstrophy_file,"zone  i=%d, j=%d\n",xmax,ymax);
	    for (iy = 0; iy < ymax; ++iy)
	    {
	    	for (ix = 0; ix < xmax; ++ix)
	    	{
	    	    icoords[0] = ix; icoords[1] = iy;
	    	    coords = Rect_coords(icoords,wave);
	    	    comp = Rect_comp(icoords,wave);
	    	    state = Rect_state(icoords,wave);
		    mesh_energy[ix][iy].real = kinetic_energy(state);
		    mesh_energy[ix][iy].imag = 0.0;

		    if (ix != 0) icoords[0] = ix - 1;
		    else icoords[0] = ix;
	    	    lstate = Rect_state(icoords,wave);
		    if (ix != xmax-1) icoords[0] = ix + 1;
		    else icoords[0] = ix;
	    	    rstate = Rect_state(icoords,wave);

		    icoords[0] = ix;
		    if (iy != 0) icoords[1] = iy - 1;
		    else icoords[1] = iy;
	    	    bstate = Rect_state(icoords,wave);
		    if (iy != ymax-1) icoords[1] = iy + 1;
		    else icoords[1] = iy;
	    	    tstate = Rect_state(icoords,wave);
		    mesh_vorticity[ix][iy].real = (Mom(rstate)[1]/Dens(rstate) 
			    		- Mom(lstate)[1]/Dens(lstate))/h[0]
					- (Mom(tstate)[0]/Dens(tstate)
					- Mom(bstate)[0]/Dens(bstate))/h[1];
		    mesh_vorticity[ix][iy].imag = 0.0;
		    fprintf(energy_file,"%lf\n",kinetic_energy(state));
		    fprintf(vorticity_file,"%lf\n",mesh_vorticity[ix][iy].real);
		    fprintf(enstrophy_file,"%lf\n",
		    		sqr(mesh_vorticity[ix][iy].real));
		    fprintf(dens_file,"%lf\n",Dens(state));
		    fprintf(pres_file,"%lf\n",pressure(state));
	    	}
	    }
	    fft_output2d(basename,"energy",step,wave->rect_grid,
	    				mesh_energy);
	    fft_output2d(basename,"vorticity",step,wave->rect_grid,
	    				mesh_vorticity);
	    free_these(2,mesh_energy,mesh_vorticity);
	    break;
	}
#endif /* defined(TWOD) */
#if defined(THREED)
	case 3:
	{
	    int		ix, iy, iz;
	    int		xmax, ymax, zmax;
	    COMPLEX	***mesh_energy;

	    xmax = wave->rect_grid->gmax[0];
	    ymax = wave->rect_grid->gmax[1];
	    zmax = wave->rect_grid->gmax[2];
	    tri_array(&mesh_energy,xmax,ymax,zmax,sizeof(COMPLEX));
	    for (iz = 0; iz < zmax; ++iz)
	    {
	    	icoords[2] = iz;
	    	for (iy = 0; iy < ymax; ++iy)
	    	{
	    	    icoords[1] = iy;
	    	    for (ix = 0; ix < xmax; ++ix)
	    	    {
	    	    	icoords[0] = ix;
	    	    	coords = Rect_coords(icoords,wave);
	    	    	comp = Rect_comp(icoords,wave);
	    	    	state = Rect_state(icoords,wave);
			mesh_energy[ix][iy][iz].real = Energy(state);
		    	mesh_energy[ix][iy][iz].imag = 0.0;
	    	    }
	    	}
	    }
	    break;
	}
#endif /* defined(THREED) */
	}
	fclose(energy_file);
	fclose(vorticity_file);
	fclose(enstrophy_file);
	fclose(dens_file);
	fclose(pres_file);

	debug_print("fft","Left fft_energy_spectral()\n");
	return FUNCTION_SUCCEEDED;
}		/*end fft_energy_spectral*/
Exemple #6
0
/**
 *  @brief Determine the total energy of the ion cloud.
 *
 *  The function sums the Coulomb and kinetic energy contribution of each ion
 *  by calling the IonCloud::coulomb_energy() and IonCloud::kinetic_energy()
 *  functions.
 *
 *  @return The total energy.
 */
double IonCloud::total_energy() const {
    return kinetic_energy() + coulomb_energy();
}
Exemple #7
0
int main(int argc, char *argv[]) {
	simparams X;

	X.m = 1;
	X.lambda = 1./6.;
	X.n = 4;
	X.gamma = 1./X.n;
	X.rho = 100;
	X.N = 10; // default
	X.tmax = 100;
	X.steps = 1e6;
	X.dt = X.tmax*1.0/X.steps;

	double te = 14; // ?
	if ( argc != 4 ) {
		printf("Too few arguments. 3 required, %d given\n", argc-1);
		printf("Usage: %s {N_min} {N_max} {N_step}\n", argv[0]); 
		return 1;
	}
	int N_min = abs(atoi(argv[1]));
	int N_max = abs(atoi(argv[2]));
	int N_step = abs(atoi(argv[3]));
	if (N_min == 0) {
		printf("You can't run the simulation for 0 particles\n");
		printf("I'm going to ignore this and start at %d\n",N_step);
		N_min = N_step;
	}

	double **q = (double**) malloc(N_max * sizeof(double));
	for (int i = 0; i < N_max; i++)
		q[i] = (double*) malloc(X.steps * sizeof(double));

	double **p = (double**) malloc(N_max * sizeof(double));
	for (int i = 0; i < N_max; i++)
		p[i] = (double*) malloc(X.steps * sizeof(double));

	double *Q = (double*) malloc(X.steps * sizeof(double));

	double *EKin = (double*) malloc(X.steps * sizeof(double));

	double *var = (double*) malloc(N_max * sizeof(double));
	time_t integration_time;
	double *times = (double*) malloc(N_max * sizeof(double));

        FILE* fp;
        if ((fp = fopen("Var.dat","w")) == NULL) return 1;

	for (int n = N_min; n <= N_max; n += N_step) {
		X.N = n;
		printf("### N = %d ###\n", X.N);

		printf("Setting up the simulation\n");
		setup_simulation(q, p, X.N);

		printf("Integrating differential equation\n");
		integration_time = time(NULL);
		for (int t = 0; t < X.steps-1; t++) {
			velocity_verlet_step(q, p, t, &X);
		}
		times[X.N-1] = time(NULL) - integration_time;
		printf("Total time taken: %.2f seconds\n", times[X.N-1]);

		printf("Calculating COM motion and kinetic energy\n");
		centre_of_mass_motion(Q, q, &X);
		kinetic_energy(EKin, p, &X);
		var[X.N-1] = mean_kinetic_energy(EKin, te, &X);
		fprintf(fp, "%d\t%e\t%e\n", X.N, var[X.N-1],times[X.N-1]);
		fflush(fp);

		//if ( n+N_step > N_max ) {
		printf("Writing results to disk\n");
		write_single_pointer("Q.dat", Q, X.steps, X.dt);
		write_single_pointer("EKin.dat", EKin, X.steps, X.dt);
		//}
	}

        fclose(fp);

	free(q);
	free(p);
	free(Q);
	free(EKin);
	free(var);
	free(times);

	return 0;
}
int main(){

  ///////////////////
  //Initialize data//
  ///////////////////

  time_t t;
  int i,j,k;
  int amount = 1000;				// Amount of particles
  int timesteps = 1000;				// Amount of timesteps
  int refresh = 10;				// Amount of timesteps without updating neighbour list
  double rc = 2.5; 				// Cutoff radius
  double rv;					// Neighborlist radius
  double rho = 0.5;				// Density
  double m = 1;				  	// Mass of particles
  double region = pow((amount*m)/rho,1./3.);	// Sidelength of region
  double dt = 0.005;				// Timestep
  double kB = 1;				// Boltzmannconstant
  double g = 0;					// Guiding factor
  double T = 1;					// Temperature
  double sigma = sqrt((2*kB*T*g)/m);		// Whitenoise factor
  double sig = sqrt((kB*T)/m);			// Initial velocity factor
  double vmax;					// Maximum velocity of particles
  double kinetic;				// Kinetic energy
  double positions[amount][3];			// Particle positions
  double velocities[amount][3];			// Particle velocities
  double forces[amount][3];			// Particle forces
  double amount_neighbors[amount];		// Amount of neighbors per particle
  double ****neighbor;				// Neighbor List
  double *vel_sum;				// For checking momentum conservation
  XiEta rnd_XiEta[amount][3];			// Array of linear independent normally distributed numbers

  srand((unsigned) time(&t));			// Set seed for random number generator

  ///////////////////////////
  //Setup initial positions//
  ///////////////////////////
  
  create_particles(positions, amount, region);
  initial_velocities(velocities, sig, m, amount);
  
  ///////////////////////////////
  //Allocate memory on the heap//
  ///////////////////////////////

  neighbor = malloc(amount*sizeof(double ***));
  if (neighbor){
    for (i=0; i<amount; ++i){
      neighbor[i] = malloc(amount*sizeof(double **));
      if (neighbor[i]){
        for (j=0; j<amount; ++j){
          neighbor[i][j] = malloc(3*sizeof(double *));
          if (!neighbor[i][j]){
            printf("\nMemory allocation error!\n");
          }
        }
      }
    }
  }

  //////////////////
  //Main algorithm//
  //////////////////

  printf("timestep\tsum velocity\tkinetic energy per particle\n");
  for (i=0; i<timesteps; i++){
    if (i%refresh==0){
      vmax = sqrt(max_abs(velocities, amount));
      rv = rc + refresh*vmax*dt;
      update_neighborlist(neighbor, amount_neighbors, positions, rv, amount, region);  
    }
    for (j=0; j<amount; j++){
      for (k=0; k<3; k++){
        rnd_XiEta[j][k] = normal_value(0,1);
      } 
    }

    calculate_force(forces, neighbor, positions, region, amount);
    update_velocity(velocities, forces, dt, g, sigma, m, rnd_XiEta, amount);
    update_position(positions, velocities, dt, sigma, rnd_XiEta, amount);
    calculate_force(forces, neighbor, positions, region, amount);
    update_velocity(velocities, forces, dt, g, sigma, m, rnd_XiEta, amount);

    if (i%100==0){
      vel_sum = sum_vel(velocities, amount);
      kinetic = kinetic_energy(velocities, m, amount);
      printf("%d\t\t%f\t%f\n", i, vel_sum[0]+vel_sum[1]+vel_sum[2], kinetic/amount);
    }
  }

  ////////////////////////////
  //Clear memory on the heap//
  ////////////////////////////

  for (i=0; i<amount; i++){
    for (j=0; j<amount; j++){
      free(neighbor[i][j]);
    }
    free(neighbor[i]);
  }
  free(neighbor);

  return 0;
}