2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
46 #include "gromacs/fileio/confio.h"
47 #include "gromacs/fileio/trxio.h"
48 #include "gromacs/fileio/xvgr.h"
49 #include "gromacs/math/functions.h"
50 #include "gromacs/math/utilities.h"
51 #include "gromacs/math/vec.h"
52 #include "gromacs/mdtypes/md_enums.h"
53 #include "gromacs/topology/index.h"
54 #include "gromacs/topology/topology.h"
55 #include "gromacs/trajectory/trajectoryframe.h"
56 #include "gromacs/utility/arraysize.h"
57 #include "gromacs/utility/cstringutil.h"
58 #include "gromacs/utility/fatalerror.h"
59 #include "gromacs/utility/futil.h"
60 #include "gromacs/utility/smalloc.h"
61 #include "gromacs/utility/strdb.h"
64 typedef struct gmx_structurefactors
{
66 int *p
; /* proton number */
67 int *n
; /* neutron number */
68 /* Parameters for the Cromer Mann fit */
69 real
**a
; /* parameter a */
70 real
**b
; /* parameter b */
71 real
*c
; /* parameter c */
72 char **atomnm
; /* atomname */
74 } gmx_structurefactors
;
76 typedef struct reduced_atom
{
82 typedef struct structure_factor
96 extern int * create_indexed_atom_type (reduced_atom_t
* atm
, int size
)
99 * create an index of the atom types found in a group
100 * i.e.: for water index_atp[0]=type_number_of_O and
101 * index_atp[1]=type_number_of_H
103 * the last element is set to 0
105 int *index_atp
, i
, i_tmp
, j
;
107 reduced_atom
*att
= static_cast<reduced_atom
*>(atm
);
111 index_atp
[0] = att
[0].t
;
112 for (i
= 1; i
< size
; i
++)
114 for (j
= 0; j
< i_tmp
; j
++)
116 if (att
[i
].t
== index_atp
[j
])
121 if (j
== i_tmp
) /* i.e. no indexed atom type is == to atm[i].t */
124 srenew (index_atp
, i_tmp
* sizeof (int));
125 index_atp
[i_tmp
- 1] = att
[i
].t
;
129 srenew (index_atp
, i_tmp
* sizeof (int));
130 index_atp
[i_tmp
- 1] = 0;
136 extern t_complex
*** rc_tensor_allocation(int x
, int y
, int z
)
143 snew(t
[0][0], x
*y
*z
);
145 for (j
= 1; j
< y
; j
++)
147 t
[0][j
] = t
[0][j
-1] + z
;
149 for (i
= 1; i
< x
; i
++)
152 t
[i
][0] = t
[i
-1][0] + y
*z
;
153 for (j
= 1; j
< y
; j
++)
155 t
[i
][j
] = t
[i
][j
-1] + z
;
162 extern void compute_structure_factor (structure_factor_t
* sft
, matrix box
,
163 reduced_atom_t
* red
, int isize
, real start_q
,
164 real end_q
, int group
, real
**sf_table
)
166 structure_factor
*sf
= static_cast<structure_factor
*>(sft
);
167 reduced_atom
*redt
= static_cast<reduced_atom
*>(red
);
171 real kdotx
, asf
, kx
, ky
, kz
, krr
;
172 int kr
, maxkx
, maxky
, maxkz
, i
, j
, k
, p
, *counter
;
175 k_factor
[XX
] = 2 * M_PI
/ box
[XX
][XX
];
176 k_factor
[YY
] = 2 * M_PI
/ box
[YY
][YY
];
177 k_factor
[ZZ
] = 2 * M_PI
/ box
[ZZ
][ZZ
];
179 maxkx
= gmx::roundToInt(end_q
/ k_factor
[XX
]);
180 maxky
= gmx::roundToInt(end_q
/ k_factor
[YY
]);
181 maxkz
= gmx::roundToInt(end_q
/ k_factor
[ZZ
]);
183 snew (counter
, sf
->n_angles
);
185 tmpSF
= rc_tensor_allocation(maxkx
, maxky
, maxkz
);
188 * compute real and imaginary part of the structure factor for every
191 fprintf(stderr
, "\n");
192 for (i
= 0; i
< maxkx
; i
++)
194 fprintf (stderr
, "\rdone %3.1f%% ", (100.0*(i
+1))/maxkx
);
196 kx
= i
* k_factor
[XX
];
197 for (j
= 0; j
< maxky
; j
++)
199 ky
= j
* k_factor
[YY
];
200 for (k
= 0; k
< maxkz
; k
++)
202 if (i
!= 0 || j
!= 0 || k
!= 0)
204 kz
= k
* k_factor
[ZZ
];
205 krr
= std::sqrt (gmx::square(kx
) + gmx::square(ky
) + gmx::square(kz
));
206 if (krr
>= start_q
&& krr
<= end_q
)
208 kr
= gmx::roundToInt(krr
/sf
->ref_k
);
209 if (kr
< sf
->n_angles
)
211 counter
[kr
]++; /* will be used for the copmutation
213 for (p
= 0; p
< isize
; p
++)
215 asf
= sf_table
[redt
[p
].t
][kr
];
217 kdotx
= kx
* redt
[p
].x
[XX
] +
218 ky
* redt
[p
].x
[YY
] + kz
* redt
[p
].x
[ZZ
];
220 tmpSF
[i
][j
][k
].re
+= std::cos(kdotx
) * asf
;
221 tmpSF
[i
][j
][k
].im
+= std::sin(kdotx
) * asf
;
228 } /* end loop on i */
230 * compute the square modulus of the structure factor, averaging on the surface
231 * kx*kx + ky*ky + kz*kz = krr*krr
232 * note that this is correct only for a (on the macroscopic scale)
235 for (i
= 0; i
< maxkx
; i
++)
237 kx
= i
* k_factor
[XX
]; for (j
= 0; j
< maxky
; j
++)
239 ky
= j
* k_factor
[YY
]; for (k
= 0; k
< maxkz
; k
++)
241 kz
= k
* k_factor
[ZZ
]; krr
= std::sqrt (gmx::square(kx
) + gmx::square(ky
)
242 + gmx::square(kz
)); if (krr
>= start_q
&& krr
<= end_q
)
244 kr
= gmx::roundToInt(krr
/ sf
->ref_k
);
245 if (kr
< sf
->n_angles
&& counter
[kr
] != 0)
248 (gmx::square(tmpSF
[i
][j
][k
].re
) +
249 gmx::square(tmpSF
[i
][j
][k
].im
))/ counter
[kr
];
262 extern gmx_structurefactors_t
*gmx_structurefactors_init(const char *datfn
)
265 /* Read the database for the structure factor of the different atoms */
268 gmx_structurefactors
*gsf
;
269 double a1
, a2
, a3
, a4
, b1
, b2
, b3
, b4
, c
;
275 gmx::FilePtr fp
= gmx::openLibraryFile(datfn
);
279 snew(gsf
->atomnm
, nralloc
);
280 snew(gsf
->a
, nralloc
);
281 snew(gsf
->b
, nralloc
);
282 snew(gsf
->c
, nralloc
);
283 snew(gsf
->p
, nralloc
);
285 gsf
->nratoms
= line_no
;
286 while (get_a_line(fp
.get(), line
, STRLEN
))
289 if (sscanf(line
, "%s %d %lf %lf %lf %lf %lf %lf %lf %lf %lf",
290 atomn
, &p
, &a1
, &a2
, &a3
, &a4
, &b1
, &b2
, &b3
, &b4
, &c
) == 11)
292 gsf
->atomnm
[i
] = gmx_strdup(atomn
);
306 gsf
->nratoms
= line_no
;
307 if (line_no
== nralloc
)
310 srenew(gsf
->atomnm
, nralloc
);
311 srenew(gsf
->a
, nralloc
);
312 srenew(gsf
->b
, nralloc
);
313 srenew(gsf
->c
, nralloc
);
314 srenew(gsf
->p
, nralloc
);
319 fprintf(stderr
, "WARNING: Error in file %s at line %d ignored\n",
324 srenew(gsf
->atomnm
, gsf
->nratoms
);
325 srenew(gsf
->a
, gsf
->nratoms
);
326 srenew(gsf
->b
, gsf
->nratoms
);
327 srenew(gsf
->c
, gsf
->nratoms
);
328 srenew(gsf
->p
, gsf
->nratoms
);
330 return static_cast<gmx_structurefactors_t
*>(gsf
);
335 extern void rearrange_atoms (reduced_atom_t
* positions
, t_trxframe
*fr
, const int * index
,
336 int isize
, const t_topology
* top
, gmx_bool flag
, gmx_structurefactors_t
*gsf
)
337 /* given the group's index, return the (continuous) array of atoms */
341 reduced_atom
*pos
= static_cast<reduced_atom
*>(positions
);
345 for (i
= 0; i
< isize
; i
++)
348 return_atom_type (*(top
->atoms
.atomname
[index
[i
]]), gsf
);
351 for (i
= 0; i
< isize
; i
++)
353 copy_rvec (fr
->x
[index
[i
]], pos
[i
].x
);
358 extern int return_atom_type (const char *name
, gmx_structurefactors_t
*gsf
)
365 { "CH1", 1 }, { "CH2", 2 }, { "CH3", 3 },
366 { "CS1", 1 }, { "CS2", 2 }, { "CS3", 3 },
367 { "CP1", 1 }, { "CP2", 2 }, { "CP3", 3 }
375 gmx_structurefactors
*gsft
= static_cast<gmx_structurefactors
*>(gsf
);
377 NCMT
= gsft
->nratoms
;
381 for (i
= 0; (i
< asize(uh
)); i
++)
383 if (std::strcmp(name
, uh
[i
].name
) == 0)
385 return NCMT
-1+uh
[i
].nh
;
389 for (i
= 0; (i
< NCMT
); i
++)
391 if (std::strncmp (name
, gsft
->atomnm
[i
], std::strlen(gsft
->atomnm
[i
])) == 0)
400 gmx_fatal(FARGS
, "\nError: atom (%s) not in list (%d types checked)!\n",
406 for (i
= 0; i
< cnt
; i
++)
408 if (std::strlen(gsft
->atomnm
[tndx
[i
]]) > static_cast<size_t>(nrc
))
410 nrc
= std::strlen(gsft
->atomnm
[tndx
[i
]]);
419 extern int gmx_structurefactors_get_sf(gmx_structurefactors_t
*gsf
, int elem
, real a
[4], real b
[4], real
*c
)
424 gmx_structurefactors
*gsft
= static_cast<gmx_structurefactors
*>(gsf
);
427 for (i
= 0; i
< 4; i
++)
429 a
[i
] = gsft
->a
[elem
][i
];
430 b
[i
] = gsft
->b
[elem
][i
];
438 extern int do_scattering_intensity (const char* fnTPS
, const char* fnNDX
,
439 const char* fnXVG
, const char *fnTRX
,
441 real start_q
, real end_q
,
442 real energy
, int ng
, const gmx_output_env_t
*oenv
)
444 int i
, *isize
, flags
= TRX_READ_X
, **index_atp
;
451 reduced_atom_t
**red
;
452 structure_factor
*sf
;
458 gmx_structurefactors_t
*gmx_sf
;
465 gmx_sf
= gmx_structurefactors_init(fnDAT
);
467 gmx_structurefactors_get_sf(gmx_sf
, 0, a
, b
, &c
);
472 /* Read the topology informations */
473 read_tps_conf (fnTPS
, &top
, &ePBC
, &xtop
, nullptr, box
, TRUE
);
476 /* groups stuff... */
481 fprintf (stderr
, "\nSelect %d group%s\n", ng
,
485 get_index (&top
.atoms
, fnNDX
, ng
, isize
, index
, grpname
);
489 rd_index (fnNDX
, ng
, isize
, index
, grpname
);
492 /* The first time we read data is a little special */
493 read_first_frame (oenv
, &status
, fnTRX
, &fr
, flags
);
495 sf
->total_n_atoms
= fr
.natoms
;
498 snew (index_atp
, ng
);
500 r_tmp
= std::max(box
[XX
][XX
], box
[YY
][YY
]);
501 r_tmp
= std::max(box
[ZZ
][ZZ
], r_tmp
);
503 sf
->ref_k
= (2.0 * M_PI
) / (r_tmp
);
504 /* ref_k will be the reference momentum unit */
505 sf
->n_angles
= gmx::roundToInt(end_q
/ sf
->ref_k
);
508 for (i
= 0; i
< ng
; i
++)
510 snew (sf
->F
[i
], sf
->n_angles
);
512 for (i
= 0; i
< ng
; i
++)
514 snew (red
[i
], isize
[i
]);
515 rearrange_atoms (red
[i
], &fr
, index
[i
], isize
[i
], &top
, TRUE
, gmx_sf
);
516 index_atp
[i
] = create_indexed_atom_type (red
[i
], isize
[i
]);
519 sf_table
= compute_scattering_factor_table (gmx_sf
, static_cast<structure_factor_t
*>(sf
));
522 /* This is the main loop over frames */
527 for (i
= 0; i
< ng
; i
++)
529 rearrange_atoms (red
[i
], &fr
, index
[i
], isize
[i
], &top
, FALSE
, gmx_sf
);
531 compute_structure_factor (static_cast<structure_factor_t
*>(sf
), box
, red
[i
], isize
[i
],
532 start_q
, end_q
, i
, sf_table
);
536 while (read_next_frame (oenv
, status
, &fr
));
538 save_data (static_cast<structure_factor_t
*>(sf
), fnXVG
, ng
, start_q
, end_q
, oenv
);
544 gmx_structurefactors_done(gmx_sf
);
550 extern void save_data (structure_factor_t
*sft
, const char *file
, int ngrps
,
551 real start_q
, real end_q
, const gmx_output_env_t
*oenv
)
556 double *tmp
, polarization_factor
, A
;
558 structure_factor
*sf
= static_cast<structure_factor
*>(sft
);
560 fp
= xvgropen (file
, "Scattering Intensity", "q (1/nm)",
561 "Intensity (a.u.)", oenv
);
565 for (g
= 0; g
< ngrps
; g
++)
567 for (i
= 0; i
< sf
->n_angles
; i
++)
571 * theta is half the angle between incoming and scattered vectors.
573 * polar. fact. = 0.5*(1+cos^2(2*theta)) = 1 - 0.5 * sin^2(2*theta)
575 * sin(theta) = q/(2k) := A -> sin^2(theta) = 4*A^2 (1-A^2) ->
576 * -> 0.5*(1+cos^2(2*theta)) = 1 - 2 A^2 (1-A^2)
578 A
= static_cast<double>(i
* sf
->ref_k
) / (2.0 * sf
->momentum
);
579 polarization_factor
= 1 - 2.0 * gmx::square(A
) * (1 - gmx::square(A
));
580 sf
->F
[g
][i
] *= polarization_factor
;
583 for (i
= 0; i
< sf
->n_angles
; i
++)
585 if (i
* sf
->ref_k
>= start_q
&& i
* sf
->ref_k
<= end_q
)
587 fprintf (fp
, "%10.5f ", i
* sf
->ref_k
);
588 for (g
= 0; g
< ngrps
; g
++)
590 fprintf (fp
, " %10.5f ", (sf
->F
[g
][i
]) /( sf
->total_n_atoms
*
601 extern double CMSF (gmx_structurefactors_t
*gsf
, int type
, int nh
, double lambda
, double sin_theta
)
603 * return Cromer-Mann fit for the atomic scattering factor:
604 * sin_theta is the sine of half the angle between incoming and scattered
605 * vectors. See g_sq.h for a short description of CM fit.
609 double tmp
= 0.0, k2
;
618 * f0[k] = c + [SUM a_i*EXP(-b_i*(k^2)) ]
628 tmp
= (CMSF (gsf
, return_atom_type ("C", gsf
), 0, lambda
, sin_theta
) +
629 nh
*CMSF (gsf
, return_atom_type ("H", gsf
), 0, lambda
, sin_theta
));
634 k2
= (gmx::square(sin_theta
) / gmx::square(10.0 * lambda
));
635 gmx_structurefactors_get_sf(gsf
, type
, a
, b
, &c
);
637 for (i
= 0; (i
< 4); i
++)
639 tmp
+= a
[i
] * exp (-b
[i
] * k2
);
647 extern real
**gmx_structurefactors_table(gmx_structurefactors_t
*gsf
, real momentum
, real ref_k
, real lambda
, int n_angles
)
655 gmx_structurefactors
*gsft
= static_cast<gmx_structurefactors
*>(gsf
);
657 NCMT
= gsft
->nratoms
;
660 snew (sf_table
, nsftable
);
661 for (i
= 0; (i
< nsftable
); i
++)
663 snew (sf_table
[i
], n_angles
);
664 for (j
= 0; j
< n_angles
; j
++)
666 q
= static_cast<double>(j
* ref_k
);
667 /* theta is half the angle between incoming
668 and scattered wavevectors. */
669 sin_theta
= q
/ (2.0 * momentum
);
672 sf_table
[i
][j
] = CMSF (gsf
, i
, 0, lambda
, sin_theta
);
676 sf_table
[i
][j
] = CMSF (gsf
, i
, i
-NCMT
+1, lambda
, sin_theta
);
683 extern void gmx_structurefactors_done(gmx_structurefactors_t
*gsf
)
687 gmx_structurefactors
*sf
;
688 sf
= static_cast<gmx_structurefactors
*>(gsf
);
690 for (i
= 0; i
< sf
->nratoms
; i
++)
694 sfree(sf
->atomnm
[i
]);
707 extern real
**compute_scattering_factor_table (gmx_structurefactors_t
*gsf
, structure_factor_t
*sft
)
710 * this function build up a table of scattering factors for every atom
711 * type and for every scattering angle.
714 double hc
= 1239.842;
717 structure_factor
*sf
= static_cast<structure_factor
*>(sft
);
720 /* \hbar \omega \lambda = hc = 1239.842 eV * nm */
721 sf
->momentum
= (static_cast<double>(2. * 1000.0 * M_PI
* sf
->energy
) / hc
);
722 sf
->lambda
= hc
/ (1000.0 * sf
->energy
);
723 fprintf (stderr
, "\nwavelenght = %f nm\n", sf
->lambda
);
725 sf_table
= gmx_structurefactors_table(gsf
, sf
->momentum
, sf
->ref_k
, sf
->lambda
, sf
->n_angles
);