def readVoxet(domain, filename, voproperty=1, origin=None, fillValue=0., referenceSystem=CartesianReferenceSystem()): """ Reads a single property from a GOCAD Voxet file and returns a data object on the given domain with the property data. Restrictions: - Voxet origin in UVW space (i.e. AXIS_MIN) needs to be [0,0,0] - samples size must be 4 (float32) or 8 (float64) - data type must be IEEE - format must be RAW - domain resolution must be (approximately) a multiple of voxet resolution :param domain: the domain to use for data (must be a ripley domain) :type domain: `Domain` :param filename: Voxet header filename (usually ends in .vo) :type filename: ``string`` :param voproperty: identifier of the property to read. Either the numeric property ID, the property name, or the filename of the property data. :type voproperty: ``int`` or ``string`` :param origin: if supplied will override the Voxet origin as read from the file. :type origin: ``list`` or ``tuple`` or ``None`` :param fillValue: value to use for cells that are not covered by property data (if applicable) :type fillValue: ``float`` :param referenceSystem: coordinate system of domain. Used to scale vertical axis accordingly :type referenceSystem: `ReferenceSystem` """ from esys.ripley import readBinaryGrid, BYTEORDER_BIG_ENDIAN, DATATYPE_FLOAT32, DATATYPE_FLOAT64 header = open(filename).readlines() if not header[0].startswith('GOCAD Voxet'): raise ValueError("Voxet header not found. Invalid Voxet file?!") NE = None axis_uvw = [None, None, None] axis_min = [0., 0., 0.] axis_max = [1., 1., 1.] # props[id]=[name,file,datatype] props = {} for line in header: if line.startswith('AXIS_O '): if origin is None: origin = [float(i) for i in line.split()[1:4]] elif line.startswith('AXIS_U '): u = [float(i) for i in line.split()[1:4]] if (u[1] != 0) or (u[2] != 0): raise ValueError('This coordinate system is not supported') axis_uvw[0] = u[0] elif line.startswith('AXIS_V '): v = [float(i) for i in line.split()[1:4]] if (v[0] != 0) or (v[2] != 0): raise ValueError('This coordinate system is not supported') axis_uvw[1] = v[1] elif line.startswith('AXIS_W '): w = [float(i) for i in line.split()[1:4]] if (w[0] != 0) or (w[1] != 0): raise ValueError('This coordinate system is not supported') axis_uvw[2] = w[2] elif line.startswith('AXIS_MIN '): axis_min = [float(i) for i in line.split()[1:4]] if axis_min != [0, 0, 0]: raise ValueError('AXIS_MIN != [0,0,0] is not supported') elif line.startswith('AXIS_MAX '): axis_max = [float(i) for i in line.split()[1:4]] elif line.startswith('AXIS_N '): NE = [int(i) for i in line.split()[1:4]] elif line.startswith('PROPERTY '): propid = int(line.split()[1]) if not propid in props: props[propid] = [None, None, None] props[propid][0] = line.split()[2].strip() elif line.startswith('PROP_ESIZE '): propid = int(line.split()[1]) t = int(line.split()[2]) if t == 4: props[propid][2] = DATATYPE_FLOAT32 elif t == 8: props[propid][2] = DATATYPE_FLOAT64 else: raise ValueError('Unsupported data size ' + t) elif line.startswith('PROP_ETYPE '): t = line.split()[2].strip() if t != 'IEEE': raise ValueError('Unsupported data type ' + t) elif line.startswith('PROP_FORMAT '): t = line.split()[2].strip() if t != 'RAW': raise ValueError('Unsupported data format ' + t) elif line.startswith('PROP_OFFSET '): dataoffset = int(line.split()[2]) if dataoffset != 0: raise ValueError('data offset != 0 not supported') elif line.startswith('PROP_FILE '): propid = int(line.split()[1]) props[propid][1] = line.split()[2].strip() if (axis_uvw[0] is None) or (axis_uvw[1] is None) or (axis_uvw[2] is None)\ or (NE is None) or (origin is None): raise ValueError( 'Could not determine data configuration. Invalid file?!') if len(props) == 0: raise ValueError('No properties found.') # voxets have these conventions: # AXIS_N = number of samples (=cells!) in each dimension # AXIS_UVW * AXIS_MAX = voxet length in each dimension # AXIS_O = origin of voxet (cell centres!) # see also http://paulbourke.net/dataformats/gocad/gocad.pdf length = [axis_uvw[i] * axis_max[i] for i in range(3)] # modify length and origin to account for the fact that Voxet cells are # centred at the data points, i.e.: # BEFORE: AFTER: # # O----length---->| O------length------>| # ___________________ ___________________ # | * | * | * | * | * | | * | * | * | * | * | # ------------------- ------------------- for i in range(3): dz = length[i] / (NE[i] - 1) origin[i] -= dz / 2. length[i] += dz if referenceSystem.isCartesian(): v_scale = 1. else: v_scale = 1. / referenceSystem.getHeightUnit() origin[-1] = origin[-1] * v_scale # retrieve domain configuration so we know where to place the voxet data gridorigin, gridspacing, gridNE = domain.getGridParameters() # determine base location of this dataset within the domain first = [ int((origin[i] - gridorigin[i]) / gridspacing[i]) for i in range(domain.getDim()) ] # determine the resolution difference between domain and data. # If domain has twice the resolution we can double up the data etc. multiplier = [ int(round((abs(length[i]) / NE[i]) / gridspacing[i])) for i in range(domain.getDim()) ] # NOTE: Depending on your data you might have to multiply your vertical # multiplier by 1000. to convert km in meters. #multiplier[-1] = int(multiplier[-1] * v_scale * 1000.) multiplier[-1] = int(multiplier[-1] * v_scale) datatype = None propfile = None for pid in props.keys(): p = props[pid] if (isinstance(voproperty, int) and pid == voproperty) or \ (isinstance(voproperty, str) and (p[0]==voproperty or p[1]==voproperty)): datatype = p[2] name = p[1] #remove quotes which GoCAD introduces for filenames with spaces if name.startswith('"') and name.endswith('"'): name = name[1:-1] propfile = os.path.join(os.path.dirname(filename), name) print("Voxet property file: %s" % propfile) break if propfile is None or datatype is None: raise ValueError("Invalid property " + str(voproperty)) reverse = [0] * domain.getDim() if axis_uvw[-1] < 0: reverse[-1] = 1 print( "calling readBinaryGrid with first=%s, nValues=%s, multiplier=%s, reverse=%s" % (str(first), str(NE), str(multiplier), str(reverse))) data = readBinaryGrid(propfile, ReducedFunction(domain), shape=(), fill=fillValue, byteOrder=BYTEORDER_BIG_ENDIAN, dataType=p[2], first=first, numValues=NE, multiplier=multiplier, reverse=reverse) return data
def readVoxet(domain, filename, voproperty=0, origin=None, fillValue=0., reference_system=None): """This subroutine reads in the Voxet and returns an escript Data object""" header=open(filename).readlines() if not header[0].startswith('GOCAD Voxet'): raise ValueError("Invalid Voxet file") NE=None axis_uvw=[None,None,None] axis_min=[0.,0.,0.] axis_max=[1.,1.,1.] # props[id]=[name,file,datatype] props={} for line in header: if line.startswith('AXIS_O '): if origin is None: origin=[float(i) for i in line.split()[1:4]] elif line.startswith('AXIS_U '): u=[float(i) for i in line.split()[1:4]] if (u[1] != 0) or (u[2] != 0): raise ValueError('This coordinate system is not supported') axis_uvw[0]=u[0] elif line.startswith('AXIS_V '): v=[float(i) for i in line.split()[1:4]] if (v[0] != 0) or (v[2] != 0): raise ValueError('This coordinate system is not supported') axis_uvw[1]=v[1] elif line.startswith('AXIS_W '): w=[float(i) for i in line.split()[1:4]] if (w[0] != 0) or (w[1] != 0): raise ValueError('This coordinate system is not supported') axis_uvw[2]=w[2] elif line.startswith('AXIS_MIN '): axis_min=[float(i) for i in line.split()[1:4]] elif line.startswith('AXIS_MAX '): axis_max=[float(i) for i in line.split()[1:4]] elif line.startswith('AXIS_N '): NE=[int(i) for i in line.split()[1:4]] elif line.startswith('PROPERTY '): propid=int(line.split()[1]) if not props.has_key(propid): props[propid]=[None,None,None] props[propid][0]=line.split()[2].strip() elif line.startswith('PROP_ESIZE '): propid=int(line.split()[1]) t=int(line.split()[2]) if t==4: props[propid][2]=DATATYPE_FLOAT32 elif t==8: props[propid][2]=DATATYPE_FLOAT64 else: raise ValueError('Unsupported data size '+t) elif line.startswith('PROP_ETYPE '): t=line.split()[2].strip() if t != 'IEEE': raise ValueError('Unsupported data type '+t) elif line.startswith('PROP_FORMAT '): t=line.split()[2].strip() if t != 'RAW': raise ValueError('Unsupported data format '+t) elif line.startswith('PROP_OFFSET '): dataoffset=int(line.split()[2]) if dataoffset != 0: raise ValueError('data offset != 0 not supported yet') elif line.startswith('PROP_FILE '): propid=int(line.split()[1]) props[propid][1]=line.split()[2].strip() if (axis_uvw[0] is None) or (axis_uvw[1] is None) or (axis_uvw[2] is None)\ or (NE is None) or (origin is None): raise ValueError('Could not determine data configuration. Invalid file?!') if len(props)==0: raise ValueError('No properties found.') #l=[(origin[i], origin[i]+axis_uvw[i]*axis_max[i]) for i in range(3)] gridorigin, gridspacing, gridNE = domain.getGridParameters() if not reference_system: reference_system = CartesianReferenceSystem() if reference_system.isCartesian(): v_scale=1. else: v_scale=1./reference_system.getHeightUnit() # add 2x half cells (top and bottom) dz = axis_uvw[-1] / (NE[-1]-1) axis_uvw = [x + dz for x in axis_uvw] origin[-1] = origin[-1]*v_scale # determine base location of this dataset within the domain first=[int((origin[i]-gridorigin[i])/gridspacing[i]) for i in range(domain.getDim())] datatype=None propfile=None for p in props.values(): if (isinstance(voproperty, int) and p[1] == voproperty) or \ (isinstance(voproperty, str) and p[0] == voproperty): datatype=p[2] name=p[1] # remove quotes which GoCAD introduces for filenames with spaces if name.startswith('"') and name.endswith('"'): name=name[1:-1] propfile=os.path.join(os.path.dirname(filename), name) print("Voxet property file: %s"%propfile) break if propfile is None or datatype is None: raise ValueError("Invalid property "+str(voproperty)) multiplier = [1,1,1] reverse = [0]*domain.getDim() if axis_uvw[-1] < 0: reverse[-1]=1 data=readBinaryGrid(propfile, ReducedFunction(domain), shape=(), fill=fillValue, byteOrder=BYTEORDER_BIG_ENDIAN, dataType=p[2], first=first, numValues=NE, multiplier=multiplier, reverse=reverse) return data
def RegionalCalculation(reg_mask): """ Calculates the "regional" from the entire FEILDS model excluding the selected region and outputs gravity at the specified altitude... see above for the "residual" """ # read in a gravity data grid to define data computation space G_DATA = os.path.join(DATADIR,'Final_BouguerTC_UC15K_qrtdeg.nc') FS=ReducedFunction(dom) nValues=[NX, NY, 1] first = [0, 0, cell_at_altitude] multiplier = [1, 1, 1] reverse = [0, 0, 0] byteorder = BYTEORDER_NATIVE gdata = readBinaryGrid(G_DATA, FS, shape=(), fill=-999999, byteOrder=byteorder, dataType=DATATYPE_FLOAT32, first=first, numValues=nValues, multiplier=multiplier, reverse=reverse) print("Grid successfully read") # get the masking and units sorted out for the data-space g_mask = whereNonZero(gdata+999999) gdata=gdata*g_mask * GRAV_UNITS # if people choose to have air in their region we exclude it from the # specified gravity calculation region if h_top < 0.: reg_mask = reg_mask+mask_air live_model = initial_model* whereNonPositive(reg_mask) dead_model = initial_model* wherePositive(reg_mask) if UseMean is True: # calculate the mean density within the selected region BackgroundDensity = integrate(dead_model)/integrate(wherePositive(reg_mask)) print("Density mean for selected region equals = %s"%BackgroundDensity) live_model = live_model + BackgroundDensity * wherePositive(reg_mask) # create mapping rho_mapping = DensityMapping(dom, rho0=live_model) # invert sign of gravity field to account for escript's coordinate system gdata = -GRAV_UNITS * gdata # turn the scalars into vectors (vertical direction) d=kronecker(DIM)[DIM-1] w=safeDiv(1., g_mask) gravity_model=GravityModel(dom, w*d, gdata*d, fixPotentialAtBottom=False, coordinates=COORDINATES) gravity_model.rescaleWeights(rho_scale=rho_mapping.getTypicalDerivative()) phi,_ = gravity_model.getArguments(live_model) g_init = -gravity_model.getCoordinateTransformation().getGradient(phi) g_init = interpolate(g_init, gdata.getFunctionSpace()) print("Computed gravity: %s"%(g_init[2])) fn=os.path.join(OUTPUTDIR,'regional-gravity') if SiloOutput is True: saveSilo(fn, density=live_model, gravity_init=g_init, g_initz=-g_init[2], gravitymask=g_mask, modelmask=reg_mask) print('SILO file written with the following fields: density (kg/m^3), gravity vector (m/s^2), gz (m/s^2), gravitymask, modelmask') # to compare calculated data against input dataset. # Not used by default but should work if the input dataset is correct #gslice = g_init[2]*wherePositive(g_mask) #g_dash = integrate(gslice)/integrate(wherePositive(g_mask)) #gdataslice = gdata*wherePositive(g_mask) #gdata_dash = integrate(gdataslice)/integrate(wherePositive(g_mask)) #misfit=(gdataslice-gdata_dash)-(gslice-g_dash) saveDataCSV(fn+".csv", mask=g_mask, gz=-g_init[2], Long=datacoords[0], Lat=datacoords[1], h=datacoords[2]) print('CSV file written with the following fields: Longitude (degrees) Latitude (degrees), h (100km), gz (m/s^2)')
def readVoxet(domain, filename, voproperty=1, origin=None, fillValue=0., referenceSystem=CartesianReferenceSystem()): """ Reads a single property from a GOCAD Voxet file and returns a data object on the given domain with the property data. Restrictions: - Voxet origin in UVW space (i.e. AXIS_MIN) needs to be [0,0,0] - samples size must be 4 (float32) or 8 (float64) - data type must be IEEE - format must be RAW - domain resolution must be (approximately) a multiple of voxet resolution :param domain: the domain to use for data (must be a ripley domain) :type domain: `Domain` :param filename: Voxet header filename (usually ends in .vo) :type filename: ``string`` :param voproperty: identifier of the property to read. Either the numeric property ID, the property name, or the filename of the property data. :type voproperty: ``int`` or ``string`` :param origin: if supplied will override the Voxet origin as read from the file. :type origin: ``list`` or ``tuple`` or ``None`` :param fillValue: value to use for cells that are not covered by property data (if applicable) :type fillValue: ``float`` :param referenceSystem: coordinate system of domain. Used to scale vertical axis accordingly :type referenceSystem: `ReferenceSystem` """ from esys.ripley import readBinaryGrid, BYTEORDER_BIG_ENDIAN, DATATYPE_FLOAT32, DATATYPE_FLOAT64 header=open(filename).readlines() if not header[0].startswith('GOCAD Voxet'): raise ValueError("Voxet header not found. Invalid Voxet file?!") NE=None axis_uvw=[None,None,None] axis_min=[0.,0.,0.] axis_max=[1.,1.,1.] # props[id]=[name,file,datatype] props={} for line in header: if line.startswith('AXIS_O '): if origin is None: origin=[float(i) for i in line.split()[1:4]] elif line.startswith('AXIS_U '): u=[float(i) for i in line.split()[1:4]] if (u[1] != 0) or (u[2] != 0): raise ValueError('This coordinate system is not supported') axis_uvw[0]=u[0] elif line.startswith('AXIS_V '): v=[float(i) for i in line.split()[1:4]] if (v[0] != 0) or (v[2] != 0): raise ValueError('This coordinate system is not supported') axis_uvw[1]=v[1] elif line.startswith('AXIS_W '): w=[float(i) for i in line.split()[1:4]] if (w[0] != 0) or (w[1] != 0): raise ValueError('This coordinate system is not supported') axis_uvw[2]=w[2] elif line.startswith('AXIS_MIN '): axis_min=[float(i) for i in line.split()[1:4]] if axis_min != [0,0,0]: raise ValueError('AXIS_MIN != [0,0,0] is not supported') elif line.startswith('AXIS_MAX '): axis_max=[float(i) for i in line.split()[1:4]] elif line.startswith('AXIS_N '): NE=[int(i) for i in line.split()[1:4]] elif line.startswith('PROPERTY '): propid=int(line.split()[1]) if not propid in props: props[propid]=[None,None,None] props[propid][0]=line.split()[2].strip() elif line.startswith('PROP_ESIZE '): propid=int(line.split()[1]) t=int(line.split()[2]) if t==4: props[propid][2]=DATATYPE_FLOAT32 elif t==8: props[propid][2]=DATATYPE_FLOAT64 else: raise ValueError('Unsupported data size '+t) elif line.startswith('PROP_ETYPE '): t=line.split()[2].strip() if t != 'IEEE': raise ValueError('Unsupported data type '+t) elif line.startswith('PROP_FORMAT '): t=line.split()[2].strip() if t != 'RAW': raise ValueError('Unsupported data format '+t) elif line.startswith('PROP_OFFSET '): dataoffset=int(line.split()[2]) if dataoffset != 0: raise ValueError('data offset != 0 not supported') elif line.startswith('PROP_FILE '): propid=int(line.split()[1]) props[propid][1]=line.split()[2].strip() if (axis_uvw[0] is None) or (axis_uvw[1] is None) or (axis_uvw[2] is None)\ or (NE is None) or (origin is None): raise ValueError('Could not determine data configuration. Invalid file?!') if len(props)==0: raise ValueError('No properties found.') # voxets have these conventions: # AXIS_N = number of samples (=cells!) in each dimension # AXIS_UVW * AXIS_MAX = voxet length in each dimension # AXIS_O = origin of voxet (cell centres!) # see also http://paulbourke.net/dataformats/gocad/gocad.pdf length = [axis_uvw[i]*axis_max[i] for i in range(3)] # modify length and origin to account for the fact that Voxet cells are # centred at the data points, i.e.: # BEFORE: AFTER: # # O----length---->| O------length------>| # ___________________ ___________________ # | * | * | * | * | * | | * | * | * | * | * | # ------------------- ------------------- for i in range(3): dz = length[i] / (NE[i]-1) origin[i] -= dz/2. length[i] += dz if referenceSystem.isCartesian(): v_scale=1. else: v_scale=1./referenceSystem.getHeightUnit() origin[-1] = origin[-1]*v_scale # retrieve domain configuration so we know where to place the voxet data gridorigin, gridspacing, gridNE = domain.getGridParameters() # determine base location of this dataset within the domain first=[int((origin[i]-gridorigin[i])/gridspacing[i]) for i in range(domain.getDim())] # determine the resolution difference between domain and data. # If domain has twice the resolution we can double up the data etc. multiplier=[int(round((abs(length[i])/NE[i])/gridspacing[i])) for i in range(domain.getDim())] # NOTE: Depending on your data you might have to multiply your vertical # multiplier by 1000. to convert km in meters. #multiplier[-1] = int(multiplier[-1] * v_scale * 1000.) multiplier[-1] = int(multiplier[-1] * v_scale) datatype=None propfile=None for pid in props.keys(): p=props[pid] if (isinstance(voproperty, int) and pid == voproperty) or \ (isinstance(voproperty, str) and (p[0]==voproperty or p[1]==voproperty)): datatype=p[2] name=p[1] #remove quotes which GoCAD introduces for filenames with spaces if name.startswith('"') and name.endswith('"'): name=name[1:-1] propfile=os.path.join(os.path.dirname(filename), name) print("Voxet property file: %s"%propfile) break if propfile is None or datatype is None: raise ValueError("Invalid property "+str(voproperty)) reverse=[0]*domain.getDim() if axis_uvw[-1] < 0: reverse[-1]=1 print("calling readBinaryGrid with first=%s, nValues=%s, multiplier=%s, reverse=%s"%(str(first),str(NE),str(multiplier),str(reverse))) data=readBinaryGrid(propfile, ReducedFunction(domain), shape=(), fill=fillValue, byteOrder=BYTEORDER_BIG_ENDIAN, dataType=p[2], first=first, numValues=NE, multiplier=multiplier, reverse=reverse) return data