5
$\begingroup$

I am trying to rewrite the output of "VertexCoordinates" such that instead of a hybrid list of atoms and coordinates that result from using the following input program, I want all coordinates of the SAME atom (e.g. H atoms) listed first, preceded by the total number of H atoms, and then followed by the total number of C atoms before a list of all coordinates of C atoms and so on. This will be used as input to an ELK file.

Import["ExampleData/caffeine.xyz", {{"VertexTypes", "VertexCoordinates"}}]
ExportString[%, {"XYZ", {"VertexTypes", "VertexCoordinates"}}]

Expected output is as follows (pls note that this is not exactly a molecule due to compression)

atoms
 3 : nspecies
 'H.in' : spfname
 5 : natoms; atposl, bfcmt below
 0.34100000 0.52900000 0.10100000 0.00000000 0.00000000 0.00000000
 0.65900000 0.47100000 0.60100000 0.00000000 0.00000000 0.00000000
 0.15900000 0.02900000 0.60100000 0.00000000 0.00000000 0.00000000
 0.84100000 0.97100000 0.10100000 0.00000000 0.00000000 0.00000000
 0.34700000 0.34800000 0.99500000 0.00000000 0.00000000 0.00000000
  'C.in' : spfname
 6 : natoms; atposl, bfcmt below
 0.48630000 0.11560000 0.04910000 0.00000000 0.00000000 0.00000000
 0.51370000 0.88440000 0.54910000 0.00000000 0.00000000 0.00000000
 0.01370000 0.61560000 0.54910000 0.00000000 0.00000000 0.00000000
 0.98630000 0.38440000 0.04910000 0.00000000 0.00000000 0.00000000
 0.44602000 0.30860000 0.10260000 0.00000000 0.00000000 0.00000000
 0.55398000 0.69140000 0.60260000 0.00000000 0.00000000 0.00000000
 'N.in' : spfname
 4 : natoms; atposl, bfcmt below
 0.37630000 0.42680000 0.04850000 0.00000000 0.00000000 0.00000000
 0.62370000 0.57320000 0.54850000 0.00000000 0.00000000 0.00000000
 0.12370000 0.92680000 0.54850000 0.00000000 0.00000000 0.00000000
 0.87630000 0.07320000 0.04850000 0.00000000 0.00000000 0.00000000
$\endgroup$
  • 2
    $\begingroup$ Just a personal style recommendation: Writing out things like "please" in full somehow makes questions seem more professional (and sometimes dampens codez rqst allergic reflexes). $\endgroup$ – Yves Klett Sep 20 '14 at 8:06
6
$\begingroup$

I am not familiar with the specific output format you need but I think I can show you how to proceed.

dat = Import["ExampleData/caffeine.xyz", {{"VertexTypes", "VertexCoordinates"}}];

dat2 = {#[[1, 1]], #[[All, 2]]} & /@ GatherBy[dat\[Transpose], First];

dat3 = {#, Length@#2, #2} & @@@ dat2;

dat3 has this format:

dat3 // TableForm

$\left( \begin{array}{ccc} \text{H} & 10 & \left( \begin{array}{ccc} -338.041 & -112.724 & 57.3304 \\ 254.97 & 297.35 & 62.2959 \\ -248.077 & -272.695 & 48.8263 \\ -300.89 & -190.253 & -104.98 \\ 291.761 & -184.815 & -78.5787 \\ 237.879 & -112.119 & -237.437 \\ 171.899 & -274.899 & -184.392 \\ -16.8703 & 404.366 & 93.0109 \\ 35.3532 & 329.791 & 251.777 \\ -120.745 & 275.376 & 172.03 \\ \end{array} \right) \\ \text{N} & 4 & \left( \begin{array}{ccc} 96.683 & -107.374 & -81.9823 \\ -137.517 & -102.122 & -5.70552 \\ 56.0263 & 208.391 & 82.5159 \\ 228.613 & 99.6844 & -24.403 \\ \end{array} \right) \\ \text{C} & 8 & \left( \begin{array}{ccc} 5.67293 & 85.2719 & 39.2316 \\ -126.15 & 25.9071 & 52.3414 \\ -30.6834 & -168.363 & -71.6934 \\ 113.942 & 18.7412 & -27.009 \\ -263.281 & -173.04 & -0.60953 \\ 205.274 & -173.609 & -149.313 \\ -15.1845 & 309.7 & 153.483 \\ 189.341 & 211.812 & 41.9319 \\ \end{array} \right) \\ \text{O} & 2 & \left( \begin{array}{ccc} -49.268 & -281.806 & -120.947 \\ -223.013 & 79.8862 & 108.997 \\ \end{array} \right) \\ \end{array} \right)$

If you give a manually created example of the exact output that you need I can try to give code for that as well.


I believe this produces the formatting that you want. It's not particularly clean but it should work.

(* helper function using method from http://mathematica.stackexchange.com/a/55904/ *)
tableToString = 
  ToString @ PaddedForm[#, {6, 6}] & @ TableForm[#, TableSpacing -> {0, 1}] &;

(* method from above *)
group =
  {#, Length@#2, #2} & @@ {#[[1, 1]], #[[All, 2]]} & /@ GatherBy[#\[Transpose], First] &;

format[dat_] :=
  "" <> Riffle[#, "\n"] & @ Join[{"atoms", ToString@Length@dat <> " : nspecies"}, ##] & @@
   Cases[dat, {name_, count_, tab_?MatrixQ} :>
     {"'" <> name <> ".in' : spfname", ToString@count <> " : natoms; atposl, bfcmt below",
       tableToString[tab/100]}]

Test:

Import["ExampleData/caffeine.xyz", {{"VertexTypes", "VertexCoordinates"}}] // group // format
atoms
4 : nspecies
'H.in' : spfname
10 : natoms; atposl, bfcmt below
-3.380410 -1.127240  0.573304
 2.549700  2.973500  0.622959
-2.480770 -2.726950  0.488263
-3.008900 -1.902530 -1.049800
 2.917610 -1.848150 -0.785787
 2.378790 -1.121190 -2.374370
 1.718990 -2.748990 -1.843920
-0.168703  4.043660  0.930109
 0.353532  3.297910  2.517770
-1.207450  2.753760  1.720300
'N.in' : spfname
4 : natoms; atposl, bfcmt below
 0.966830 -1.073740 -0.819823
-1.375170 -1.021220 -0.057055
 0.560263  2.083910  0.825159
 2.286130  0.996844 -0.244030
'C.in' : spfname
8 : natoms; atposl, bfcmt below
 0.056729  0.852719  0.392316
-1.261500  0.259071  0.523414
-0.306834 -1.683630 -0.716934
 1.139420  0.187412 -0.270090
-2.632810 -1.730400 -0.006095
 2.052740 -1.736090 -1.493130
-0.151845  3.097000  1.534830
 1.893410  2.118120  0.419319
'O.in' : spfname
2 : natoms; atposl, bfcmt below
-0.492680 -2.818060 -1.209470
-2.230130  0.798862  1.089970

The output is a String. You can export it with e.g. Export["file.txt", string, "Text"].

$\endgroup$
  • $\begingroup$ There appears to be a magnification in coordinates... $\endgroup$ – thils Sep 20 '14 at 7:45
  • $\begingroup$ @thils Sorry, I don't understand what you mean. $\endgroup$ – Mr.Wizard Sep 20 '14 at 7:50
  • $\begingroup$ Please see new edits $\endgroup$ – thils Sep 20 '14 at 7:54
  • $\begingroup$ @thils The coordinates shown in my answer are as they are given by Import in the first line. How should they be scaled or translated? $\endgroup$ – Mr.Wizard Sep 20 '14 at 8:04
  • $\begingroup$ @Wizard Not a worry, divide by 100 to convert to Angstroms, minor issue. But the main query relates to the expected output explained above. $\endgroup$ – thils Sep 20 '14 at 8:14
1
$\begingroup$

This is my attempt at producing the output style that you desire where i have assumed that all co-ordinates should be padded with three zeroes at the end.

data = Import[
"ExampleData/caffeine.xyz", {{"VertexTypes", "VertexCoordinates"}}];

Gather co-ordinates of same elements

table = Table[
 If[data[[1, #]] == data[[1, i]], Sow[N[data[[2, i]]/100]], 
  Unevaluated[Sequence[]]], {i, 1, Length[data[[1]]]}] & /@ 
 GatherBy[Range@Length[data[[1]]], data[[1]][[#]] &][[All, 1]]

Gather all the distinct elements

elements = 
data[[1, #]] & /@ 
 GatherBy[Range@Length[data[[1]]], data[[1]][[#]] &][[All, 1]];
 total = Length@table[[#]] & /@ Range@Length@table

Format by padding with 3 zeroes and 8 digits after decimal

 padtable = 
 Table[NumberForm[PadRight[table[[i, #]], 6, 0], {8, 8}] & /@ 
 Range[Length[table[[i]]]], {i, 1, Length[table]}]

Finally display the result with required string structure

 result = Table[{ToString["'"] <> ToString[elements[[i]]] <> 
    ToString[".in' : spfname"], 
  ToString[total[[i]]] <> ToString[": natoms; atposl, bfcmt below"], 
  padtable[[i]]}, {i, 1, Length[table]}]

P.S. There seems to be a problem with NumberForm when exporting the final result. Maybe someone can provide some help on this.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.