kat_io.c 98.7 KB
Newer Older
1

2
/*!
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * \file kat_io.c
 * \brief Input-output routines.
 * 
 * @section Copyright notice
 *
 *  This file is part of the interferometer simulation Finesse
 *  http://www.gwoptics.org/finesse
 *
 *  Copyright (C) 1999 onwards Andreas Freise
 *  with parts of the code written by Daniel Brown, Paul Cochrane
 *  and Gerhard Heinzel.
 *
 *  This program is free software; you can redistribute it and/or modify it under
 *  the terms of the GNU General Public License version 3 as published
 *  by the Free Software Foundation.
 *
 *  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Daniel Brown's avatar
Daniel Brown committed
21
 *  See the GNU General Public License for more details.
22
 *
Daniel Brown's avatar
Daniel Brown committed
23
 *  You should have received a copy of the GNU General Public License along with
24 25
 *  this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
 *  Suite 330, Boston, MA 02111-1307 USA
26
 */
27

28

29
#include "kat.h"
30
#include "kat_config.h"
31
#include "kat_io.h"
adf's avatar
 
adf committed
32
#include "kat_inline.c"
33
#include "kat_aux.h"
34 35
#include "kat_init.h"
#include "kat_aa.h"
36 37
#include "kat_optics.h"
#include "kat_knm_mirror.h"
38
#include "kat_knm_bs.h"
39
#include <stdarg.h>
40
#include "md5.h"
41
#include "base64.h"
42 43
#include "f2c.h"
#include "kat_read.h"
adf's avatar
 
adf committed
44 45 46
#include <sys/types.h> 
#include <sys/stat.h>
#include <unistd.h>
47
#include "kat_paralution.h"
adf's avatar
 
adf committed
48

49
//extern init_variables_t in;
50
extern interferometer_t inter;
adf's avatar
 
adf committed
51
extern global_var_t vglobal;
52
extern char mydate[];
adf's avatar
 
adf committed
53
extern memory_t mem;
54
extern options_t options;
55
extern FILE *fp_log;
56

57 58 59 60
//! Print the progress of the simulation to stderr
size_t prev_progress_print_size = 0;
extern FILE* pykat_file;

61 62 63
char progress_action[LINE_LEN] = {0};
char progress_message[LINE_LEN] = {0};

64
typedef struct n1n2m1m2 {
Daniel Brown's avatar
Daniel Brown committed
65
    int n1, n2, m1, m2;
66 67 68 69
} n1n2m1m2_t;

n1n2m1m2_t *nms;

adf's avatar
 
adf committed
70
//! Checks if a file exists, returns 1 if so and 0 otherwise
71

adf's avatar
 
adf committed
72 73 74
/*!
 * \param filename, string giving the filename
 */
75
int check_if_file_exists(char *filename) {
76
    struct stat file_stat;
77

78 79 80 81
    if (stat(filename, &file_stat) == 0)
        return (1);
    else
        return (0);
adf's avatar
 
adf committed
82 83 84
}

//! Renames a file to filename.bak if the file exists
85

adf's avatar
 
adf committed
86 87 88
/*!
 * \param filename, string giving the filename
 */
89
void make_backup_of_file(char *filename) {
adf's avatar
 
adf committed
90

91
    char newname[LINE_LEN];
adf's avatar
 
adf committed
92

93 94 95 96 97
    if (check_if_file_exists(filename)) {
        strcpy(newname, filename);
        strcat(newname, ".bak");
        rename(filename, newname);
    }
adf's avatar
 
adf committed
98 99 100
}

//! opens file for writing (making a backup first) and returns handle
101

adf's avatar
 
adf committed
102 103 104
/*!
 * \param filename, string giving the filename
 */
105
void open_file_to_write_ascii(char *filename, FILE **handle) {
106 107 108 109 110
    make_backup_of_file(filename);
    *handle = fopen(filename, "w");
    if (*handle == NULL) {
        gerror("Could not open file '%s'\n", filename);
    }
adf's avatar
 
adf committed
111 112
}

113
void open_file_to_read_ascii(char *filename, FILE **handle) {
114 115 116 117
    *handle = fopen(filename, "r");
    if (*handle == NULL) {
        gerror("Could not open file '%s'\n", filename);
    }
118 119
}

120
void open_file_to_write_binary(char *filename, FILE **handle) {
121
    make_backup_of_file(filename);
122 123 124 125 126 127 128 129 130 131 132 133 134
    *handle = fopen(filename, "wb");
    if (*handle == NULL) {
        gerror("Could not open file '%s'\n", filename);
    }
}

void open_file_to_read_binary(char *filename, FILE **handle) {
    *handle = fopen(filename, "rb");
    if (*handle == NULL) {
        gerror("Could not open file '%s'\n", filename);
    }
}

135 136
void _read_merged_map_ascii_data(char* name, surface_merged_map_t *map, MAP_COMPONENTS_t num) {
    assert(map != NULL);
137

138
    double **data = NULL; // remove compiler warning
139
    FILE *file = NULL;
140 141
    char buf[MAX_MAP_LINE];
    char filenamemap[LINE_LEN];
142
    int row_count = 0, col_count = 0;
143 144
    double val;

145
    switch (num) {
146
        case R_ABS:
147 148 149
            data = map->r_abs;
            sprintf(buf, "%s_r_abs.map", map->filename);
            break;
150
        case R_PHS:
151 152 153
            data = map->r_phs;
            sprintf(buf, "%s_r_phs.map", map->filename);
            break;
154
        case T_ABS:
155 156 157
            data = map->t_abs;
            sprintf(buf, "%s_t_abs.map", map->filename);
            break;
158
        case T_PHS:
159 160 161 162 163
            data = map->t_phs;
            sprintf(buf, "%s_t_phs.map", map->filename);
            break;
        default:
            bug_error("%i was passed when the value should only be between 0-3\n", num);
164
    }
165

166 167 168
    assert(data!=NULL);
    
    if (inter.debug & 128 && !options.quiet)
169
        message("* Reading map file %s...\n", buf);
170

171
    strcpy(filenamemap, buf);
172 173

    if (!check_if_file_exists(filenamemap))
Daniel Brown's avatar
Daniel Brown committed
174
        gerror("The map file %s is missing. Please delete all other .map and .knm files\n"
175
            "    for mirror %s and regenerate them or replace the missing file\n", filenamemap, name);
176

177
    open_file_to_read_ascii(filenamemap, &file);
178 179

    while (fgets(buf, MAX_MAP_LINE - 1, file) != NULL) {
180 181 182 183
        // ensure there is an end of line value, this should make sure that
        // if there happens to be more numbers than can fit in the buffer this
        // should allow the scanf to pick up the end and then the difference
        // in column count should be found
184 185 186
        buf[MAX_MAP_LINE - 1] = '\n';

        if (row_count > map->rows)
187
            gerror("There are more rows than expected in the map file %s.\n"
188
                "    Please fix or delete the files and regenerate the map data.\n", filenamemap);
189 190 191 192 193 194 195 196

        col_count = 0;

        while (true) {
            // the -1 is here because below we check when only 1 matched was 
            // found using sscanf and then we break, so we would only get here
            // if there were too many columns
            if (col_count > map->cols - 1)
197
                gerror("There are more columns than expected in the map file %s in row %i,\n"
198
                    "    Please fix or delete the files and regenerate the map data.\n", filenamemap, row_count + 1);
199 200 201 202 203 204 205 206 207 208 209 210 211

            int n = sscanf(buf, "%lg %[^\n]s", &val, buf);

            if (n == 2) {
                data[col_count][row_count] = val;
                col_count++;
            } else if (n == 1) {
                data[col_count][row_count] = val;
                col_count++;
                break;
            } else if ((buf[0] == '\n') && (row_count == map->rows))
                break;
            else
212
                gerror("Problem occured when reading map file %s, please ensure it has not been tampered with.\n"
213
                    "    If not delete files and regenerate the map data.\n", filenamemap);
214 215 216 217 218 219
        }

        if ((buf[0] == '\n') && (row_count == map->rows))
            break;

        if (col_count != map->cols)
220
            gerror("There was not the expected amount of columns in the map file %s in row %i.\n"
221
                "    Please fix or delete the files and regenerate the map data\n", filenamemap, row_count);
222 223

        row_count++;
224 225
    }

226
    if (row_count != map->rows)
227
        gerror("There was not the expected amount of rows in the map file %s.\n"
228
            "    Please fix or delete the files and regenerate the map data\n", filenamemap);
229 230 231 232

    fclose(file);
}

233
void _read_merged_map_binary_data(char *name, surface_merged_map_t *map) {
234 235 236 237 238 239 240 241 242 243 244 245

    FILE *file;
    unsigned char* filebuf;
    unsigned long filesize;
    char buf[LINE_LEN];
    char filename[FILENAME_MAX];
    MD5_CTX ctx;

    sprintf(buf, "%s.map.bin", map->filename);
    strcpy(filename, buf);

    if (!check_if_file_exists(filename))
Daniel Brown's avatar
Daniel Brown committed
246
        gerror("The map file %s is missing. Please delete all .map.bin, .knm.bin and .knm files\n"
247
            "    for mirror %s and regenerate them or replace the missing files\n", filename, name);
248

249
    if ((inter.debug & 128) && !options.quiet)
250
        message("* Reading map file %s...\n", buf);
251

252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
    MD5Init(&ctx);

    //calculate length that the file should be
    filesize = sizeof (ctx.digest);
    filesize += sizeof (map->rows);
    filesize += sizeof (map->cols);
    filesize += sizeof (double) * 4 * map->rows * map->cols;

    open_file_to_read_binary(filename, &file);

    fseek(file, 0L, SEEK_END);
    unsigned long fs = ftell(file);
    fseek(file, 0L, SEEK_SET);

    if (filesize != fs)
267
        gerror("The merged map data in %s has a different filesize to what was expected\n"
Daniel Brown's avatar
Daniel Brown committed
268
            "    for the mirror %s.  Please delete all .map.bin, .knm.bin and .knm files\n"
269
            "    for mirror %s and regenerate them or replace with the correct files\n", filename, name);
270

271 272 273 274 275
#if DEBUG
    filebuf = (unsigned char*) calloc(filesize, sizeof (unsigned char));
#else
    filebuf = (unsigned char*) malloc(filesize);
#endif
276 277

    fread(filebuf, sizeof (unsigned char), filesize, file);
278
    fseek(file, 0L, SEEK_SET); // get back to the start of the file
279 280

    MD5Update(&ctx, &filebuf[16], filesize - 16);
281
    MD5Final(&ctx);
282

283 284 285 286
    int rows, cols;
    unsigned long pos = 0;

    // compare checksum
287
    if (memcmp(ctx.digest, filebuf, sizeof (ctx.digest)))
288
        gerror("The checksum for file %s did not match the stored checksum value.\n"
Daniel Brown's avatar
Daniel Brown committed
289
            "    Please delete all .map.bin, .knm.bin and .knm files for mirror %s\n"
290
            "    and regenerate them or replace with the correct files\n", filename, name);
291

292 293 294 295 296 297 298
    pos += sizeof (ctx.digest);

    rows = *((int*) &filebuf[pos]);
    pos += sizeof (map->rows);

    cols = *((int*) &filebuf[pos]);
    pos += sizeof (map->cols);
299 300

    if (rows != map->rows || cols != map->cols)
301
        gerror("The merged map data in %s has a different number of rows and columns to\n"
302
            "    what was expected for the mirror %s. Please delete all .map.bin,\n"
Daniel Brown's avatar
Daniel Brown committed
303
            "    .knm.bin and .knm files for mirror %s and regenerate them or\n"
304
            "     replace with the correct files\n", filename, name);
305 306 307

    size_t s = sizeof (map->r_abs[0][0]);

308
    int i;
309
    for (i = 0; i < map->cols; i++) {
310
        memcpy(map->r_abs[i], &filebuf[pos], s * rows);
311
        pos += cols*s;
312
        EOF_CHECK;
313
        memcpy(map->r_phs[i], &filebuf[pos], s * rows);
314
        pos += cols*s;
315
        EOF_CHECK;
316
        memcpy(map->t_abs[i], &filebuf[pos], s * rows);
317
        pos += cols*s;
318
        EOF_CHECK;
319
        memcpy(map->t_phs[i], &filebuf[pos], s * rows);
320 321 322
        pos += cols*s;
        EOF_CHECK;
    }
323 324

    if (pos != filesize)
325
        bug_error("Whilst reading the binary merged map we didn't read the entire file.\n");
326

327 328 329 330
    free(filebuf);
    fclose(file);
}

Daniel Brown's avatar
Daniel Brown committed
331
void _read_knm_binary_data(char *name, surface_merged_map_t *map, void *knm, bool converting, KNM_COMPONENT_t knmcmp){
332 333 334 335
    FILE *file;
    unsigned char* filebuf;
    unsigned long filesize;
    char buf[LINE_LEN];
Daniel Brown's avatar
Daniel Brown committed
336
    char filename[FILENAME_MAX];
337 338
    MD5_CTX ctx;

Daniel Brown's avatar
Daniel Brown committed
339
    sprintf(buf, "%s.knm.bin", map->filename);
340 341 342
    strcpy(filename, buf);

    if (!check_if_file_exists(filename))
Daniel Brown's avatar
Daniel Brown committed
343
        gerror("The map file %s is missing. Please delete all .map.bin, .knm.bin and .knm files\n"
344
            "    for mirror %s and regenerate them or replace the missing files\n", filename, name);
345

346
    if (inter.debug && !options.quiet)
Daniel Brown's avatar
Daniel Brown committed
347
        message("* Reading binary knm file %s...\n", buf);
348

349 350 351 352
    MD5Init(&ctx);
    // this is the num_fields of the simulation that wrote the 
    // data file, not the currrent one!
    int num_fields = (int) (map->_maxtem + 1) * (map->_maxtem + 2) / 2;
Daniel Brown's avatar
Daniel Brown committed
353
    int numknm = num_fields*num_fields;
354

355 356 357
    //calculate length that the file should be
    filesize = sizeof (ctx.digest);
    filesize += sizeof (int);
358
    // length for n1,n2,m1,m2 for each knm
Daniel Brown's avatar
Daniel Brown committed
359
    filesize += numknm * 4 * sizeof (unsigned char);
360 361 362
    
    // length of each knm
    if(knmcmp == MIRROR_CMP)
Daniel Brown's avatar
Daniel Brown committed
363
        filesize += numknm * 4 * (sizeof (complex_t));
364
    else if(knmcmp == BEAMSPLITTER_CMP)
Daniel Brown's avatar
Daniel Brown committed
365
        filesize += numknm * 8 * (sizeof (complex_t));
366
    else
Daniel Brown's avatar
Daniel Brown committed
367
        bug_error("couldn't handle knmcmp in _read_knm_binary_data");
368

369 370 371 372 373 374 375
    open_file_to_read_binary(filename, &file);

    fseek(file, 0L, SEEK_END);
    unsigned long fs = ftell(file);
    fseek(file, 0L, SEEK_SET);

    if (filesize != fs)
376
        gerror("The merged map data in %s has a different filesize to what was expected for\n"
Daniel Brown's avatar
Daniel Brown committed
377
            "    the mirror %s.  Please delete all .map.bin, .knm.bin and .knm files for\n"
378
            "    mirror %s and regenerate them or replace with the correct files\n", filename, name);
379

380 381 382 383 384
#if DEBUG
    filebuf = (unsigned char*) calloc(filesize, sizeof (unsigned char));
#else
    filebuf = (unsigned char*) malloc(filesize);
#endif
385 386

    if (filebuf == NULL)
387
        gerror("Out of memory: Could not allocate enough memory to create binary file buffer.\n");
388 389

    // load the whole file into memory
390
    fread(filebuf, sizeof (unsigned char), filesize, file);
391
    fseek(file, 0L, SEEK_SET); // get back to the start of the file
392 393

    MD5Update(&ctx, &filebuf[16], filesize - 16);
394
    MD5Final(&ctx);
395

396 397 398
    unsigned long pos = 0;

    // compare checksum
399
    if (memcmp(ctx.digest, filebuf, sizeof (ctx.digest)))
400
        gerror("The checksum for file %s did not match the stored checksum value.\n"
Daniel Brown's avatar
Daniel Brown committed
401
            "    Please delete all .map.bin, .knm.bin and .knm files for mirror %s\n"
402
            "    and regenerate them or replace with the correct files\n", filename, name);
403 404 405

    pos = sizeof (ctx.digest);

Daniel Brown's avatar
Daniel Brown committed
406 407
    int numknm_read = *((int*) &filebuf[pos]);
    pos += sizeof (numknm_read);
408

Daniel Brown's avatar
Daniel Brown committed
409
    // if the number of knm we calculated there would be earlier is not the
410
    // same as what has just been read there is a problem
Daniel Brown's avatar
Daniel Brown committed
411 412 413
    if (numknm_read != numknm)
        gerror("The number of knm's in the file %s was not what was expected.\n"
            "    Please delete all .map.bin, .knm.bin and .knm files for mirror %s\n"
414
            "    and regenerate them or replace with the correct files\n", filename, name);
415

416
#ifdef DEBUG
417
    if(knmcmp == MIRROR_CMP) {
Daniel Brown's avatar
Daniel Brown committed
418 419
        if (!IS_MIRROR_KNM_ALLOCD((mirror_knm_t*)knm))
            bug_error(" ! Mirror knm matric was not allocated\n");
420
    } else if(knmcmp == BEAMSPLITTER_CMP) {
Daniel Brown's avatar
Daniel Brown committed
421 422
        if (!IS_BS_KNM_ALLOCD((bs_knm_t*)knm))
            bug_error(" ! Beamsplitter knm matric was not allocated\n");
423
    }
424
#endif
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449

    int n, m, n1, n2, m1, m2;
    unsigned char _n1, _n2, _m1, _m2;
    size_t cs = sizeof (complex_t);

    for (n = 0; n < num_fields; n++) {
        for (m = 0; m < num_fields; m++) {
            _n1 = *((unsigned char*) &filebuf[pos]);
            pos += 1;
            EOF_CHECK;
            _n2 = *((unsigned char*) &filebuf[pos]);
            pos += 1;
            EOF_CHECK;
            _m1 = *((unsigned char*) &filebuf[pos]);
            pos += 1;
            EOF_CHECK;
            _m2 = *((unsigned char*) &filebuf[pos]);
            pos += 1;
            EOF_CHECK;

            n1 = (int) _n1;
            n2 = (int) _n2;
            m1 = (int) _m1;
            m2 = (int) _m2;

Daniel Brown's avatar
Daniel Brown committed
450
            if (converting) {
451 452 453 454 455
                nms[n + num_fields * m].n1 = n1;
                nms[n + num_fields * m].n2 = n2;
                nms[n + num_fields * m].m1 = m1;
                nms[n + num_fields * m].m2 = m2;
            }
Daniel Brown's avatar
Daniel Brown committed
456

457 458 459
            if (((n1 + m1) <= inter.tem) && ((n2 + m2) <= inter.tem)) {
                int f1 = get_field_index_from_tem(n1, m1);
                int f2 = get_field_index_from_tem(n2, m2);
460

461 462
                switch(knmcmp){
                    case MIRROR_CMP:
Daniel Brown's avatar
Daniel Brown committed
463
                        memcpy(&(((mirror_knm_t*)knm)->k11[f1][f2]), &filebuf[pos], cs);
464 465
                        pos += cs;
                        EOF_CHECK;
Daniel Brown's avatar
Daniel Brown committed
466
                        memcpy(&(((mirror_knm_t*)knm)->k12[f1][f2]), &filebuf[pos], cs);
467 468
                        pos += cs;
                        EOF_CHECK;
Daniel Brown's avatar
Daniel Brown committed
469
                        memcpy(&(((mirror_knm_t*)knm)->k21[f1][f2]), &filebuf[pos], cs);
470 471
                        pos += cs;
                        EOF_CHECK;
Daniel Brown's avatar
Daniel Brown committed
472
                        memcpy(&(((mirror_knm_t*)knm)->k22[f1][f2]), &filebuf[pos], cs);
473 474 475 476
                        pos += cs;
                        EOF_CHECK;
                        break;
                    case BEAMSPLITTER_CMP:
Daniel Brown's avatar
Daniel Brown committed
477
                        memcpy(&(((bs_knm_t*)knm)->k12[f1][f2]), &filebuf[pos], cs);
478 479
                        pos += cs;
                        EOF_CHECK;
Daniel Brown's avatar
Daniel Brown committed
480
                        memcpy(&(((bs_knm_t*)knm)->k21[f1][f2]), &filebuf[pos], cs);
481 482
                        pos += cs;
                        EOF_CHECK;
Daniel Brown's avatar
Daniel Brown committed
483
                        memcpy(&(((bs_knm_t*)knm)->k34[f1][f2]), &filebuf[pos], cs);
484 485
                        pos += cs;
                        EOF_CHECK;
Daniel Brown's avatar
Daniel Brown committed
486
                        memcpy(&(((bs_knm_t*)knm)->k43[f1][f2]), &filebuf[pos], cs);
487 488
                        pos += cs;
                        EOF_CHECK;
Daniel Brown's avatar
Daniel Brown committed
489
                        memcpy(&(((bs_knm_t*)knm)->k13[f1][f2]), &filebuf[pos], cs);
490 491
                        pos += cs;
                        EOF_CHECK;
Daniel Brown's avatar
Daniel Brown committed
492
                        memcpy(&(((bs_knm_t*)knm)->k31[f1][f2]), &filebuf[pos], cs);
493 494
                        pos += cs;
                        EOF_CHECK;
Daniel Brown's avatar
Daniel Brown committed
495
                        memcpy(&(((bs_knm_t*)knm)->k24[f1][f2]), &filebuf[pos], cs);
496 497
                        pos += cs;
                        EOF_CHECK;
Daniel Brown's avatar
Daniel Brown committed
498
                        memcpy(&(((bs_knm_t*)knm)->k42[f1][f2]), &filebuf[pos], cs);
499 500 501 502 503
                        pos += cs;
                        EOF_CHECK;
                        break;
                }
                
504
            } else {
505 506 507 508 509 510 511 512 513
                if(knmcmp == MIRROR_CMP)
                    pos += cs * 4;  
                else if(knmcmp == BEAMSPLITTER_CMP)
                    pos += cs * 8;
                
                //EOF_CHECK;
                if(pos > filesize) 
                    gerror(" ! %s:%i :: Prematurely reached the end of the map file %s. The file" 
                            " could be corrupt or the incorrect map file for the mirror. Please" 
Daniel Brown's avatar
Daniel Brown committed
514
                            " delete all .map.bin, .knm.bin and .knm files for mirror %s" 
515
                            " and regenerate them or replace with the correct files\n",__FILE__,__LINE__, filename);
516
            }
517
        }
518
    }
519 520


521 522 523 524
    fclose(file);
    free(filebuf);
}

Daniel Brown's avatar
Daniel Brown committed
525 526
//bool read_mirror_knm_files(mirror_t *mirror, bool converting) {
bool read_knm_file(void *cmp, bool converting, KNM_COMPONENT_t knmcmp) {
527 528 529
#define READ(A) \
linenum++;\
fgets(buf, LINE_LEN-1,file); \
530
if(feof(file)) gerror("Unexpectedly reached the end of the coupling coefficient file '%s'. Please delete this file and recompute it\n as it could be corrupt or for the wrong version of Finesse.\n",knmfilename); \
531
((A == 0) ? gerror("Line %i ('%s') could not be read in map file %s\n" , linenum, buf, knmfilename) : NULL)
532

Daniel Brown's avatar
Daniel Brown committed
533 534 535 536 537
    char *name=NULL;
    surface_map_t **maps=NULL;
    surface_merged_map_t *map=NULL;
    void* knm=NULL;
    int num_maps=0; 
538 539 540 541 542 543
    
    if(knmcmp == MIRROR_CMP) {
        mirror_t *mirror = (mirror_t*)cmp;
        
        name = mirror->name;
        map = &mirror->map_merged;
Daniel Brown's avatar
Daniel Brown committed
544
        knm = (void*)&mirror->knm_map;
545 546 547 548 549 550 551
        num_maps = mirror->num_maps;
        maps = mirror->map;
        
    } else if(knmcmp == BEAMSPLITTER_CMP) {
        beamsplitter_t *bs = (beamsplitter_t*)cmp;
        name = bs->name;
        map = &bs->map_merged;
Daniel Brown's avatar
Daniel Brown committed
552
        knm = (void*)&bs->knm_map;
553 554 555 556
        num_maps = bs->num_maps;
        maps = bs->map;
        
    } else
Daniel Brown's avatar
Daniel Brown committed
557
        bug_error("Couldn't handle component in read_knm_file()");
558
    
559
    FILE *file = NULL;
560

561
    assert(knm != NULL);
562 563 564 565 566 567
    assert(map != NULL);

    char buf[LINE_LEN];
    int linenum = 0;
    char knmfilename[LINE_LEN];

568
    sprintf(knmfilename, "%s.knm", map->filename);
569

570
    if (!check_if_file_exists(knmfilename)) {
571
        return false;
572
    } else {
573
        open_file_to_read_ascii(knmfilename, &file);
574 575 576 577 578 579 580

        // read three lines of comments
        READ(sscanf(buf, "%% %s", buf));
        READ(sscanf(buf, "%% %s", buf));
        READ(sscanf(buf, "%% %s", buf));

        int n, mapnum = 0;
581 582
        
        if(knmcmp == BEAMSPLITTER_CMP){
Daniel Brown's avatar
Daniel Brown committed
583
            READ(sscanf(buf, "component : %s", buf));
584 585
            
            if (strcmp(buf, "BEAMSPLITTER") != 0)
586
                gerror("Type of knm file '%s' read was not for a BEAMSPLITTER component, %s\n", knmfilename, name);
587 588
            
        } else if(knmcmp == MIRROR_CMP){
Daniel Brown's avatar
Daniel Brown committed
589
            READ(sscanf(buf, "component : %s", buf));
590 591
            
            if (strcmp(buf, "MIRROR") != 0)
592
                gerror("Type of knm file '%s' read was not for a MIRROR component, %s\n", knmfilename, name);
593
            
594
        } else
595
            bug_error("Could not understand knmcmp %i\n", knmcmp);
596
        
597
        READ(sscanf(buf, "mapnum : %i", &mapnum));
598 599 600 601
        
        int bphstrans = 0;
        READ(sscanf(buf, "transonly : %i", &bphstrans));
        map->phaseIsOnlyTransmission = (bool) bphstrans;
602
        
603 604
        int bhasreflmap = 0;
        READ(sscanf(buf, "hasreflmap : %i", &bhasreflmap));
605
        map->hasReflectivityMap = (bool) bhasreflmap;
606
        
607
        // if we haven't got the same number of maps recompute
Daniel Brown's avatar
Daniel Brown committed
608

609
        if (mapnum != num_maps && !converting) {
610
            if (inter.debug && !options.quiet)
611
                message("* KNM file read: Different number of maps on component %s\n", name);
612

Daniel Brown's avatar
Daniel Brown committed
613
            return false;
614 615 616 617 618 619 620 621
        } else {
            // if we are converting get the map numbers from the file
            num_maps = mapnum;
            
            if ( mapnum > 0 )
                map->noMapPresent = false;
            else
                map->noMapPresent = true;
622
        }
623
        
624 625
        int mn;
        char mapfile[LINE_LEN];
626 627
        char B64maphash[LINE_LEN];
        unsigned char maphash[LINE_LEN];
628

629 630
        // if we are converting the knn file the various map files
        // won't be loaded so no need to check them
Daniel Brown's avatar
Daniel Brown committed
631
        if (!converting) {
632
            for (n = 0; n < mapnum; n++) {
633
                READ(sscanf(buf, "map%i : %s %s", &mn, mapfile, B64maphash));
634 635
                // if the map is not the same file name then the order could have 
                // changed or different maps have been used.
636
                if (strcmp(maps[n]->filename, mapfile) != 0) {
637
                    if (inter.debug && !options.quiet)
638
                        message("* KNM file read: Map order on component %s is different to knm file\n", name);
639

640
                    return false;
641
                }
642

643
                // make sure it isnt too long
644 645
                if (strlen(B64maphash) > 30) {
                    if (inter.debug && !options.quiet)
646
                        message("* KNM file read: The Base64 hash key is not correct for file %s\n", mapfile);
647

648 649
                    return false;
                }
650

651
                //First need to decode the base64 hash
652 653
                if (!decode_base64(maphash, B64maphash)) {
                    if (inter.debug && !options.quiet)
654
                        message("* KNM file read: Could not decode the Base64 hash key correctly for file %s\n", mapfile);
655

656 657
                    return false;
                }
658

659 660
                // compare the hash that has been read when reading the maps
                // and that in the file
661
                if (memcmp((char*) maps[n]->hash, (char*) maphash, 16) != 0) {
662
                    if (inter.debug && !options.quiet)
663
                        message("* KNM file read: Map hash code was not the same for file %s\n", mapfile);
664

665 666
                    return false;
                }
667
            }
Daniel Brown's avatar
Daniel Brown committed
668
        } else {
669 670 671
            // however if we are converting then we do need to store the map
            // names to write again later, so we fake the maps here
            long currpos;
672

673 674 675 676
            if(knmcmp == MIRROR_CMP)
                ((mirror_t*)cmp)->num_maps = num_maps;
            else if(knmcmp == BEAMSPLITTER_CMP)
                ((beamsplitter_t*)cmp)->num_maps = num_maps;
677
            else
Daniel Brown's avatar
Daniel Brown committed
678
                bug_error("Could not handle knmcmp value %i",knmcmp);
679
            
680 681
            int i = 0;
            
Daniel Brown's avatar
Daniel Brown committed
682
            while (true) {
683
                currpos = ftell(file);
Daniel Brown's avatar
Daniel Brown committed
684 685 686
                fgets(buf, LINE_LEN - 1, file);

                if (feof(file))
687
                    gerror("Unexpectedly reached the end of the coupling coefficient file '%s'. Please delete this file and recompute it\n as it could be corrupt or for the wrong version of Finesse.\n",knmfilename);
Daniel Brown's avatar
Daniel Brown committed
688

689
                // check if the start of the line is a map definition
Daniel Brown's avatar
Daniel Brown committed
690
                if (strcspn(buf, "map") == 0 && strlen(buf) != 0) {
691
                    char b64Hash[LINE_LEN];
692
                    
693
                    maps[i] = (surface_map_t *) calloc(1, sizeof (surface_map_t));
694

695
                    if (maps[i] == NULL) {
696 697
                        bug_error("memory allocation for surface map failed");
                    }
698 699
                    
                    sscanf(buf, "map%i : %s %s", &mn, maps[i]->filename, b64Hash);
Daniel Brown's avatar
Daniel Brown committed
700

701 702 703 704 705 706 707 708
                    if ( !decode_base64(maps[i]->hash, b64Hash)){
                        gerror("Could not decode the BASE64 string %s for map %i in %s",b64Hash, maps[i]->filename, knmfilename);
                    }
        
                    // if the number of maps read so far is different to the map
                    // index there is a problem
                    if(mn != i)
                        bug_error("Problem converting line '%s' as the map index did not increase by 1 each time", buf);
Daniel Brown's avatar
Daniel Brown committed
709

710
                    i++; // keep track of how many maps we have read
711
                    
Daniel Brown's avatar
Daniel Brown committed
712
                } else
713 714
                    break;
            }
715 716 717 718
            
            // check that hte number of maps read is the same as what was specified in the file
            if(mapnum != i)
                bug_error("Only %i maps were loaded when %i should have been",i, mapnum);
Daniel Brown's avatar
Daniel Brown committed
719

720 721 722 723 724 725 726 727
            //reset to the start of the line so the next read works
            fseek(file, currpos, SEEK_SET);
        }

        READ(sscanf(buf, "integration method : %i", &map->_intmeth));
        READ(sscanf(buf, "interpolation method : %i", &map->_intermeth));
        READ(sscanf(buf, "interpolation size : %i", &map->_intersize));

728 729
        // if the interpolation method, size or the integration method used
        // has changed then return false and recompute the map data
730 731
        if (map->_intmeth != map->integration_method && !converting) {
            if (inter.debug && !options.quiet)
732
                message("* KNM file read: Different integration method used on component %s\n", name);
733
            return false;
734
        }
735 736
        if (map->_intermeth != map->interpolation_method && !converting) {
            if (inter.debug && !options.quiet)
737
                message("* KNM file read: Different interpolation method used on component %s\n", name);
738 739
            return false;
        }
740 741
        if (map->_intersize != map->interpolation_size && !converting) {
            if (inter.debug && !options.quiet)
742
                message("* KNM file read: Different interpolation size used on component %s\n", name);
743 744
            return false;
        }
745
        if(knmcmp == MIRROR_CMP){
Daniel Brown's avatar
Daniel Brown committed
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764
            READ(sscanf(buf, "qx1_11 : %lg %lg", &(map->mirror_knm_q.qxt1_11.re), &(map->mirror_knm_q.qxt1_11.im)));
            READ(sscanf(buf, "qy1_11 : %lg %lg", &(map->mirror_knm_q.qyt1_11.re), &(map->mirror_knm_q.qyt1_11.im)));
            READ(sscanf(buf, "qx2_11 : %lg %lg", &(map->mirror_knm_q.qxt2_11.re), &(map->mirror_knm_q.qxt2_11.im)));
            READ(sscanf(buf, "qy2_11 : %lg %lg", &(map->mirror_knm_q.qyt2_11.re), &(map->mirror_knm_q.qyt2_11.im)));

            READ(sscanf(buf, "qx1_12 : %lg %lg", &(map->mirror_knm_q.qxt1_12.re), &(map->mirror_knm_q.qxt1_12.im)));
            READ(sscanf(buf, "qy1_12 : %lg %lg", &(map->mirror_knm_q.qyt1_12.re), &(map->mirror_knm_q.qyt1_12.im)));
            READ(sscanf(buf, "qx2_12 : %lg %lg", &(map->mirror_knm_q.qxt2_12.re), &(map->mirror_knm_q.qxt2_12.im)));
            READ(sscanf(buf, "qy2_12 : %lg %lg", &(map->mirror_knm_q.qyt2_12.re), &(map->mirror_knm_q.qyt2_12.im)));

            READ(sscanf(buf, "qx1_21 : %lg %lg", &(map->mirror_knm_q.qxt1_21.re), &(map->mirror_knm_q.qxt1_21.im)));
            READ(sscanf(buf, "qy1_21 : %lg %lg", &(map->mirror_knm_q.qyt1_21.re), &(map->mirror_knm_q.qyt1_21.im)));
            READ(sscanf(buf, "qx2_21 : %lg %lg", &(map->mirror_knm_q.qxt2_21.re), &(map->mirror_knm_q.qxt2_21.im)));
            READ(sscanf(buf, "qy2_21 : %lg %lg", &(map->mirror_knm_q.qyt2_21.re), &(map->mirror_knm_q.qyt2_21.im)));

            READ(sscanf(buf, "qx1_22 : %lg %lg", &(map->mirror_knm_q.qxt1_22.re), &(map->mirror_knm_q.qxt1_22.im)));
            READ(sscanf(buf, "qy1_22 : %lg %lg", &(map->mirror_knm_q.qyt1_22.re), &(map->mirror_knm_q.qyt1_22.im)));
            READ(sscanf(buf, "qx2_22 : %lg %lg", &(map->mirror_knm_q.qxt2_22.re), &(map->mirror_knm_q.qxt2_22.im)));
            READ(sscanf(buf, "qy2_22 : %lg %lg", &(map->mirror_knm_q.qyt2_22.re), &(map->mirror_knm_q.qyt2_22.im)));
765 766

        }else if(knmcmp == BEAMSPLITTER_CMP){
Daniel Brown's avatar
Daniel Brown committed
767 768 769 <