{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# APSG tutorial - Part 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**APSG** defines several new python classes to easily manage, analyze and visualize orientation structural geology data. There are several classes to work with orientation data, namely `Vector3` for vectorial data and `Lineation`, `Foliation` for axial data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Basic usage" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**APSG** module could be imported either into own name space or into active one for easier interactive work." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:05.451471Z", "iopub.status.busy": "2026-02-06T23:36:05.451351Z", "iopub.status.idle": "2026-02-06T23:36:06.317504Z", "shell.execute_reply": "2026-02-06T23:36:06.317021Z" }, "scrolled": true }, "outputs": [], "source": [ "from apsg import *" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Basic operations with vectors in 2D and 3D\n", "Instance of vector object `Vector3` could be created by passing 3 arguments correspondig to 3 components to function `vec`:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.319191Z", "iopub.status.busy": "2026-02-06T23:36:06.319016Z", "iopub.status.idle": "2026-02-06T23:36:06.321084Z", "shell.execute_reply": "2026-02-06T23:36:06.320709Z" } }, "outputs": [], "source": [ "u = vec(1, -2, 3)\n", "v = vec(-2, 1, 1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternative ways to create vector is to pass single iterable object as list, tuple or array, or to provide geological orientation according to **APSG** notation (default is *direction of dip* and *dip angle* for planar and *trend* and *plunge* for linear features)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.322562Z", "iopub.status.busy": "2026-02-06T23:36:06.322447Z", "iopub.status.idle": "2026-02-06T23:36:06.324635Z", "shell.execute_reply": "2026-02-06T23:36:06.324271Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Vector3(-2, 2, 3) Vector3(-0.25, 0.433, 0.866)\n" ] } ], "source": [ "coords = (-2, 2, 3)\n", "a = vec(coords)\n", "b = vec(120, 60)\n", "print(a, b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The instance of 2D vector `Vector2` could be created passing 2 arguments correspondig to 2 components or single iterable with components to function `vec2`:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.347547Z", "iopub.status.busy": "2026-02-06T23:36:06.347401Z", "iopub.status.idle": "2026-02-06T23:36:06.349868Z", "shell.execute_reply": "2026-02-06T23:36:06.349417Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Vector2(1, 1) Vector2(-1, 2)\n" ] } ], "source": [ "k = vec2(1, 1)\n", "coords = (-1, 2)\n", "l = vec2(coords)\n", "print(k, l)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively, single argument is interpreted as direction in degrees (0-top, 90-right, 180-down, 270-left)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.351070Z", "iopub.status.busy": "2026-02-06T23:36:06.350955Z", "iopub.status.idle": "2026-02-06T23:36:06.354638Z", "shell.execute_reply": "2026-02-06T23:36:06.354249Z" } }, "outputs": [ { "data": { "text/plain": [ "Vector2(-2.5, 4.33)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m = 5 * vec2(120)\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For common vector operation we can use standard mathematical operators or special methods using dot notation" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.355873Z", "iopub.status.busy": "2026-02-06T23:36:06.355743Z", "iopub.status.idle": "2026-02-06T23:36:06.358034Z", "shell.execute_reply": "2026-02-06T23:36:06.357705Z" } }, "outputs": [ { "data": { "text/plain": [ "Vector3(-1, -1, 4)" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u + v" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.359380Z", "iopub.status.busy": "2026-02-06T23:36:06.359265Z", "iopub.status.idle": "2026-02-06T23:36:06.361509Z", "shell.execute_reply": "2026-02-06T23:36:06.361180Z" } }, "outputs": [ { "data": { "text/plain": [ "Vector3(3, -3, 2)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u - v" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.362772Z", "iopub.status.busy": "2026-02-06T23:36:06.362635Z", "iopub.status.idle": "2026-02-06T23:36:06.365013Z", "shell.execute_reply": "2026-02-06T23:36:06.364666Z" } }, "outputs": [ { "data": { "text/plain": [ "Vector3(7, -8, 7)" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "3*u - 2*v" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Its magnitude or length is most commonly defined as its Euclidean norm and could be calculated using `abs`" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.366390Z", "iopub.status.busy": "2026-02-06T23:36:06.366278Z", "iopub.status.idle": "2026-02-06T23:36:06.368559Z", "shell.execute_reply": "2026-02-06T23:36:06.368190Z" } }, "outputs": [ { "data": { "text/plain": [ "2.449489742783178" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "abs(v)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.369645Z", "iopub.status.busy": "2026-02-06T23:36:06.369513Z", "iopub.status.idle": "2026-02-06T23:36:06.371662Z", "shell.execute_reply": "2026-02-06T23:36:06.371388Z" } }, "outputs": [ { "data": { "text/plain": [ "4.242640687119285" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "abs(u + v)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For *dot product* we can use `dot` method or operator `@` " ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.373024Z", "iopub.status.busy": "2026-02-06T23:36:06.372875Z", "iopub.status.idle": "2026-02-06T23:36:06.375102Z", "shell.execute_reply": "2026-02-06T23:36:06.374809Z" } }, "outputs": [ { "data": { "text/plain": [ "-1" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u.dot(v)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.376456Z", "iopub.status.busy": "2026-02-06T23:36:06.376341Z", "iopub.status.idle": "2026-02-06T23:36:06.378574Z", "shell.execute_reply": "2026-02-06T23:36:06.378255Z" } }, "outputs": [ { "data": { "text/plain": [ "-1.0" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u @ v" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For *cross product* we can method `cross`" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.379875Z", "iopub.status.busy": "2026-02-06T23:36:06.379744Z", "iopub.status.idle": "2026-02-06T23:36:06.381918Z", "shell.execute_reply": "2026-02-06T23:36:06.381619Z" } }, "outputs": [ { "data": { "text/plain": [ "Vector3(-5, -7, -3)" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u.cross(v)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To project vector ``u`` onto vector ``v`` we can use method ``proj``" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.383193Z", "iopub.status.busy": "2026-02-06T23:36:06.383077Z", "iopub.status.idle": "2026-02-06T23:36:06.385360Z", "shell.execute_reply": "2026-02-06T23:36:06.385029Z" } }, "outputs": [ { "data": { "text/plain": [ "Vector3(0.333, -0.167, -0.167)" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u.proj(v)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To find angle (in degrees) between to vectors we use method ``angle``" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.386583Z", "iopub.status.busy": "2026-02-06T23:36:06.386468Z", "iopub.status.idle": "2026-02-06T23:36:06.388698Z", "shell.execute_reply": "2026-02-06T23:36:06.388381Z" } }, "outputs": [ { "data": { "text/plain": [ "96.26395271992722" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u.angle(v)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Method ``rotate`` provide possibility to rotate vector around another vector. For example, to rotate vector ``u`` around vector ``v`` for 45°" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.390085Z", "iopub.status.busy": "2026-02-06T23:36:06.389970Z", "iopub.status.idle": "2026-02-06T23:36:06.392322Z", "shell.execute_reply": "2026-02-06T23:36:06.391991Z" } }, "outputs": [ { "data": { "text/plain": [ "Vector3(2.248, 0.558, 2.939)" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "u.rotate(v, 45)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Classes Lineation and Foliation\n", "To work with orientation data in structural geology, **APSG** provide two classes, `Foliation` class to represent planar features and `Lineation` class to represent linear features. Both classes support all `Vector3` methods and operators, but it should be noted, that `dot` and `angle` respect their axial nature, i.e. angle between two lineations cant't be bigger than 90 degrees." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To create instance of `Lineation` or `Foliation`, we can use functions `lin` and `fol`. Arguments have similar syntax to `vec3`." ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.393553Z", "iopub.status.busy": "2026-02-06T23:36:06.393438Z", "iopub.status.idle": "2026-02-06T23:36:06.395906Z", "shell.execute_reply": "2026-02-06T23:36:06.395509Z" } }, "outputs": [ { "data": { "text/plain": [ "(L:120/60, S:216/62)" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lin(120, 60), fol(216, 62)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also cast `Vector3` instance to `Foliation` or `Lineation`" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.397037Z", "iopub.status.busy": "2026-02-06T23:36:06.396923Z", "iopub.status.idle": "2026-02-06T23:36:06.399211Z", "shell.execute_reply": "2026-02-06T23:36:06.398939Z" } }, "outputs": [ { "data": { "text/plain": [ "(L:297/53, S:117/37)" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lin(u), fol(u)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Vector methods for Lineation and Foliation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "To find angle between two linear or planar features we can use method `angle`" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.400546Z", "iopub.status.busy": "2026-02-06T23:36:06.400430Z", "iopub.status.idle": "2026-02-06T23:36:06.402855Z", "shell.execute_reply": "2026-02-06T23:36:06.402449Z" } }, "outputs": [ { "data": { "text/plain": [ "41.59741268003547" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l1 = lin(110, 40)\n", "l2 = lin(160, 30)\n", "l1.angle(l2)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.403969Z", "iopub.status.busy": "2026-02-06T23:36:06.403854Z", "iopub.status.idle": "2026-02-06T23:36:06.406282Z", "shell.execute_reply": "2026-02-06T23:36:06.405969Z" } }, "outputs": [ { "data": { "text/plain": [ "54.696399321975335" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p1 = fol(330, 50)\n", "p2 = fol(250, 40)\n", "p1.angle(p2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can use *cross product* to construct planar feature defined by two linear features" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.407491Z", "iopub.status.busy": "2026-02-06T23:36:06.407376Z", "iopub.status.idle": "2026-02-06T23:36:06.409583Z", "shell.execute_reply": "2026-02-06T23:36:06.409302Z" } }, "outputs": [ { "data": { "text/plain": [ "S:113/40" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l1.cross(l2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "or to construct linear feature defined by intersection of two planar features" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.410794Z", "iopub.status.busy": "2026-02-06T23:36:06.410653Z", "iopub.status.idle": "2026-02-06T23:36:06.412940Z", "shell.execute_reply": "2026-02-06T23:36:06.412574Z" } }, "outputs": [ { "data": { "text/plain": [ "L:278/36" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p1.cross(p2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Cross product* of planar and linear features could be used to construct plane defined by linear feature and normal of planar feature" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.414037Z", "iopub.status.busy": "2026-02-06T23:36:06.413920Z", "iopub.status.idle": "2026-02-06T23:36:06.416199Z", "shell.execute_reply": "2026-02-06T23:36:06.415890Z" } }, "outputs": [ { "data": { "text/plain": [ "S:96/53" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l2.cross(p2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "or to find perpendicular linear feature on given plane" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.417415Z", "iopub.status.busy": "2026-02-06T23:36:06.417297Z", "iopub.status.idle": "2026-02-06T23:36:06.419523Z", "shell.execute_reply": "2026-02-06T23:36:06.419221Z" } }, "outputs": [ { "data": { "text/plain": [ "L:276/37" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p2.cross(l2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To rotate structural features we can use method ``rotate``" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.420694Z", "iopub.status.busy": "2026-02-06T23:36:06.420577Z", "iopub.status.idle": "2026-02-06T23:36:06.422945Z", "shell.execute_reply": "2026-02-06T23:36:06.422572Z" } }, "outputs": [ { "data": { "text/plain": [ "S:269/78" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p2.rotate(l2, 45)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Classes Pair and Fault\n", "To work with paired orientation data like foliations and lineations or fault data in structural geology, **APSG** provide two base `Pair` class and derived `Fault` class. Both classes are instantiated providing dip direction and dip of planar and linear measurements, which are automatically orthogonalized. If misfit is too high, warning is raised. The `Fault` class expects one more argument providing sense of movement information, either 1 or -1 for normal/reverse movement." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To create instance of `Pair`, we have to pass two arguments for planar and two argumets for linear features following geological notation to function `pair`:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.424035Z", "iopub.status.busy": "2026-02-06T23:36:06.423919Z", "iopub.status.idle": "2026-02-06T23:36:06.426399Z", "shell.execute_reply": "2026-02-06T23:36:06.426039Z" } }, "outputs": [ { "data": { "text/plain": [ "P:118/39-163/30" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p = pair(120, 40, 162, 28)\n", "p" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.427352Z", "iopub.status.busy": "2026-02-06T23:36:06.427233Z", "iopub.status.idle": "2026-02-06T23:36:06.429371Z", "shell.execute_reply": "2026-02-06T23:36:06.429014Z" } }, "outputs": [ { "data": { "text/plain": [ "3.5623168411508175" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p.misfit" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Planar and linear features are accessible using `fol` and `lin` properties" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.430351Z", "iopub.status.busy": "2026-02-06T23:36:06.430236Z", "iopub.status.idle": "2026-02-06T23:36:06.432475Z", "shell.execute_reply": "2026-02-06T23:36:06.432101Z" } }, "outputs": [ { "data": { "text/plain": [ "(S:118/39, L:163/30)" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p.fol, p.lin" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To rotate ``Pair`` instance we can use ``rotate`` method" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.433460Z", "iopub.status.busy": "2026-02-06T23:36:06.433344Z", "iopub.status.idle": "2026-02-06T23:36:06.435978Z", "shell.execute_reply": "2026-02-06T23:36:06.435601Z" } }, "outputs": [ { "data": { "text/plain": [ "P:314/83-237/61" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p.rotate(lin(45, 10), 60)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Instantiation of ``Fault`` class is similar, we just have to provide argument to define sense of movement" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.436983Z", "iopub.status.busy": "2026-02-06T23:36:06.436867Z", "iopub.status.idle": "2026-02-06T23:36:06.439588Z", "shell.execute_reply": "2026-02-06T23:36:06.439213Z" } }, "outputs": [ { "data": { "text/plain": [ "F:120/59-110/59 N" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f = fault(120, 60, 110, 58, 1) # 1 for normal fault\n", "f" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note the change in sense of movement after ``Fault`` rotation" ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.440642Z", "iopub.status.busy": "2026-02-06T23:36:06.440525Z", "iopub.status.idle": "2026-02-06T23:36:06.443419Z", "shell.execute_reply": "2026-02-06T23:36:06.443058Z" } }, "outputs": [ { "data": { "text/plain": [ "F:312/62-340/59 R" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.rotate(lin(45, 10), 60)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For simple fault analyses ``Fault`` class also provide ``p``, ``t``, ``m`` and ``d`` properties to get PT-axes, kinematic plane and dihedra separation plane" ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.444404Z", "iopub.status.busy": "2026-02-06T23:36:06.444289Z", "iopub.status.idle": "2026-02-06T23:36:06.446743Z", "shell.execute_reply": "2026-02-06T23:36:06.446400Z" } }, "outputs": [ { "data": { "text/plain": [ "(L:315/75, L:116/14, S:27/85, S:290/31)" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.p, f.t, f.m, f.d" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Class Cone\n", "General feature type to store small or great circles as cone. It could be defined by `axis`, `secant` and `revolving angle` or by `axis` and `apical angle` The revolving angle is by default 360° defining full cone. For segments of small circles, the `revolving angle` could be different." ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.447896Z", "iopub.status.busy": "2026-02-06T23:36:06.447778Z", "iopub.status.idle": "2026-02-06T23:36:06.450119Z", "shell.execute_reply": "2026-02-06T23:36:06.449782Z" } }, "outputs": [ { "data": { "text/plain": [ "C:140/50 [25]" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c = cone(lin(140, 50), lin(140, 75))\n", "c" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To create small circle segment, you can provide `revolving angle`" ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.451152Z", "iopub.status.busy": "2026-02-06T23:36:06.451033Z", "iopub.status.idle": "2026-02-06T23:36:06.452822Z", "shell.execute_reply": "2026-02-06T23:36:06.452484Z" } }, "outputs": [], "source": [ "c = cone(lin(90, 70), lin(45,30), 115)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The tips of small circle segments could be obtained from cone property `secant` and `rotated_secant`" ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.453905Z", "iopub.status.busy": "2026-02-06T23:36:06.453787Z", "iopub.status.idle": "2026-02-06T23:36:06.456100Z", "shell.execute_reply": "2026-02-06T23:36:06.455731Z" } }, "outputs": [ { "data": { "text/plain": [ "(L:45/30, L:137/30)" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lin(c.secant), lin(c.rotated_secant)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To define cone using `apical angle`, use `axis` amd number arguments. Note, that `revolving angle` is 360 by default" ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.457173Z", "iopub.status.busy": "2026-02-06T23:36:06.457049Z", "iopub.status.idle": "2026-02-06T23:36:06.459462Z", "shell.execute_reply": "2026-02-06T23:36:06.459082Z" } }, "outputs": [ { "data": { "text/plain": [ "C:140/50 [25]" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c = cone(lin(140, 50), 25)\n", "c" ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.460475Z", "iopub.status.busy": "2026-02-06T23:36:06.460355Z", "iopub.status.idle": "2026-02-06T23:36:06.462490Z", "shell.execute_reply": "2026-02-06T23:36:06.462142Z" } }, "outputs": [ { "data": { "text/plain": [ "360.0" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.revangle" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Feature sets\n", "*APSG* provide several classes to process, analyze and visualize the sets of data. There are e.g. `vecset`, `linset` and `folset` classes to store group of `vec`, `lin` and `fol` objects. All these feature sets are created from homogeneous list of data with optional `name` atribute." ] }, { "cell_type": "code", "execution_count": 38, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.463579Z", "iopub.status.busy": "2026-02-06T23:36:06.463462Z", "iopub.status.idle": "2026-02-06T23:36:06.465967Z", "shell.execute_reply": "2026-02-06T23:36:06.465592Z" } }, "outputs": [ { "data": { "text/plain": [ "V3(5) Vectors" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v = vecset([vec(120,60), vec(116,50), vec(132,45), vec(90,60), vec(84,52)], name='Vectors')\n", "v" ] }, { "cell_type": "code", "execution_count": 39, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.467006Z", "iopub.status.busy": "2026-02-06T23:36:06.466889Z", "iopub.status.idle": "2026-02-06T23:36:06.469292Z", "shell.execute_reply": "2026-02-06T23:36:06.468925Z" } }, "outputs": [ { "data": { "text/plain": [ "L(5) Lineations" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l = linset([lin(120,60), lin(116,50), lin(132,45), lin(90,60), lin(84,52)], name='Lineations')\n", "l" ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.470380Z", "iopub.status.busy": "2026-02-06T23:36:06.470265Z", "iopub.status.idle": "2026-02-06T23:36:06.472698Z", "shell.execute_reply": "2026-02-06T23:36:06.472308Z" } }, "outputs": [ { "data": { "text/plain": [ "S(5) Foliations" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f = folset([fol(120,60), fol(116,50), fol(132,45), fol(90,60), fol(84,52)], name='Foliations')\n", "f" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To simplify interactive group creation, you can use function ``G``" ] }, { "cell_type": "code", "execution_count": 41, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.473762Z", "iopub.status.busy": "2026-02-06T23:36:06.473635Z", "iopub.status.idle": "2026-02-06T23:36:06.476081Z", "shell.execute_reply": "2026-02-06T23:36:06.475741Z" } }, "outputs": [ { "data": { "text/plain": [ "L(5) L1" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g = G([lin(120,60), lin(116,50), lin(132,45), lin(90,60), lin(84,52)], name='L1')\n", "g" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Method ``len`` returns number of features in group" ] }, { "cell_type": "code", "execution_count": 42, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.477278Z", "iopub.status.busy": "2026-02-06T23:36:06.477159Z", "iopub.status.idle": "2026-02-06T23:36:06.479344Z", "shell.execute_reply": "2026-02-06T23:36:06.478956Z" } }, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(v)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Most of the `vec`, `lin` and `fol` methods could be used for feature sets as well. For example, to measure angles between all features in group and another feature, we can use method `angle`:" ] }, { "cell_type": "code", "execution_count": 43, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.480389Z", "iopub.status.busy": "2026-02-06T23:36:06.480272Z", "iopub.status.idle": "2026-02-06T23:36:06.482827Z", "shell.execute_reply": "2026-02-06T23:36:06.482423Z" } }, "outputs": [ { "data": { "text/plain": [ "array([11.49989817, 3.85569115, 15.61367789, 15.11039885, 16.3947936 ])" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.angle(lin(110,50))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To rotate all features in group around another feature, we can use method ``rotate``" ] }, { "cell_type": "code", "execution_count": 44, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.483855Z", "iopub.status.busy": "2026-02-06T23:36:06.483738Z", "iopub.status.idle": "2026-02-06T23:36:06.485822Z", "shell.execute_reply": "2026-02-06T23:36:06.485525Z" } }, "outputs": [], "source": [ "lr = l.rotate(lin(150, 30), 45)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To show data in list you can use ``data`` property" ] }, { "cell_type": "code", "execution_count": 45, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.487086Z", "iopub.status.busy": "2026-02-06T23:36:06.486967Z", "iopub.status.idle": "2026-02-06T23:36:06.489271Z", "shell.execute_reply": "2026-02-06T23:36:06.488900Z" } }, "outputs": [ { "data": { "text/plain": [ "(L:120/60, L:116/50, L:132/45, L:90/60, L:84/52)" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.data" ] }, { "cell_type": "code", "execution_count": 46, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.490308Z", "iopub.status.busy": "2026-02-06T23:36:06.490191Z", "iopub.status.idle": "2026-02-06T23:36:06.492418Z", "shell.execute_reply": "2026-02-06T23:36:06.492070Z" } }, "outputs": [ { "data": { "text/plain": [ "(L:107/35, L:113/26, L:126/30, L:93/26, L:94/18)" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lr.data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Function `R` returns resultant of all features in set. Note that `Lineation` and `Foliation` are axial in nature, so resultant vector is not reliable. Check the orientation tensor anlysis below." ] }, { "cell_type": "code", "execution_count": 47, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.493553Z", "iopub.status.busy": "2026-02-06T23:36:06.493435Z", "iopub.status.idle": "2026-02-06T23:36:06.495669Z", "shell.execute_reply": "2026-02-06T23:36:06.495318Z" } }, "outputs": [ { "data": { "text/plain": [ "Vector3(-0.941, 2.649, 3.993)" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.R()" ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.496772Z", "iopub.status.busy": "2026-02-06T23:36:06.496646Z", "iopub.status.idle": "2026-02-06T23:36:06.498985Z", "shell.execute_reply": "2026-02-06T23:36:06.498577Z" } }, "outputs": [ { "data": { "text/plain": [ "L:110/55" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lin(v.R())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There is several methods to infer spherical statistics as spherical variance, Fisher's statistics, confidence cones on data etc." ] }, { "cell_type": "code", "execution_count": 49, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.500026Z", "iopub.status.busy": "2026-02-06T23:36:06.499908Z", "iopub.status.idle": "2026-02-06T23:36:06.502223Z", "shell.execute_reply": "2026-02-06T23:36:06.501837Z" } }, "outputs": [ { "data": { "text/plain": [ "0.02337168447438498" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l.var()" ] }, { "cell_type": "code", "execution_count": 50, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.503229Z", "iopub.status.busy": "2026-02-06T23:36:06.503112Z", "iopub.status.idle": "2026-02-06T23:36:06.505452Z", "shell.execute_reply": "2026-02-06T23:36:06.505068Z" } }, "outputs": [ { "data": { "text/plain": [ "{'k': 34.22945405911087,\n", " 'a95': 13.26402990511733,\n", " 'csd': np.float64(13.844747281750971)}" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.fisher_statistics()" ] }, { "cell_type": "code", "execution_count": 51, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.506452Z", "iopub.status.busy": "2026-02-06T23:36:06.506334Z", "iopub.status.idle": "2026-02-06T23:36:06.508763Z", "shell.execute_reply": "2026-02-06T23:36:06.508381Z" } }, "outputs": [ { "data": { "text/plain": [ "C:110/55 [13.264]" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.fisher_cone_a95()" ] }, { "cell_type": "code", "execution_count": 52, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.509776Z", "iopub.status.busy": "2026-02-06T23:36:06.509653Z", "iopub.status.idle": "2026-02-06T23:36:06.512093Z", "shell.execute_reply": "2026-02-06T23:36:06.511738Z" } }, "outputs": [ { "data": { "text/plain": [ "C:110/55 [13.8447]" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.fisher_cone_csd()" ] }, { "cell_type": "code", "execution_count": 53, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.513199Z", "iopub.status.busy": "2026-02-06T23:36:06.513080Z", "iopub.status.idle": "2026-02-06T23:36:06.515396Z", "shell.execute_reply": "2026-02-06T23:36:06.515050Z" } }, "outputs": [ { "data": { "text/plain": [ "12.411724720740516" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.delta()" ] }, { "cell_type": "code", "execution_count": 54, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.516616Z", "iopub.status.busy": "2026-02-06T23:36:06.516496Z", "iopub.status.idle": "2026-02-06T23:36:06.518654Z", "shell.execute_reply": "2026-02-06T23:36:06.518370Z" } }, "outputs": [ { "data": { "text/plain": [ "95.32566310512297" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.rdegree()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To calculate orientation tensor of all features in group, we can use `ortensor` method." ] }, { "cell_type": "code", "execution_count": 55, "metadata": { "execution": { "iopub.execute_input": "2026-02-06T23:36:06.519920Z", "iopub.status.busy": "2026-02-06T23:36:06.519801Z", "iopub.status.idle": "2026-02-06T23:36:06.522440Z", "shell.execute_reply": "2026-02-06T23:36:06.522025Z" } }, "outputs": [ { "data": { "text/plain": [ "OrientationTensor3\n", "[[ 0.074 -0.096 -0.143]\n", " [-0.096 0.284 0.421]\n", " [-0.143 0.421 0.642]]\n", "(S1:0.977, S2:0.201, S3:0.0758)" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.ortensor()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.3" } }, "nbformat": 4, "nbformat_minor": 4 }