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$
1
  • 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
    Commented Sep 20, 2014 at 8:06

2 Answers 2

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$
5
  • $\begingroup$ There appears to be a magnification in coordinates... $\endgroup$
    – thils
    Commented Sep 20, 2014 at 7:45
  • $\begingroup$ @thils Sorry, I don't understand what you mean. $\endgroup$
    – Mr.Wizard
    Commented Sep 20, 2014 at 7:50
  • $\begingroup$ Please see new edits $\endgroup$
    – thils
    Commented Sep 20, 2014 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
    Commented Sep 20, 2014 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
    Commented Sep 20, 2014 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$
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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