00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <stdio.h>
00015 #include <stdlib.h>
00016 #include <ctype.h>
00017 #include <string.h>
00018
00019 #include <sys/stat.h>
00020 #include "qcschema_json.c"
00021
00022 #if defined(_AIX)
00023 #include <strings.h>
00024 #endif
00025
00026 #if defined(WIN32) || defined(WIN64)
00027 #define strcasecmp stricmp
00028 #endif
00029
00030 #include "molfile_plugin.h"
00031 #include "unit_conversion.h"
00032 #include "periodic_table.h"
00033 #include "qmplugin.h"
00034
00035
00036 #define ALLOCATE(array, type, size) \
00037 array = (type *)calloc(size, sizeof(type)); \
00038 if (array == NULL) { \
00039 fprintf(stderr, "qcschemaplugin) Memory allocation for %s failed!\n", #array); \
00040 return FALSE; \
00041 }
00042
00043 #define GET_LINE(x,y) if (!fgets(x, sizeof(x), y)) return FALSE
00044
00045
00046 static int get_basis (qmdata_t *);
00047 static int shelltype_int(char *type);
00048 static int fill_basis_arrays(qmdata_t *data);
00049
00050
00051 static int read_molecular_orbitals(qmdata_t *data);
00052 static int read_wave_coeffs(FILE *file, qm_wavefunction_t *wave);
00053 static int count_orbitals(qmdata_t *data);
00054
00055 typedef struct {
00056 json_value* geom_array;
00057 json_value* symbol_array;
00058 json_value* model;
00059 json_value* keywords;
00060 json_value* extras;
00061 json_value* provenance;
00062 json_value* properties;
00063 json_value* return_result;
00064 int coordsonly;
00065 } jsondata_t;
00066
00067
00068
00069
00070
00071
00072
00073 static void *open_qcschema_read(const char *filename,
00074 const char *filetype,
00075 int *natoms) {
00076 FILE *fd;
00077 qmdata_t *data = NULL;
00078 char buffer[1024];
00079 char keystring[20];
00080 json_char* json;
00081 json_value* value;
00082 json_value* aux_value;
00083 char* file_contents;
00084 struct stat filestatus;
00085 int file_size;
00086
00087 if ( stat(filename, &filestatus) != 0) {
00088 fprintf(stderr, "File %s not found\n", filename);
00089 return NULL;
00090 }
00091 file_size = filestatus.st_size;
00092 file_contents = (char*)malloc(filestatus.st_size);
00093 if ( file_contents == NULL) {
00094 fprintf(stderr, "Memory error: unable to allocate %d bytes\n", file_size);
00095 return NULL;
00096 }
00097
00098 fd = fopen(filename, "rb");
00099 if (!fd) return NULL;
00100
00101
00102 data = init_qmdata();
00103 if (!data) return NULL;
00104
00105 data->file = fd;
00106
00107
00108 jsondata_t * jsondata = (jsondata_t *)calloc(1, sizeof(jsondata_t));
00109 if (!jsondata) return NULL;
00110
00111 if ( fread(file_contents, file_size, 1, fd) != 1 ) {
00112 fprintf(stderr, "Unable to read content of %s\n", filename);
00113 fclose(fd);
00114 free(file_contents);
00115 return NULL;
00116 }
00117
00118 fclose(fd);
00119 json = (json_char*)file_contents;
00120
00121 value = json_parse(json,file_size);
00122
00123 int i, j;
00124 if (value == NULL) {
00125 return NULL;
00126 }
00127
00128 _Bool check_schema_done = FALSE;
00129 _Bool molecule_done = FALSE;
00130 _Bool driver_done = FALSE;
00131 _Bool model_done = FALSE;
00132 _Bool extras_done = FALSE;
00133 _Bool properties_done = FALSE;
00134 _Bool return_result_done = FALSE;
00135
00136
00137 for (i = 0; i < value->u.object.length; i++) {
00138
00139
00140
00141 if (!check_schema_done && !strcmp(value->u.object.values[i].name, "schema_name")) {
00142
00143 check_schema_done = TRUE;
00144 }
00145
00146 else if (!molecule_done && !strcmp(value->u.object.values[i].name, "molecule")) {
00147
00148 aux_value = value->u.object.values[i].value;
00149
00150 for (j = 0; j < aux_value->u.object.length; j++) {
00151 if (!strcmp(aux_value->u.object.values[j].name, "geometry")) {
00152
00153 data->numatoms = aux_value->u.object.values[j].value->u.array.length / 3;
00154 jsondata->geom_array = aux_value->u.object.values[j].value;
00155 }
00156 else if (!strcmp(aux_value->u.object.values[j].name, "symbols")) {
00157
00158 data->numatoms = aux_value->u.object.values[j].value->u.array.length;
00159 jsondata->symbol_array = aux_value->u.object.values[j].value;
00160 }
00161 else if (!strcmp(aux_value->u.object.values[j].name, "molecular_charge")) {
00162 data->totalcharge = aux_value->u.object.values[j].value;
00163 }
00164 else if (!strcmp(aux_value->u.object.values[j].name, "molecular_multiplicity")) {
00165 data->multiplicity = aux_value->u.object.values[j].value;
00166 }
00167 }
00168 molecule_done = TRUE;
00169 }
00170
00171 else if (!driver_done && !strcmp(value->u.object.values[i].name, "driver")) {
00172 aux_value = value->u.object.values[i].value;
00173
00174 if (!strcmp(aux_value->u.string.ptr, "energy")) {
00175 data->runtype = MOLFILE_RUNTYPE_ENERGY;
00176 }
00177 else if (!strcmp(aux_value->u.string.ptr, "gradient")) {
00178 data->runtype = MOLFILE_RUNTYPE_GRADIENT;
00179 }
00180 else if (!strcmp(aux_value->u.string.ptr, "hessian")) {
00181 data->runtype = MOLFILE_RUNTYPE_HESSIAN;
00182 }
00183 driver_done = TRUE;
00184 }
00185
00186 else if (!model_done && !strcmp(value->u.object.values[i].name, "model")) {
00187 jsondata->model = value->u.object.values[i].value;
00188 model_done = TRUE;
00189 }
00190
00191 else if (!extras_done && !strcmp(value->u.object.values[i].name, "extras")) {
00192 jsondata->extras = value->u.object.values[i].value;
00193 extras_done = TRUE;
00194 }
00195
00196 else if (!properties_done && !strcmp(value->u.object.values[i].name, "properties")) {
00197 jsondata->properties = value->u.object.values[i].value;
00198 properties_done = TRUE;
00199 }
00200
00201 else if (!return_result_done && !strcmp(value->u.object.values[i].name, "return_result")) {
00202 jsondata->return_result = value->u.object.values[i].value;
00203 return_result_done = TRUE;
00204 }
00205 }
00206
00207 if (!check_schema_done) {
00208 printf("qcschemaplugin) The file is not in JSON/QCSCHEMA format!\n");
00209 return NULL;
00210 }
00211
00212
00213
00214 data->format_specific_data = jsondata;
00215 *natoms = data->numatoms;
00216 data->num_frames = 1;
00217 return data;
00218 }
00219
00220
00221
00222
00223
00224
00225
00226 static int read_qcschema_structure(void *mydata, int *optflags,
00227 molfile_atom_t *atoms)
00228 {
00229 int i;
00230 char buffer[1024];
00231 char atname[1024];
00232 int num, atomicnum;
00233 molfile_atom_t *atom;
00234 qmdata_t *data = (qmdata_t *)mydata;
00235 jsondata_t* jsondata = (jsondata_t*)data->format_specific_data;
00236
00237 ALLOCATE(data->atoms, qm_atom_t, data->numatoms);
00238
00239
00240
00241 *optflags = MOLFILE_ATOMICNUMBER;
00242
00243 float unitfac = 1.f;
00244
00245 for (i=0; i<data->numatoms; i++) {
00246 atom = atoms+i;
00247
00248 strncpy(atname,jsondata->symbol_array->u.array.values[i]->u.string.ptr,sizeof(atname));
00249
00250 strncpy(atom->name, atname, sizeof(atom->name));
00251 strncpy(atom->type, atom->name, sizeof(atom->type));
00252 atom->atomicnumber = get_pte_idx_from_string(atname);
00253 strncpy(atom->resname,"MOL", sizeof(atom->resname));
00254 atom->resid = 1;
00255 atom->chain[0] = '\0';
00256 atom->segid[0] = '\0';
00257 data->atoms[i].atomicnum = atom->atomicnumber;
00258 data->num_frames_read = 0;
00259
00260
00261 strncpy(data->atoms[i].type, atname, sizeof(data->atoms[i].type));
00262 data->atoms[i].atomicnum = atomicnum;
00263 data->atoms[i].x = jsondata->geom_array->u.array.values[i*3]->u.dbl*unitfac;
00264 data->atoms[i].y = jsondata->geom_array->u.array.values[i*3+1]->u.dbl*unitfac;
00265 data->atoms[i].z = jsondata->geom_array->u.array.values[i*3+2]->u.dbl*unitfac;
00266
00267 }
00268
00269 return MOLFILE_SUCCESS;
00270
00271 }
00272
00273
00274
00275
00276
00277
00278
00279
00280 static int read_timestep_metadata(void *mydata,
00281 molfile_timestep_metadata_t *meta) {
00282
00283 meta->count = -1;
00284 meta->has_velocities = 0;
00285
00286 return MOLFILE_SUCCESS;
00287 }
00288
00289
00290
00291
00292
00293
00294
00295
00296 static int read_qm_timestep_metadata(void *mydata,
00297 molfile_qm_timestep_metadata_t *meta) {
00298 qmdata_t *data = (qmdata_t *)mydata;
00299 jsondata_t* jsondata = (jsondata_t *)data->format_specific_data;
00300
00301 if (data->num_frames_sent >= data->num_frames) {
00302
00303 return MOLFILE_ERROR;
00304 }
00305
00306
00307
00308 if (data->num_frames_sent == data->num_frames-1) {
00309 int i;
00310 qm_timestep_t *cur_ts;
00311
00312 if (!count_orbitals(data)) return MOLFILE_ERROR;
00313
00314
00315 cur_ts = data->qm_timestep;
00316
00317 for (i=0; (i<MOLFILE_MAXWAVEPERTS && i<cur_ts->numwave); i++) {
00318 meta->num_orbitals_per_wavef[i] = cur_ts->wave[i].num_orbitals;
00319 meta->has_occup_per_wavef[i] = cur_ts->wave[i].has_occup;
00320 meta->has_orben_per_wavef[i] = cur_ts->wave[i].has_orben;
00321 }
00322 meta->wavef_size = data->wavef_size;
00323 meta->num_wavef = cur_ts->numwave;
00324 meta->num_scfiter = cur_ts->num_scfiter;
00325 meta->has_gradient = FALSE;
00326 meta->num_charge_sets = 0;
00327 }
00328 return MOLFILE_SUCCESS;
00329 }
00330
00331
00332
00333
00334
00335
00336
00337
00338 static int read_timestep(void *mydata, int natoms,
00339 molfile_timestep_t *ts, molfile_qm_metadata_t *qm_metadata,
00340 molfile_qm_timestep_t *qm_ts) {
00341 int i;
00342 qmdata_t *data = (qmdata_t *)mydata;
00343 qm_timestep_t *cur_ts;
00344
00345 if (data->num_frames_sent >= data->num_frames) {
00346
00347 return MOLFILE_ERROR;
00348 }
00349
00350 if (data->num_frames_sent == data->num_frames_read) {
00351
00352
00353
00354
00355 printf("qcschemaplugin) Read frame %d\n", data->num_frames_read);
00356 data->num_frames_read++;
00357 }
00358
00359
00360
00361 for (i=0; i<natoms; i++) {
00362 ts->coords[3*i ] = data->atoms[i].x;
00363 ts->coords[3*i+1] = data->atoms[i].y;
00364 ts->coords[3*i+2] = data->atoms[i].z;
00365 }
00366
00367
00368 data->num_frames_sent++;
00369
00370
00371 if (data->num_frames_sent == data->num_frames) {
00372
00373
00374 cur_ts = data->qm_timestep;
00375
00376 read_molecular_orbitals(data);
00377
00378
00379 if (cur_ts != NULL && cur_ts->wave != NULL) {
00380 for (i=0; i<cur_ts->numwave; i++) {
00381 qm_wavefunction_t *wave = &cur_ts->wave[i];
00382 qm_ts->wave[i].type = wave->type;
00383 qm_ts->wave[i].spin = wave->spin;
00384 qm_ts->wave[i].excitation = wave->exci;
00385 qm_ts->wave[i].multiplicity = wave->mult;
00386 qm_ts->wave[i].energy = wave->energy;
00387 strncpy(qm_ts->wave[i].info, wave->info, MOLFILE_BUFSIZ);
00388
00389 if (wave->wave_coeffs) {
00390 memcpy(qm_ts->wave[i].wave_coeffs, wave->wave_coeffs,
00391 wave->num_orbitals*data->wavef_size*sizeof(float));
00392 }
00393 if (wave->orb_energies) {
00394 memcpy(qm_ts->wave[i].orbital_energies, wave->orb_energies,
00395 wave->num_orbitals*sizeof(float));
00396 }
00397 if (wave->has_occup) {
00398 memcpy(qm_ts->wave[i].occupancies, wave->orb_occupancies,
00399 wave->num_orbitals*sizeof(float));
00400 }
00401 }
00402 }
00403
00404 }
00405
00406 return MOLFILE_SUCCESS;
00407 }
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422 static int read_qcschema_metadata(void *mydata,
00423 molfile_qm_metadata_t *metadata) {
00424
00425 qmdata_t *data;
00426 jsondata_t* jsondata = (jsondata_t *)data->format_specific_data;
00427 data = (qmdata_t *)mydata;
00428
00429 metadata->ncart = 0;
00430 metadata->nimag = 0;
00431 metadata->nintcoords = 0;
00432
00433 metadata->have_sysinfo = 0;
00434 metadata->have_carthessian = 0;
00435 metadata->have_inthessian = 0;
00436 metadata->have_normalmodes = 0;
00437
00438 metadata->num_basis_funcs = 0;
00439 metadata->num_basis_atoms = 0;
00440 metadata->num_shells = 0;
00441 metadata->wavef_size = 0;
00442
00443 jsondata->coordsonly = 1;
00444
00445 if (!jsondata->coordsonly) {
00446
00447 if (!get_basis(data)) return MOLFILE_ERROR;
00448
00449
00450 metadata->num_basis_funcs = data->num_basis_funcs;
00451 metadata->num_basis_atoms = data->num_basis_atoms;
00452 metadata->num_shells = data->num_shells;
00453 metadata->wavef_size = data->wavef_size;
00454 }
00455
00456 return MOLFILE_SUCCESS;
00457 }
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467 static int read_qcschema_rundata(void *mydata,
00468 molfile_qm_t *qm_data) {
00469 qmdata_t *data = (qmdata_t *)mydata;
00470 int i;
00471 molfile_qm_hessian_t *hessian_data;
00472 molfile_qm_basis_t *basis_data;
00473 molfile_qm_sysinfo_t *sys_data;
00474
00475 if (!qm_data) return MOLFILE_ERROR;
00476
00477
00478 hessian_data = &qm_data->hess;
00479 basis_data = &qm_data->basis;
00480 sys_data = &qm_data->run;
00481
00482 sys_data->num_electrons = data->num_electrons;
00483 sys_data->totalcharge = data->totalcharge;
00484 sys_data->runtype = data->runtype;
00485
00486
00487
00488 if (data->num_basis_funcs) {
00489 for (i=0; i<data->num_basis_atoms; i++) {
00490 basis_data->num_shells_per_atom[i] = data->num_shells_per_atom[i];
00491 basis_data->atomic_number[i] = data->atomicnum_per_basisatom[i];
00492 }
00493
00494 for (i=0; i<data->num_shells; i++) {
00495 basis_data->num_prim_per_shell[i] = data->num_prim_per_shell[i];
00496 basis_data->shell_types[i] = data->shell_types[i];
00497 }
00498
00499 for (i=0; i<2*data->num_basis_funcs; i++) {
00500 basis_data->basis[i] = data->basis[i];
00501 }
00502
00503
00504
00505 if (data->angular_momentum) {
00506 for (i=0; i<3*data->wavef_size; i++) {
00507 basis_data->angular_momentum[i] = data->angular_momentum[i];
00508 }
00509 }
00510 }
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522 return MOLFILE_SUCCESS;
00523 }
00524
00525
00526
00527
00528
00529
00530
00531 static void close_qcschema_read(void *mydata) {
00532 int i, j;
00533 qmdata_t *data = (qmdata_t *)mydata;
00534
00535
00536 free(data->atoms);
00537 free(data->basis);
00538 free(data->shell_types);
00539 free(data->atomicnum_per_basisatom);
00540 free(data->num_shells_per_atom);
00541 free(data->num_prim_per_shell);
00542 free(data->angular_momentum);
00543
00544 if (data->basis_set) {
00545 for(i=0; i<data->num_basis_atoms; i++) {
00546 for (j=0; j<data->basis_set[i].numshells; j++) {
00547 free(data->basis_set[i].shell[j].prim);
00548 }
00549 free(data->basis_set[i].shell);
00550 }
00551 free(data->basis_set);
00552 }
00553
00554 free(data->format_specific_data);
00555 free(data->filepos_array);
00556
00557 if (data->qm_timestep != NULL) {
00558 for (j=0; j<data->qm_timestep[0].numwave; j++) {
00559 free(data->qm_timestep[0].wave[j].wave_coeffs);
00560 free(data->qm_timestep[0].wave[j].orb_energies);
00561 free(data->qm_timestep[0].wave[j].orb_occupancies);
00562 }
00563 free(data->qm_timestep[0].wave);
00564 free(data->qm_timestep);
00565 } else {
00566 printf("close_qcschema_read(): NULL qm_timestep!\n");
00567 }
00568
00569 free(data);
00570 }
00571
00572
00573
00574
00575
00576
00577
00578
00579 static int get_basis(qmdata_t *data) {
00580
00581 return TRUE;
00582 }
00583
00584
00585
00586
00587
00588
00589
00590
00591 static int fill_basis_arrays(qmdata_t *data) {
00592 int i, j, k;
00593 int shellcount = 0;
00594 int primcount = 0;
00595
00596 float *basis;
00597 int *num_shells_per_atom;
00598 int *num_prim_per_shell;
00599 int *shell_types;
00600 int *atomicnum_per_basisatom;
00601
00602
00603
00604 for(i=0; i<data->num_basis_atoms; i++) {
00605 for (j=0; j<data->basis_set[i].numshells; j++) {
00606 primcount += data->basis_set[i].shell[j].numprims;
00607 }
00608 }
00609 data->num_basis_funcs = primcount;
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619 ALLOCATE(basis, float, 2*primcount);
00620 ALLOCATE(shell_types, int, data->num_shells);
00621 ALLOCATE(num_shells_per_atom, int, data->num_basis_atoms);
00622 ALLOCATE(num_prim_per_shell, int, data->num_shells);
00623 ALLOCATE(atomicnum_per_basisatom, int, data->num_basis_atoms);
00624
00625
00626
00627
00628 data->basis = basis;
00629 data->shell_types = shell_types;
00630 data->num_shells_per_atom = num_shells_per_atom;
00631 data->num_prim_per_shell = num_prim_per_shell;
00632 data->atomicnum_per_basisatom = atomicnum_per_basisatom;
00633
00634 primcount = 0;
00635 for (i=0; i<data->num_basis_atoms; i++) {
00636
00637 data->basis_set[i].atomicnum = data->atoms[i].atomicnum;
00638 atomicnum_per_basisatom[i] = data->atoms[i].atomicnum;
00639
00640 num_shells_per_atom[i] = data->basis_set[i].numshells;
00641
00642 for (j=0; j<data->basis_set[i].numshells; j++) {
00643 shell_types[shellcount] = data->basis_set[i].shell[j].type;
00644 num_prim_per_shell[shellcount] = data->basis_set[i].shell[j].numprims;
00645
00646 for (k=0; k<data->basis_set[i].shell[j].numprims; k++) {
00647 basis[2*primcount ] = data->basis_set[i].shell[j].prim[k].exponent;
00648 basis[2*primcount+1] = data->basis_set[i].shell[j].prim[k].contraction_coeff;
00649 primcount++;
00650 }
00651 shellcount++;
00652 }
00653 }
00654
00655 return TRUE;
00656 }
00657
00658
00659
00660
00661
00662
00663
00664
00665 static int shelltype_int(char *type) {
00666 int shelltype;
00667 if (!strcasecmp(type, "sp")) shelltype = SP_SHELL;
00668 else if (!strcasecmp(type, "s")) shelltype = S_SHELL;
00669 else if (!strcasecmp(type, "p")) shelltype = P_SHELL;
00670 else if (!strcasecmp(type, "d")) shelltype = D_SHELL;
00671 else if (!strcasecmp(type, "f")) shelltype = F_SHELL;
00672 else if (!strcasecmp(type, "g")) shelltype = G_SHELL;
00673 else shelltype = UNK_SHELL;
00674
00675 return shelltype;
00676 }
00677
00678 static int count_orbitals(qmdata_t *data) {
00679 int nr;
00680 int num_wave_coeff=0;
00681 float orbenergy, occu;
00682 char spin[1024];
00683 qm_wavefunction_t *wave;
00684 jsondata_t *jsondata = (jsondata_t *)data->format_specific_data;
00685 int dummy1;
00686 float dummy2;
00687
00688
00689 data->qm_timestep = (qm_timestep_t *)calloc(1, sizeof(qm_timestep_t));
00690
00691 return TRUE;
00692 }
00693
00694 static int read_molecular_orbitals(qmdata_t *data) {
00695 jsondata_t *jsondata = (jsondata_t *)data->format_specific_data;
00696 qm_wavefunction_t *wave;
00697 if (!data->qm_timestep || jsondata->coordsonly) return FALSE;
00698 return TRUE;
00699 }
00700
00701 static int read_wave_coeffs(FILE *file, qm_wavefunction_t *wave) {
00702 return TRUE;
00703 }
00704
00705
00706
00707
00708
00709
00710 static molfile_plugin_t plugin;
00711
00712 VMDPLUGIN_API int VMDPLUGIN_init() {
00713 memset(&plugin, 0, sizeof(molfile_plugin_t));
00714 plugin.abiversion = vmdplugin_ABIVERSION;
00715 plugin.type = MOLFILE_PLUGIN_TYPE;
00716 plugin.name = "qcschema";
00717 plugin.prettyname = "QCSchema";
00718 plugin.author = "Mariano Spivak";
00719 plugin.majorv = 0;
00720 plugin.minorv = 1;
00721 plugin.is_reentrant = VMDPLUGIN_THREADSAFE;
00722 plugin.filename_extension = "json,qcs";
00723 plugin.open_file_read = open_qcschema_read;
00724 plugin.read_structure = read_qcschema_structure;
00725
00726 plugin.read_timestep_metadata = read_timestep_metadata;
00727 plugin.read_timestep = read_timestep;
00728 plugin.read_qm_timestep_metadata = read_qm_timestep_metadata;
00729
00730 plugin.read_qm_metadata = read_qcschema_metadata;
00731 plugin.read_qm_rundata = read_qcschema_rundata;
00732
00733 plugin.close_file_read = close_qcschema_read;
00734 return VMDPLUGIN_SUCCESS;
00735 }
00736
00737 VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
00738 (*cb)(v, (vmdplugin_t *)&plugin);
00739 return VMDPLUGIN_SUCCESS;
00740 }
00741
00742 VMDPLUGIN_API int VMDPLUGIN_fini() {
00743 return VMDPLUGIN_SUCCESS;
00744 }
00745