
"""simple docstring"""




import argparse
import pathlib
from pathlib import Path
from tempfile import TemporaryDirectory

import esm as esm_module
import torch
from esm.esmfold.va.misc import batch_encode_sequences as esmfold_encode_sequences
from esm.esmfold.va.pretrained import esmfold_va

from transformers.models.esm.configuration_esm import EsmConfig, EsmFoldConfig
from transformers.models.esm.modeling_esm import (
    EsmForMaskedLM,
    EsmForSequenceClassification,
    EsmIntermediate,
    EsmLayer,
    EsmOutput,
    EsmSelfAttention,
    EsmSelfOutput,
)
from transformers.models.esm.modeling_esmfold import EsmForProteinFolding
from transformers.models.esm.tokenization_esm import EsmTokenizer
from transformers.utils import logging


logging.set_verbosity_info()
snake_case					  =						logging.get_logger(__name__)

snake_case					  =						[
    (
        'protein1',
        'MNGTEGPNFYVPFSNATGVVRSPFEYPQYYLAEPWQFSMLAAYMFLLIVLGFPINFLTLYVTVQHKKLRTPLNYILLNLAVADLFMVLGGFTSTLYTSLHGYFVFGPTGCNLEGFFATLGGEIALWSLVVLAIERYVVVCKPMSNFRFGENHAIMGVAFTWVMALACAAPPLAGWSRYIPEGLQCSCGIDYYTLKPEVNNESFVIYMFVVHFTIPMIIIFFCYGQLVFTVKEAAAQQQESATTQKAEKEVTRMVIIMVIAFLICWVPYASVAFYIFTHQGSNFGPIFMTIPAFFAKSAAIYNPVIYIMMNKQFRNCMLTTICCGKNPLGDDEASATVSKTETSQVAPA',
    ),
    ('protein2', 'MKTVRQERLKSIVRILERSKEPVSGAQLAEELSVSRQVIVQDIAYLRSLGYNIVATPRGYVLA'),
    ('protein3', 'MKTVRQERLKSI<mask>RILERSKEPVSGAQLAEELS<mask>SRQVIVQDIAYLRSLGYN<mask>VATPRGYVLAGG'),
    ('protein4', 'MKTVRQERLKSI<mask>RILERSKEPVSGAQLAEELS<mask>SRQVIVQDIAYLRSLGYN<mask>VATPRGYVLA'),
]

snake_case					  =						{
    'esm1b_t33_650M_UR50S': esm_module.pretrained.esm1b_t33_650M_UR50S,
    'esm1v_t33_650M_UR90S_1': esm_module.pretrained.esm1v_t33_650M_UR90S_1,
    'esm1v_t33_650M_UR90S_2': esm_module.pretrained.esm1v_t33_650M_UR90S_2,
    'esm1v_t33_650M_UR90S_3': esm_module.pretrained.esm1v_t33_650M_UR90S_3,
    'esm1v_t33_650M_UR90S_4': esm_module.pretrained.esm1v_t33_650M_UR90S_4,
    'esm1v_t33_650M_UR90S_5': esm_module.pretrained.esm1v_t33_650M_UR90S_5,
    'esm2_t48_15B_UR50D': esm_module.pretrained.esm2_t48_15B_UR50D,
    'esm2_t36_3B_UR50D': esm_module.pretrained.esm2_t36_3B_UR50D,
    'esm2_t33_650M_UR50D': esm_module.pretrained.esm2_t33_650M_UR50D,
    'esm2_t30_150M_UR50D': esm_module.pretrained.esm2_t30_150M_UR50D,
    'esm2_t12_35M_UR50D': esm_module.pretrained.esm2_t12_35M_UR50D,
    'esm2_t6_8M_UR50D': esm_module.pretrained.esm2_t6_8M_UR50D,
    'esmfold_v1': esmfold_va,
}

snake_case					  =						list('ARNDCQEGHILKMFPSTWYV')

snake_case					  =						restypes + ['X']
snake_case					  =						restypes_with_x + ['<pad>', '<mask>', '<cls>', '<sep>', '<eos>']

def     UpperCamelCase_    (						):
					with TemporaryDirectory() as tempdir:
										SCREAMING_SNAKE_CASE           =      '\n'.join(SCREAMING_SNAKE_CASE_     )
										SCREAMING_SNAKE_CASE           =      Path(SCREAMING_SNAKE_CASE_     ) / 'vocab.txt'
										vocab_file.write_text(SCREAMING_SNAKE_CASE_     )
										SCREAMING_SNAKE_CASE           =      EsmTokenizer(vocab_file=str(SCREAMING_SNAKE_CASE_     )     )
					SCREAMING_SNAKE_CASE           =      0  # Overlaps with 'A' but that seems to be what they want
					return hf_tokenizer

def     UpperCamelCase_    (						SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     ):
					SCREAMING_SNAKE_CASE           =      our_module.load_state_dict(original_module.state_dict()     )
					if status.missing_keys:
										raise ValueError(f'''Missing keys: {status.missing_keys}'''     )
					if status.unexpected_keys:
										raise ValueError(f'''Unexpected keys: {status.unexpected_keys}'''     )

def     UpperCamelCase_    (						SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     ):
					if model.startswith('esmfold'     ):
										SCREAMING_SNAKE_CASE           =      MODEL_MAPPING[model]()
					else:
										SCREAMING_SNAKE_CASE      ,       SCREAMING_SNAKE_CASE           =      MODEL_MAPPING[model]()
					esm.eval()  # disable dropout

					if model.startswith('esmfold'     ):
										SCREAMING_SNAKE_CASE           =      esm.esm.embed_dim
										SCREAMING_SNAKE_CASE           =      esm.esm.num_layers
										SCREAMING_SNAKE_CASE           =      esm.esm.attention_heads
										SCREAMING_SNAKE_CASE           =      4 * embed_dim
										SCREAMING_SNAKE_CASE           =      esm.esm.token_dropout
										SCREAMING_SNAKE_CASE           =      False  # This code path does not exist in ESM-2
										SCREAMING_SNAKE_CASE           =      'rotary'
										SCREAMING_SNAKE_CASE           =      True
										SCREAMING_SNAKE_CASE           =      EsmFoldConfig()
										for key, val in esm.cfg.items():
															if hasattr(SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     ) and key != "trunk":
																				setattr(SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     )
										for key, val in esm.cfg.trunk.items():
															if hasattr(esmfold_config.trunk,	SCREAMING_SNAKE_CASE_     ) and key != "structure_module":
																				setattr(esmfold_config.trunk,	SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     )
										for key, val in esm.cfg.trunk.structure_module.items():
															if hasattr(esmfold_config.trunk.structure_module,	SCREAMING_SNAKE_CASE_     ):
																				setattr(esmfold_config.trunk.structure_module,	SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     )
					elif hasattr(SCREAMING_SNAKE_CASE_,	'args'     ):
										# Indicates an ESM-1b or ESM-1v model
										SCREAMING_SNAKE_CASE           =      esm.args.embed_dim
										SCREAMING_SNAKE_CASE           =      esm.args.layers
										SCREAMING_SNAKE_CASE           =      esm.args.attention_heads
										SCREAMING_SNAKE_CASE           =      esm.args.ffn_embed_dim
										SCREAMING_SNAKE_CASE           =      esm.args.token_dropout
										SCREAMING_SNAKE_CASE           =      True if esm.emb_layer_norm_before else False
										SCREAMING_SNAKE_CASE           =      'absolute'
										SCREAMING_SNAKE_CASE           =      False
										SCREAMING_SNAKE_CASE           =      None
					else:
										# Indicates an ESM-2 model
										SCREAMING_SNAKE_CASE           =      esm.embed_dim
										SCREAMING_SNAKE_CASE           =      esm.num_layers
										SCREAMING_SNAKE_CASE           =      esm.attention_heads
										SCREAMING_SNAKE_CASE           =      4 * embed_dim  # This is hardcoded in ESM-2
										SCREAMING_SNAKE_CASE           =      esm.token_dropout
										SCREAMING_SNAKE_CASE           =      False  # This code path does not exist in ESM-2
										SCREAMING_SNAKE_CASE           =      'rotary'
										SCREAMING_SNAKE_CASE           =      False
										SCREAMING_SNAKE_CASE           =      None

					if is_folding_model:
										SCREAMING_SNAKE_CASE           =      esm.esm.alphabet
					SCREAMING_SNAKE_CASE           =      tuple(alphabet.all_toks     )
					SCREAMING_SNAKE_CASE           =      alphabet.mask_idx
					SCREAMING_SNAKE_CASE           =      alphabet.padding_idx

					if is_folding_model:
										SCREAMING_SNAKE_CASE           =      esm.esm
					else:
										SCREAMING_SNAKE_CASE           =      esm

					SCREAMING_SNAKE_CASE           =      EsmConfig(
					    vocab_size=original_esm_model.embed_tokens.num_embeddings,	mask_token_id=SCREAMING_SNAKE_CASE_,	hidden_size=SCREAMING_SNAKE_CASE_,	num_hidden_layers=SCREAMING_SNAKE_CASE_,	num_attention_heads=SCREAMING_SNAKE_CASE_,	intermediate_size=SCREAMING_SNAKE_CASE_,	max_position_embeddings=1_0_2_6,	layer_norm_eps=1E-5,	attention_probs_dropout_prob=0.0,	hidden_dropout_prob=0.0,	pad_token_id=SCREAMING_SNAKE_CASE_,	emb_layer_norm_before=SCREAMING_SNAKE_CASE_,	token_dropout=SCREAMING_SNAKE_CASE_,	position_embedding_type=SCREAMING_SNAKE_CASE_,	is_folding_model=SCREAMING_SNAKE_CASE_,	esmfold_config=SCREAMING_SNAKE_CASE_,	vocab_list=SCREAMING_SNAKE_CASE_,	)
					if classification_head:
										SCREAMING_SNAKE_CASE           =      esm.classification_heads['mnli'].out_proj.weight.shape[0]
					print('Our ESM config:',	SCREAMING_SNAKE_CASE_     )

					if model.startswith('esmfold'     ):
										SCREAMING_SNAKE_CASE           =      EsmForProteinFolding
					elif classification_head:
										SCREAMING_SNAKE_CASE           =      EsmForSequenceClassification
					else:
										SCREAMING_SNAKE_CASE           =      EsmForMaskedLM
					SCREAMING_SNAKE_CASE           =      model_class(SCREAMING_SNAKE_CASE_     )
					model.eval()

					# Now let's copy all the weights.
					# Embeddings
					SCREAMING_SNAKE_CASE           =      original_esm_model.embed_tokens.weight
					if position_embedding_type == "absolute":
										SCREAMING_SNAKE_CASE           =      original_esm_model.embed_positions.weight

					if config.emb_layer_norm_before:
										SCREAMING_SNAKE_CASE           =      original_esm_model.emb_layer_norm_before.weight
										SCREAMING_SNAKE_CASE           =      original_esm_model.emb_layer_norm_before.bias

					SCREAMING_SNAKE_CASE           =      original_esm_model.emb_layer_norm_after.weight
					SCREAMING_SNAKE_CASE           =      original_esm_model.emb_layer_norm_after.bias

					for i in range(config.num_hidden_layers     ):
										# Encoder: start of layer
										SCREAMING_SNAKE_CASE           =      model.esm.encoder.layer[i]
										# esm_layer: TransformerSentenceEncoderLayer = original_esm_model.layers[i]
										SCREAMING_SNAKE_CASE           =      original_esm_model.layers[i]

										# self attention
										SCREAMING_SNAKE_CASE           =      layer.attention.self
										assert (
										    esm_layer.self_attn.k_proj.weight.data.shape
										    == esm_layer.self_attn.q_proj.weight.data.shape
										    == esm_layer.self_attn.v_proj.weight.data.shape
										    == torch.Size((config.hidden_size, config.hidden_size)     )
										)

										SCREAMING_SNAKE_CASE           =      esm_layer.self_attn.q_proj.weight
										SCREAMING_SNAKE_CASE           =      esm_layer.self_attn.q_proj.bias
										SCREAMING_SNAKE_CASE           =      esm_layer.self_attn.k_proj.weight
										SCREAMING_SNAKE_CASE           =      esm_layer.self_attn.k_proj.bias
										SCREAMING_SNAKE_CASE           =      esm_layer.self_attn.v_proj.weight
										SCREAMING_SNAKE_CASE           =      esm_layer.self_attn.v_proj.bias

										if getattr(esm_layer.self_attn,	'rot_emb',	SCREAMING_SNAKE_CASE_     ) is not None:
															# Matt: Although inv_freq is not a trainable weight, it is computed at model init and cached.
															# During the training of ESM-2 the model was converted to float16 precision, which also converts
															# the inv_freq tensor, and the loss of precision remains even if the model is loaded later as float32.
															# If we recompute inv_freq without this loss of precision then we will get subtly different rotary
															# embeddings, which are enough to cause significant discrepancies in model outputs. To avoid this,
															# we make sure the new model copies the data from the old inv_freq.
															SCREAMING_SNAKE_CASE           =      esm_layer.self_attn.rot_emb.inv_freq

										# LayerNorm changes for pre-activation
										SCREAMING_SNAKE_CASE           =      esm_layer.self_attn_layer_norm.weight
										SCREAMING_SNAKE_CASE           =      esm_layer.self_attn_layer_norm.bias
										SCREAMING_SNAKE_CASE           =      esm_layer.final_layer_norm.weight
										SCREAMING_SNAKE_CASE           =      esm_layer.final_layer_norm.bias

										# self-attention output
										SCREAMING_SNAKE_CASE           =      layer.attention.output
										assert self_output.dense.weight.shape == esm_layer.self_attn.out_proj.weight.shape
										SCREAMING_SNAKE_CASE           =      esm_layer.self_attn.out_proj.weight
										SCREAMING_SNAKE_CASE           =      esm_layer.self_attn.out_proj.bias

										# intermediate
										SCREAMING_SNAKE_CASE           =      layer.intermediate
										assert intermediate.dense.weight.shape == esm_layer.fca.weight.shape
										SCREAMING_SNAKE_CASE           =      esm_layer.fca.weight
										SCREAMING_SNAKE_CASE           =      esm_layer.fca.bias

										# output
										SCREAMING_SNAKE_CASE           =      layer.output
										assert bert_output.dense.weight.shape == esm_layer.fca.weight.shape
										SCREAMING_SNAKE_CASE           =      esm_layer.fca.weight
										SCREAMING_SNAKE_CASE           =      esm_layer.fca.bias
										# end of layer

					if is_folding_model:
										SCREAMING_SNAKE_CASE           =      esm.esm_s_combine.data
										SCREAMING_SNAKE_CASE           =      esm.afa_to_esm.data
										transfer_and_check_weights(esm.embedding,	model.embedding     )
										transfer_and_check_weights(esm.esm_s_mlp,	model.esm_s_mlp     )
										transfer_and_check_weights(esm.trunk,	model.trunk     )
										transfer_and_check_weights(esm.distogram_head,	model.distogram_head     )
										transfer_and_check_weights(esm.ptm_head,	model.ptm_head     )
										transfer_and_check_weights(esm.lm_head,	model.lm_head     )
										transfer_and_check_weights(esm.lddt_head,	model.lddt_head     )

					elif classification_head:
										SCREAMING_SNAKE_CASE           =      esm.esm.classification_heads['mnli'].dense.weight
										SCREAMING_SNAKE_CASE           =      esm.classification_heads['mnli'].dense.bias
										SCREAMING_SNAKE_CASE           =      esm.classification_heads['mnli'].out_proj.weight
										SCREAMING_SNAKE_CASE           =      esm.classification_heads['mnli'].out_proj.bias
					else:
										# LM Head
										SCREAMING_SNAKE_CASE           =      esm.lm_head.dense.weight
										SCREAMING_SNAKE_CASE           =      esm.lm_head.dense.bias
										SCREAMING_SNAKE_CASE           =      esm.lm_head.layer_norm.weight
										SCREAMING_SNAKE_CASE           =      esm.lm_head.layer_norm.bias
										SCREAMING_SNAKE_CASE           =      esm.lm_head.weight
										SCREAMING_SNAKE_CASE           =      esm.lm_head.bias

					# Contact prediction head
					transfer_and_check_weights(esm.contact_head,	model.esm.contact_head     )

					# Prepare data (first 2 sequences from ESMStructuralSplitDataset superfamily / 4)
					if is_folding_model:
										# Folding models aren't trained on masked inputs and don't like mask tokens.
										SCREAMING_SNAKE_CASE           =      SAMPLE_DATA[:2]
					else:
										SCREAMING_SNAKE_CASE           =      SAMPLE_DATA

					if is_folding_model:
										SCREAMING_SNAKE_CASE           =      get_esmfold_tokenizer()
										SCREAMING_SNAKE_CASE           =      hf_tokenizer(
										    [row[1] for row in sample_data],	return_tensors='pt',	padding=SCREAMING_SNAKE_CASE_,	add_special_tokens=SCREAMING_SNAKE_CASE_     )
										SCREAMING_SNAKE_CASE      ,       SCREAMING_SNAKE_CASE      ,       SCREAMING_SNAKE_CASE      ,       SCREAMING_SNAKE_CASE      ,       SCREAMING_SNAKE_CASE           =      esmfold_encode_sequences([row[1] for row in sample_data]     )
										SCREAMING_SNAKE_CASE           =      torch.all(hf_tokens['input_ids'] == esmfold_aas     ) and torch.all(
										    hf_tokens['attention_mask'] == esmfold_mask     )
					else:
										# Let's check that we get the same results.
										SCREAMING_SNAKE_CASE           =      alphabet.get_batch_converter()
										SCREAMING_SNAKE_CASE      ,       SCREAMING_SNAKE_CASE      ,       SCREAMING_SNAKE_CASE           =      batch_converter(SCREAMING_SNAKE_CASE_     )
										# Prepare tokenizer and make sure it matches
										with TemporaryDirectory() as tempdir:
															SCREAMING_SNAKE_CASE           =      '\n'.join(alphabet.all_toks     )
															SCREAMING_SNAKE_CASE           =      Path(SCREAMING_SNAKE_CASE_     ) / 'vocab.txt'
															vocab_file.write_text(SCREAMING_SNAKE_CASE_     )
															SCREAMING_SNAKE_CASE           =      EsmTokenizer(vocab_file=str(SCREAMING_SNAKE_CASE_     )     )

										SCREAMING_SNAKE_CASE           =      hf_tokenizer([row[1] for row in sample_data],	return_tensors='pt',	padding=SCREAMING_SNAKE_CASE_     )
										SCREAMING_SNAKE_CASE           =      torch.all(hf_tokens['input_ids'] == batch_tokens     )

					print('Do both models tokenizers output the same tokens?',	'🔥' if success else '💩'     )
					if not success:
										raise Exception('Tokenization does not match!'     )

					with torch.no_grad():
										if is_folding_model:
															# Let's test the model in parts
															# ESMFold always converts the ESM stem to float16, which requires float16 ops
															# that don't exist on CPU. Therefore, to test it we need to run it on GPU. However,
															# ESMFold is what we in the community call a "big boy" and so we desperately avoid putting both the
															# original and the converted model on the GPU at the same time.
															SCREAMING_SNAKE_CASE           =      esm.cuda().infer([row[1] for row in sample_data]     )
															SCREAMING_SNAKE_CASE           =      model.cuda()(
															    input_ids=hf_tokens['input_ids'].cuda(),	attention_mask=hf_tokens['attention_mask'].cuda()     )
										else:
															SCREAMING_SNAKE_CASE           =      model(**SCREAMING_SNAKE_CASE_,	output_hidden_states=SCREAMING_SNAKE_CASE_     )
															SCREAMING_SNAKE_CASE           =      our_output['logits']
															if classification_head:
																				SCREAMING_SNAKE_CASE           =      esm.model.classification_heads['mnli'](esm.extract_features(SCREAMING_SNAKE_CASE_     )     )
															else:
																				SCREAMING_SNAKE_CASE           =      esm(hf_tokens['input_ids'],	repr_layers=list(range(9_9_9     )     )     )
																				SCREAMING_SNAKE_CASE           =      their_output['logits']

										if is_folding_model:
															SCREAMING_SNAKE_CASE           =      torch.max(torch.abs(our_output['positions'] - their_output['positions']     )     ).item()
															SCREAMING_SNAKE_CASE           =      torch.allclose(our_output['positions'],	their_output['positions'],	atol=1E-5     )
										else:
															SCREAMING_SNAKE_CASE           =      torch.max(torch.abs(our_output - their_output     )     ).item()
															SCREAMING_SNAKE_CASE           =      torch.allclose(SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_,	atol=1E-5     )

										print(f'''max_absolute_diff = {max_absolute_diff}'''     )  # ~ 1e-5
										print('Do both models output the same tensors?',	'🔥' if success else '💩'     )

										if not success:
															raise Exception('Something went wRoNg'     )

										if not is_folding_model:
															# Let's check contact prediction too
															SCREAMING_SNAKE_CASE           =      model.predict_contacts(hf_tokens['input_ids'],	hf_tokens['attention_mask']     )
															SCREAMING_SNAKE_CASE           =      esm.predict_contacts(hf_tokens['input_ids']     )
															SCREAMING_SNAKE_CASE           =      torch.max(torch.abs(our_output - their_output     )     ).item()
															SCREAMING_SNAKE_CASE           =      torch.allclose(SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_,	atol=1E-5     )

															print('Contact prediction testing:'     )
															print(f'''max_absolute_diff = {max_absolute_diff}'''     )  # ~ 1e-5
															print('Do both models output the same tensors?',	'🔥' if success else '💩'     )

															if not success:
																				raise Exception('Something went wRoNg'     )

										pathlib.Path(SCREAMING_SNAKE_CASE_     ).mkdir(parents=SCREAMING_SNAKE_CASE_,	exist_ok=SCREAMING_SNAKE_CASE_     )
										print(f'''Saving model to {pytorch_dump_folder_path}'''     )
										model.save_pretrained(SCREAMING_SNAKE_CASE_     )

										del esm  # Free up some memory before continuing

					print(f'''Saving tokenizer to {pytorch_dump_folder_path}'''     )
					hf_tokenizer.save_pretrained(SCREAMING_SNAKE_CASE_     )

					if push_to_repo:
										model.push_to_hub(repo_id=SCREAMING_SNAKE_CASE_,	use_auth_token=SCREAMING_SNAKE_CASE_     )
										hf_tokenizer.push_to_hub(repo_id=SCREAMING_SNAKE_CASE_,	use_auth_token=SCREAMING_SNAKE_CASE_     )


if __name__ == "__main__":
	snake_case					  =						argparse.ArgumentParser()
	# Required parameters
	parser.add_argument(
	    '--pytorch_dump_folder_path', type=str, required=True, help='Path to the output PyTorch model.'
	)
	parser.add_argument(
	    '--classification_head', action='store_true', help='Whether to convert a final classification head.'
	)
	parser.add_argument('--model', default=None, type=str, required=True, help='Name of model to convert.')
	parser.add_argument('--push_to_repo', type=str, help='Repo to upload to (including username!).')
	parser.add_argument('--auth_token', type=str, help='HuggingFace auth token.')
	snake_case					  =						parser.parse_args()
	convert_esm_checkpoint_to_pytorch(
	    args.model, args.pytorch_dump_folder_path, args.classification_head, args.push_to_repo, args.auth_token
	)


"""simple docstring"""




from __future__ import annotations

from math import pi, pow

def     UpperCamelCase_    (						SCREAMING_SNAKE_CASE_     ):
					if side_length < 0:
										raise ValueError('vol_cube() only accepts non-negative values'     )
					return pow(SCREAMING_SNAKE_CASE_,	3     )

def     UpperCamelCase_    (						SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     ):
					if height < 0 or radius < 0:
										raise ValueError('vol_spherical_cap() only accepts non-negative values'     )
					# Volume is 1/3 pi * height squared * (3 * radius - height)
					return 1 / 3 * pi * pow(SCREAMING_SNAKE_CASE_,	2     ) * (3 * radius - height)

def     UpperCamelCase_    (						SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     ):
					if radius_a < 0 or radius_a < 0 or centers_distance < 0:
										raise ValueError('vol_spheres_intersect() only accepts non-negative values'     )
					if centers_distance == 0:
										return vol_sphere(min(SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     )     )

					SCREAMING_SNAKE_CASE           =      (
					    (radius_a - radius_a + centers_distance)
					    * (radius_a + radius_a - centers_distance)
					    / (2 * centers_distance)
					)
					SCREAMING_SNAKE_CASE           =      (
					    (radius_a - radius_a + centers_distance)
					    * (radius_a + radius_a - centers_distance)
					    / (2 * centers_distance)
					)

					return vol_spherical_cap(SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     ) + vol_spherical_cap(SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     )

def     UpperCamelCase_    (						SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     ):

					if radius_a <= 0 or radius_a <= 0 or centers_distance < 0:
										raise ValueError(
										    'vol_spheres_union() only accepts non-negative values, non-zero radius'     )

					if centers_distance == 0:
										return vol_sphere(max(SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     )     )

					return (
					    vol_sphere(SCREAMING_SNAKE_CASE_     )
					    + vol_sphere(SCREAMING_SNAKE_CASE_     )
					    - vol_spheres_intersect(SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     )
					)

def     UpperCamelCase_    (						SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     ):
					if width < 0 or height < 0 or length < 0:
										raise ValueError('vol_cuboid() only accepts non-negative values'     )
					return float(width * height * length     )

def     UpperCamelCase_    (						SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     ):
					if height < 0 or area_of_base < 0:
										raise ValueError('vol_cone() only accepts non-negative values'     )
					return area_of_base * height / 3.0

def     UpperCamelCase_    (						SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     ):
					if height < 0 or radius < 0:
										raise ValueError('vol_right_circ_cone() only accepts non-negative values'     )
					return pi * pow(SCREAMING_SNAKE_CASE_,	2     ) * height / 3.0

def     UpperCamelCase_    (						SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     ):
					if height < 0 or area_of_base < 0:
										raise ValueError('vol_prism() only accepts non-negative values'     )
					return float(area_of_base * height     )

def     UpperCamelCase_    (						SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     ):
					if height < 0 or area_of_base < 0:
										raise ValueError('vol_pyramid() only accepts non-negative values'     )
					return area_of_base * height / 3.0

def     UpperCamelCase_    (						SCREAMING_SNAKE_CASE_     ):
					if radius < 0:
										raise ValueError('vol_sphere() only accepts non-negative values'     )
					# Volume is 4/3 * pi * radius cubed
					return 4 / 3 * pi * pow(SCREAMING_SNAKE_CASE_,	3     )

def     UpperCamelCase_    (						SCREAMING_SNAKE_CASE_     ):
					if radius < 0:
										raise ValueError('vol_hemisphere() only accepts non-negative values'     )
					# Volume is radius cubed * pi * 2/3
					return pow(SCREAMING_SNAKE_CASE_,	3     ) * pi * 2 / 3

def     UpperCamelCase_    (						SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     ):
					if height < 0 or radius < 0:
										raise ValueError('vol_circular_cylinder() only accepts non-negative values'     )
					# Volume is radius squared * height * pi
					return pow(SCREAMING_SNAKE_CASE_,	2     ) * height * pi

def     UpperCamelCase_    (						SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     ):
					# Volume - (outer_radius squared - inner_radius squared) * pi * height
					if inner_radius < 0 or outer_radius < 0 or height < 0:
										raise ValueError(
										    'vol_hollow_circular_cylinder() only accepts non-negative values'     )
					if outer_radius <= inner_radius:
										raise ValueError('outer_radius must be greater than inner_radius'     )
					return pi * (pow(SCREAMING_SNAKE_CASE_,	2     ) - pow(SCREAMING_SNAKE_CASE_,	2     )) * height

def     UpperCamelCase_    (						SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     ):
					# Volume is 1/3 * pi * height *
					#           (radius_1 squared + radius_2 squared + radius_1 * radius_2)
					if radius_a < 0 or radius_a < 0 or height < 0:
										raise ValueError('vol_conical_frustum() only accepts non-negative values'     )
					return (
					    1
					    / 3
					    * pi
					    * height
					    * (pow(SCREAMING_SNAKE_CASE_,	2     ) + pow(SCREAMING_SNAKE_CASE_,	2     ) + radius_a * radius_a)
					)

def     UpperCamelCase_    (						SCREAMING_SNAKE_CASE_,	SCREAMING_SNAKE_CASE_     ):
					if torus_radius < 0 or tube_radius < 0:
										raise ValueError('vol_torus() only accepts non-negative values'     )
					return 2 * pow(SCREAMING_SNAKE_CASE_,	2     ) * torus_radius * pow(SCREAMING_SNAKE_CASE_,	2     )

def     UpperCamelCase_    (						):
					print('Volumes:'     )
					print(f'''Cube: {vol_cube(2     ) = }'''     )  # = 8
					print(f'''Cuboid: {vol_cuboid(2,	2,	2     ) = }'''     )  # = 8
					print(f'''Cone: {vol_cone(2,	2     ) = }'''     )  # ~= 1.33
					print(f'''Right Circular Cone: {vol_right_circ_cone(2,	2     ) = }'''     )  # ~= 8.38
					print(f'''Prism: {vol_prism(2,	2     ) = }'''     )  # = 4
					print(f'''Pyramid: {vol_pyramid(2,	2     ) = }'''     )  # ~= 1.33
					print(f'''Sphere: {vol_sphere(2     ) = }'''     )  # ~= 33.5
					print(f'''Hemisphere: {vol_hemisphere(2     ) = }'''     )  # ~= 16.75
					print(f'''Circular Cylinder: {vol_circular_cylinder(2,	2     ) = }'''     )  # ~= 25.1
					print(f'''Torus: {vol_torus(2,	2     ) = }'''     )  # ~= 157.9
					print(f'''Conical Frustum: {vol_conical_frustum(2,	2,	4     ) = }'''     )  # ~= 58.6
					print(f'''Spherical cap: {vol_spherical_cap(1,	2     ) = }'''     )  # ~= 5.24
					print(f'''Spheres intersetion: {vol_spheres_intersect(2,	2,	1     ) = }'''     )  # ~= 21.21
					print(f'''Spheres union: {vol_spheres_union(2,	2,	1     ) = }'''     )  # ~= 45.81
					print(
					    f'''Hollow Circular Cylinder: {vol_hollow_circular_cylinder(1,	2,	3     ) = }'''     )  # ~= 28.3


if __name__ == "__main__":
	main()
